Changes.
[cairo/gpu.git] / src / cairo-xlib-surface.c
blobd25308b0e0b87900b773819faa30889b20940a8b
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
33 * California.
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
42 #include "cairoint.h"
44 #include "cairo-xlib-private.h"
45 #include "cairo-xlib-surface-private.h"
46 #include "cairo-clip-private.h"
47 #include "cairo-scaled-font-private.h"
49 #include <X11/Xutil.h> /* for XDestroyImage */
51 #define XLIB_COORD_MAX 32767
53 /* Xlib doesn't define a typedef, so define one ourselves */
54 typedef int (*cairo_xlib_error_func_t) (Display *display,
55 XErrorEvent *event);
57 static cairo_surface_t *
58 _cairo_xlib_surface_create_internal (Display *dpy,
59 Drawable drawable,
60 Screen *screen,
61 Visual *visual,
62 XRenderPictFormat *xrender_format,
63 int width,
64 int height,
65 int depth);
67 static cairo_status_t
68 _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
70 static void
71 _cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface);
73 static void
74 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface);
76 static void
77 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface);
79 static cairo_bool_t
80 _cairo_surface_is_xlib (cairo_surface_t *surface);
82 static cairo_bool_t
83 _native_byte_order_lsb (void);
85 static cairo_int_status_t
86 _cairo_xlib_surface_show_glyphs (void *abstract_dst,
87 cairo_operator_t op,
88 const cairo_pattern_t *src_pattern,
89 cairo_glyph_t *glyphs,
90 int num_glyphs,
91 cairo_scaled_font_t *scaled_font,
92 int *remaining_glyphs,
93 cairo_rectangle_int_t *extents);
95 /* XXX temporarily used by cairo-qt-surface.c */
96 slim_hidden_proto (cairo_xlib_surface_create);
97 slim_hidden_proto (cairo_xlib_surface_create_with_xrender_format);
100 * Instead of taking two round trips for each blending request,
101 * assume that if a particular drawable fails GetImage that it will
102 * fail for a "while"; use temporary pixmaps to avoid the errors
105 #define CAIRO_ASSUME_PIXMAP 20
107 static const XTransform identity = { {
108 { 1 << 16, 0x00000, 0x00000 },
109 { 0x00000, 1 << 16, 0x00000 },
110 { 0x00000, 0x00000, 1 << 16 },
111 } };
113 #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
114 (((surface)->render_major > major) || \
115 (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
117 #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
118 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
119 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
121 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
123 #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
124 #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
126 #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
127 #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
128 #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
129 #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
131 #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
132 #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
134 static cairo_surface_t *
135 _cairo_xlib_surface_create_similar_with_format (void *abstract_src,
136 cairo_format_t format,
137 int width,
138 int height)
140 cairo_xlib_surface_t *src = abstract_src;
141 Display *dpy = src->dpy;
142 Pixmap pix;
143 cairo_xlib_surface_t *surface;
144 XRenderPictFormat *xrender_format;
146 assert (width <= XLIB_COORD_MAX && height <= XLIB_COORD_MAX);
148 /* As a good first approximation, if the display doesn't have even
149 * the most elementary RENDER operation, then we're better off
150 * using image surfaces for all temporary operations, so return NULL
151 * and let the fallback code happen.
153 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
154 return NULL;
156 xrender_format = _cairo_xlib_display_get_xrender_format (src->display,
157 format);
158 if (xrender_format == NULL)
159 return NULL;
161 pix = XCreatePixmap (dpy, src->drawable,
162 width <= 0 ? 1 : width, height <= 0 ? 1 : height,
163 xrender_format->depth);
165 surface = (cairo_xlib_surface_t *)
166 _cairo_xlib_surface_create_internal (dpy, pix,
167 src->screen, NULL,
168 xrender_format,
169 width, height,
170 xrender_format->depth);
171 if (surface->base.status) {
172 XFreePixmap (dpy, pix);
173 return &surface->base;
176 surface->owns_pixmap = TRUE;
178 return &surface->base;
181 static cairo_content_t
182 _xrender_format_to_content (XRenderPictFormat *xrender_format)
184 cairo_bool_t xrender_format_has_alpha;
185 cairo_bool_t xrender_format_has_color;
187 /* This only happens when using a non-Render server. Let's punt
188 * and say there's no alpha here. */
189 if (xrender_format == NULL)
190 return CAIRO_CONTENT_COLOR;
192 xrender_format_has_alpha = (xrender_format->direct.alphaMask != 0);
193 xrender_format_has_color = (xrender_format->direct.redMask != 0 ||
194 xrender_format->direct.greenMask != 0 ||
195 xrender_format->direct.blueMask != 0);
197 if (xrender_format_has_alpha)
198 if (xrender_format_has_color)
199 return CAIRO_CONTENT_COLOR_ALPHA;
200 else
201 return CAIRO_CONTENT_ALPHA;
202 else
203 return CAIRO_CONTENT_COLOR;
206 static cairo_surface_t *
207 _cairo_xlib_surface_create_similar (void *abstract_src,
208 cairo_content_t content,
209 int width,
210 int height)
212 cairo_xlib_surface_t *src = abstract_src;
213 XRenderPictFormat *xrender_format;
214 cairo_xlib_surface_t *surface;
215 Pixmap pix;
217 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
218 return NULL;
220 _cairo_xlib_display_notify (src->display);
222 /* If we never found an XRenderFormat or if it isn't compatible
223 * with the content being requested, then we fallback to just
224 * constructing a cairo_format_t instead, (which will fairly
225 * arbitrarily pick a visual/depth for the similar surface.
227 xrender_format = src->xrender_format;
228 if (xrender_format == NULL ||
229 _xrender_format_to_content (xrender_format) != content)
231 return _cairo_xlib_surface_create_similar_with_format (abstract_src,
232 _cairo_format_from_content (content),
233 width, height);
236 /* We've got a compatible XRenderFormat now, which means the
237 * similar surface will match the existing surface as closely in
238 * visual/depth etc. as possible. */
239 pix = XCreatePixmap (src->dpy, src->drawable,
240 width <= 0 ? 1 : width, height <= 0 ? 1 : height,
241 xrender_format->depth);
243 surface = (cairo_xlib_surface_t *)
244 _cairo_xlib_surface_create_internal (src->dpy, pix,
245 src->screen, src->visual,
246 xrender_format,
247 width, height,
248 xrender_format->depth);
249 if (surface->base.status != CAIRO_STATUS_SUCCESS) {
250 XFreePixmap (src->dpy, pix);
251 return &surface->base;
254 surface->owns_pixmap = TRUE;
256 return &surface->base;
259 static cairo_status_t
260 _cairo_xlib_surface_finish (void *abstract_surface)
262 cairo_xlib_surface_t *surface = abstract_surface;
263 cairo_xlib_display_t *display = surface->display;
264 cairo_status_t status = CAIRO_STATUS_SUCCESS;
266 if (surface->owns_pixmap) {
267 cairo_status_t status2;
269 if (surface->dst_picture != None) {
270 status2 = _cairo_xlib_display_queue_resource (display,
271 XRenderFreePicture,
272 surface->dst_picture);
273 if (status2 == CAIRO_STATUS_SUCCESS)
274 surface->dst_picture = None;
275 else if (status == CAIRO_STATUS_SUCCESS)
276 status = status2;
279 if (surface->src_picture != None) {
280 status2 = _cairo_xlib_display_queue_resource (display,
281 XRenderFreePicture,
282 surface->src_picture);
283 if (status2 == CAIRO_STATUS_SUCCESS)
284 surface->src_picture = None;
285 else if (status == CAIRO_STATUS_SUCCESS)
286 status = status2;
289 status2 = _cairo_xlib_display_queue_resource (display,
290 (cairo_xlib_notify_resource_func) XFreePixmap,
291 surface->drawable);
292 if (status2 == CAIRO_STATUS_SUCCESS) {
293 surface->owns_pixmap = FALSE;
294 surface->drawable = None;
295 } else if (status == CAIRO_STATUS_SUCCESS)
296 status = status2;
297 } else {
298 if (surface->dst_picture != None)
299 XRenderFreePicture (surface->dpy, surface->dst_picture);
301 if (surface->src_picture != None)
302 XRenderFreePicture (surface->dpy, surface->src_picture);
305 if (surface->gc != NULL) {
306 _cairo_xlib_screen_put_gc (surface->screen_info,
307 surface->depth,
308 surface->gc,
309 surface->gc_has_clip_rects);
310 surface->gc = NULL;
313 if (surface->clip_rects != surface->embedded_clip_rects)
314 free (surface->clip_rects);
316 if (surface->screen_info != NULL)
317 _cairo_xlib_screen_info_destroy (surface->screen_info);
319 if (surface->display != NULL) {
320 _cairo_xlib_remove_close_display_hook (surface->display,
321 &surface->close_display_hook);
322 _cairo_xlib_display_destroy (surface->display);
325 surface->dpy = NULL;
327 return status;
330 static int
331 _noop_error_handler (Display *display,
332 XErrorEvent *event)
334 return False; /* return value is ignored */
337 static void
338 _swap_ximage_2bytes (XImage *ximage)
340 int i, j;
341 char *line = ximage->data;
343 for (j = ximage->height; j; j--) {
344 uint16_t *p = (uint16_t *) line;
345 for (i = ximage->width; i; i--) {
346 *p = bswap_16 (*p);
347 p++;
350 line += ximage->bytes_per_line;
354 static void
355 _swap_ximage_3bytes (XImage *ximage)
357 int i, j;
358 char *line = ximage->data;
360 for (j = ximage->height; j; j--) {
361 uint8_t *p = (uint8_t *) line;
362 for (i = ximage->width; i; i--) {
363 uint8_t tmp;
364 tmp = p[2];
365 p[2] = p[0];
366 p[0] = tmp;
367 p += 3;
370 line += ximage->bytes_per_line;
374 static void
375 _swap_ximage_4bytes (XImage *ximage)
377 int i, j;
378 char *line = ximage->data;
380 for (j = ximage->height; j; j--) {
381 uint32_t *p = (uint32_t *) line;
382 for (i = ximage->width; i; i--) {
383 *p = bswap_32 (*p);
384 p++;
387 line += ximage->bytes_per_line;
391 static void
392 _swap_ximage_nibbles (XImage *ximage)
394 int i, j;
395 char *line = ximage->data;
397 for (j = ximage->height; j; j--) {
398 uint8_t *p = (uint8_t *) line;
399 for (i = (ximage->width + 1) / 2; i; i--) {
400 *p = ((*p >> 4) & 0xf) | ((*p << 4) & ~0xf);
401 p++;
404 line += ximage->bytes_per_line;
408 static void
409 _swap_ximage_bits (XImage *ximage)
411 int i, j;
412 char *line = ximage->data;
413 int unit = ximage->bitmap_unit;
414 int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8;
416 for (j = ximage->height; j; j--) {
417 char *p = line;
419 for (i = line_bytes; i; i--) {
420 char b = *p;
421 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
422 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
423 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
424 *p = b;
426 p++;
429 line += ximage->bytes_per_line;
433 static void
434 _swap_ximage_to_native (XImage *ximage)
436 int unit_bytes = 0;
437 int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
439 if (ximage->bits_per_pixel == 1 &&
440 ximage->bitmap_bit_order != native_byte_order)
442 _swap_ximage_bits (ximage);
443 if (ximage->bitmap_bit_order == ximage->byte_order)
444 return;
447 if (ximage->byte_order == native_byte_order)
448 return;
450 switch (ximage->bits_per_pixel) {
451 case 1:
452 unit_bytes = ximage->bitmap_unit / 8;
453 break;
454 case 4:
455 _swap_ximage_nibbles (ximage);
456 /* fall-through */
457 case 8:
458 case 16:
459 case 20:
460 case 24:
461 case 28:
462 case 30:
463 case 32:
464 unit_bytes = (ximage->bits_per_pixel + 7) / 8;
465 break;
466 default:
467 /* This could be hit on some rare but possible cases. */
468 ASSERT_NOT_REACHED;
471 switch (unit_bytes) {
472 case 1:
473 break;
474 case 2:
475 _swap_ximage_2bytes (ximage);
476 break;
477 case 3:
478 _swap_ximage_3bytes (ximage);
479 break;
480 case 4:
481 _swap_ximage_4bytes (ximage);
482 break;
483 default:
484 ASSERT_NOT_REACHED;
489 /* Given a mask, (with a single sequence of contiguous 1 bits), return
490 * the number of 1 bits in 'width' and the number of 0 bits to its
491 * right in 'shift'. */
492 static void
493 _characterize_field (uint32_t mask, int *width, int *shift)
495 *width = _cairo_popcount (mask);
496 /* The final '& 31' is to force a 0 mask to result in 0 shift. */
497 *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
501 /* Convert a field of 'width' bits to 'new_width' bits with correct
502 * rounding. */
503 static inline uint32_t
504 _resize_field (uint32_t field, int width, int new_width)
506 if (width == 0)
507 return 0;
509 if (width >= new_width) {
510 return field >> (width - new_width);
511 } else {
512 uint32_t result = field << (new_width - width);
514 while (width < new_width) {
515 result |= result >> width;
516 width <<= 1;
518 return result;
522 static inline uint32_t
523 _adjust_field (uint32_t field, int adjustment)
525 return MIN (255, MAX(0, (int)field + adjustment));
528 /* Given a shifted field value, (described by 'width' and 'shift),
529 * resize it 8-bits and return that value.
531 * Note that the original field value must not have any non-field bits
532 * set.
534 static inline uint32_t
535 _field_to_8 (uint32_t field, int width, int shift)
537 return _resize_field (field >> shift, width, 8);
540 static inline uint32_t
541 _field_to_8_undither (uint32_t field, int width, int shift,
542 int dither_adjustment)
544 return _adjust_field (_field_to_8 (field, width, shift), - dither_adjustment>>width);
547 /* Given an 8-bit value, convert it to a field of 'width', shift it up
548 * to 'shift, and return it. */
549 static inline uint32_t
550 _field_from_8 (uint32_t field, int width, int shift)
552 return _resize_field (field, 8, width) << shift;
555 static inline uint32_t
556 _field_from_8_dither (uint32_t field, int width, int shift,
557 int8_t dither_adjustment)
559 return _field_from_8 (_adjust_field (field, dither_adjustment>>width), width, shift);
562 static inline uint32_t
563 _pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info,
564 uint32_t r, uint32_t g, uint32_t b,
565 int8_t dither_adjustment)
567 if (r == g && g == b) {
568 dither_adjustment /= RAMP_SIZE;
569 return visual_info->gray8_to_pseudocolor[_adjust_field (r, dither_adjustment)];
570 } else {
571 dither_adjustment = visual_info->dither8_to_cube[dither_adjustment+128];
572 return visual_info->cube_to_pseudocolor[visual_info->field8_to_cube[_adjust_field (r, dither_adjustment)]]
573 [visual_info->field8_to_cube[_adjust_field (g, dither_adjustment)]]
574 [visual_info->field8_to_cube[_adjust_field (b, dither_adjustment)]];
578 static inline uint32_t
579 _pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info,
580 uint32_t pixel)
582 uint32_t r, g, b;
583 pixel &= 0xff;
584 r = visual_info->colors[pixel].r;
585 g = visual_info->colors[pixel].g;
586 b = visual_info->colors[pixel].b;
587 return (r << 16) |
588 (g << 8) |
589 (b );
593 /* should range from -128 to 127 */
594 #define X 16
595 static const int8_t dither_pattern[4][4] = {
596 {-8*X, +0*X, -6*X, +2*X},
597 {+4*X, -4*X, +6*X, -2*X},
598 {-5*X, +4*X, -7*X, +1*X},
599 {+7*X, -1*X, +5*X, -3*X}
601 #undef X
604 static cairo_status_t
605 _get_image_surface (cairo_xlib_surface_t *surface,
606 cairo_rectangle_int_t *interest_rect,
607 cairo_image_surface_t **image_out,
608 cairo_rectangle_int_t *image_rect)
610 cairo_int_status_t status;
611 cairo_image_surface_t *image = NULL;
612 XImage *ximage;
613 cairo_rectangle_int_t extents;
614 pixman_format_code_t pixman_format;
615 cairo_format_masks_t xlib_masks;
617 extents.x = 0;
618 extents.y = 0;
619 extents.width = surface->width;
620 extents.height = surface->height;
622 if (interest_rect) {
623 if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
624 *image_out = NULL;
625 return CAIRO_STATUS_SUCCESS;
629 if (image_rect)
630 *image_rect = extents;
632 /* XXX: This should try to use the XShm extension if available */
634 if (surface->use_pixmap == 0)
636 cairo_xlib_error_func_t old_handler;
638 old_handler = XSetErrorHandler (_noop_error_handler);
640 ximage = XGetImage (surface->dpy,
641 surface->drawable,
642 extents.x, extents.y,
643 extents.width, extents.height,
644 AllPlanes, ZPixmap);
646 XSetErrorHandler (old_handler);
648 /* If we get an error, the surface must have been a window,
649 * so retry with the safe code path.
651 if (!ximage)
652 surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
654 else
656 surface->use_pixmap--;
657 ximage = NULL;
660 if (!ximage) {
662 /* XGetImage from a window is dangerous because it can
663 * produce errors if the window is unmapped or partially
664 * outside the screen. We could check for errors and
665 * retry, but to keep things simple, we just create a
666 * temporary pixmap
668 Pixmap pixmap;
670 status = _cairo_xlib_surface_ensure_gc (surface);
671 if (unlikely (status))
672 return status;
674 pixmap = XCreatePixmap (surface->dpy,
675 surface->drawable,
676 extents.width, extents.height,
677 surface->depth);
678 if (pixmap) {
679 XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
680 extents.x, extents.y,
681 extents.width, extents.height,
682 0, 0);
684 ximage = XGetImage (surface->dpy,
685 pixmap,
686 0, 0,
687 extents.width, extents.height,
688 AllPlanes, ZPixmap);
690 XFreePixmap (surface->dpy, pixmap);
693 if (!ximage)
694 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
696 _cairo_xlib_surface_maybe_put_gc (surface);
699 _swap_ximage_to_native (ximage);
701 xlib_masks.bpp = ximage->bits_per_pixel;
702 xlib_masks.alpha_mask = surface->a_mask;
703 xlib_masks.red_mask = surface->r_mask;
704 xlib_masks.green_mask = surface->g_mask;
705 xlib_masks.blue_mask = surface->b_mask;
707 if (_pixman_format_from_masks (&xlib_masks, &pixman_format) &&
708 xlib_masks.bpp >= 24 &&
709 ximage->bitmap_unit == 32 &&
710 ximage->bitmap_pad == 32)
712 image = (cairo_image_surface_t*)
713 _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
714 pixman_format,
715 ximage->width,
716 ximage->height,
717 ximage->bytes_per_line);
718 status = image->base.status;
719 if (unlikely (status))
720 goto BAIL;
722 /* Let the surface take ownership of the data */
723 _cairo_image_surface_assume_ownership_of_data (image);
724 ximage->data = NULL;
725 } else {
726 /* The visual we are dealing with is not supported by the
727 * standard pixman formats. So we must first convert the data
728 * to a supported format. */
730 cairo_format_t format;
731 unsigned char *data;
732 uint32_t *row;
733 uint32_t in_pixel, out_pixel;
734 unsigned int rowstride;
735 uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0;
736 int a_width=0, r_width=0, g_width=0, b_width=0;
737 int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
738 int x, y, x0, y0, x_off, y_off;
739 cairo_xlib_visual_info_t *visual_info;
741 if (surface->visual == NULL || surface->visual->class == TrueColor) {
742 cairo_bool_t has_alpha;
743 cairo_bool_t has_color;
745 has_alpha = surface->a_mask;
746 has_color = (surface->r_mask ||
747 surface->g_mask ||
748 surface->b_mask);
750 if (has_color) {
751 if (has_alpha) {
752 format = CAIRO_FORMAT_ARGB32;
753 } else {
754 format = CAIRO_FORMAT_RGB24;
756 } else {
757 /* XXX: Using CAIRO_FORMAT_A8 here would be more
758 * efficient, but would require slightly different code in
759 * the image conversion to put the alpha channel values
760 * into the right place. */
761 format = CAIRO_FORMAT_ARGB32;
764 a_mask = surface->a_mask;
765 r_mask = surface->r_mask;
766 g_mask = surface->g_mask;
767 b_mask = surface->b_mask;
769 _characterize_field (a_mask, &a_width, &a_shift);
770 _characterize_field (r_mask, &r_width, &r_shift);
771 _characterize_field (g_mask, &g_width, &g_shift);
772 _characterize_field (b_mask, &b_width, &b_shift);
774 } else {
775 format = CAIRO_FORMAT_RGB24;
777 status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
778 surface->visual,
779 &visual_info);
780 if (unlikely (status))
781 goto BAIL;
784 image = (cairo_image_surface_t *) cairo_image_surface_create
785 (format, ximage->width, ximage->height);
786 status = image->base.status;
787 if (unlikely (status))
788 goto BAIL;
790 data = cairo_image_surface_get_data (&image->base);
791 rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
792 row = (uint32_t *) data;
793 x0 = extents.x + surface->base.device_transform.x0;
794 y0 = extents.y + surface->base.device_transform.y0;
795 for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
796 y < ximage->height;
797 y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
798 const int8_t *dither_row = dither_pattern[y_off];
799 for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
800 x < ximage->width;
801 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) {
802 int dither_adjustment = dither_row[x_off];
804 in_pixel = XGetPixel (ximage, x, y);
805 if (surface->visual == NULL || surface->visual->class == TrueColor) {
806 out_pixel = (
807 _field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
808 _field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
809 _field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 |
810 _field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment));
811 } else {
812 /* Undithering pseudocolor does not look better */
813 out_pixel = _pseudocolor_to_rgb888 (visual_info, in_pixel);
815 row[x] = out_pixel;
817 row += rowstride;
821 BAIL:
822 XDestroyImage (ximage);
824 if (unlikely (status)) {
825 if (image) {
826 cairo_surface_destroy (&image->base);
827 image = NULL;
830 *image_out = image;
831 return status;
834 static void
835 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface)
837 if (!surface->src_picture) {
838 XRenderPictureAttributes pa;
839 int mask = 0;
841 pa.subwindow_mode = IncludeInferiors;
842 mask |= CPSubwindowMode;
844 surface->src_picture = XRenderCreatePicture (surface->dpy,
845 surface->drawable,
846 surface->xrender_format,
847 mask, &pa);
851 static void
852 _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
854 if (surface->have_clip_rects) {
855 XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
856 0, 0,
857 surface->clip_rects,
858 surface->num_clip_rects);
859 } else {
860 XRenderPictureAttributes pa;
861 pa.clip_mask = None;
862 XRenderChangePicture (surface->dpy, surface->dst_picture,
863 CPClipMask, &pa);
866 surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE;
869 static void
870 _cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface)
872 surface->gc_has_clip_rects = surface->have_clip_rects;
873 if (surface->have_clip_rects) {
874 XSetClipRectangles(surface->dpy, surface->gc,
875 0, 0,
876 surface->clip_rects,
877 surface->num_clip_rects, YXSorted);
878 } else
879 XSetClipMask (surface->dpy, surface->gc, None);
881 surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
884 static void
885 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface)
887 if (!surface->dst_picture) {
888 surface->dst_picture = XRenderCreatePicture (surface->dpy,
889 surface->drawable,
890 surface->xrender_format,
891 0, NULL);
894 if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE)
895 _cairo_xlib_surface_set_picture_clip_rects (surface);
898 static cairo_status_t
899 _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
902 if (surface->gc == NULL) {
903 surface->gc = _cairo_xlib_screen_get_gc (surface->screen_info,
904 surface->depth,
905 surface->drawable,
906 &surface->clip_dirty);
907 if (unlikely (surface->gc == NULL))
908 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
911 if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)
912 _cairo_xlib_surface_set_gc_clip_rects (surface);
914 return CAIRO_STATUS_SUCCESS;
917 static void
918 _cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface)
920 /* return the GC back to the common pool if clean */
922 if (surface->gc_has_clip_rects)
923 return;
925 _cairo_xlib_screen_put_gc (surface->screen_info,
926 surface->depth,
927 surface->gc,
928 FALSE);
929 surface->gc = NULL;
932 static cairo_status_t
933 _draw_image_surface (cairo_xlib_surface_t *surface,
934 cairo_image_surface_t *image,
935 int src_x,
936 int src_y,
937 int width,
938 int height,
939 int dst_x,
940 int dst_y)
942 XImage ximage;
943 cairo_format_masks_t image_masks;
944 int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
945 cairo_status_t status;
946 cairo_bool_t own_data;
948 _pixman_format_to_masks (image->pixman_format, &image_masks);
950 ximage.width = image->width;
951 ximage.height = image->height;
952 ximage.format = ZPixmap;
953 ximage.byte_order = native_byte_order;
954 ximage.bitmap_unit = 32; /* always for libpixman */
955 ximage.bitmap_bit_order = native_byte_order;
956 ximage.bitmap_pad = 32; /* always for libpixman */
957 ximage.depth = surface->depth;
958 ximage.red_mask = surface->r_mask;
959 ximage.green_mask = surface->g_mask;
960 ximage.blue_mask = surface->b_mask;
961 ximage.xoffset = 0;
963 if ((image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
964 (image_masks.red_mask == surface->r_mask || surface->r_mask == 0) &&
965 (image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
966 (image_masks.blue_mask == surface->b_mask || surface->b_mask == 0))
968 int ret;
970 ximage.bits_per_pixel = image_masks.bpp;
971 ximage.bytes_per_line = image->stride;
972 ximage.data = (char *)image->data;
973 own_data = FALSE;
975 ret = XInitImage (&ximage);
976 assert (ret != 0);
977 } else {
978 unsigned int stride, rowstride;
979 int x, y, x0, y0, x_off, y_off;
980 uint32_t in_pixel, out_pixel, *row;
981 int i_a_width=0, i_r_width=0, i_g_width=0, i_b_width=0;
982 int i_a_shift=0, i_r_shift=0, i_g_shift=0, i_b_shift=0;
983 int o_a_width=0, o_r_width=0, o_g_width=0, o_b_width=0;
984 int o_a_shift=0, o_r_shift=0, o_g_shift=0, o_b_shift=0;
985 cairo_xlib_visual_info_t *visual_info = NULL;
986 cairo_bool_t true_color;
987 int ret;
989 if (surface->depth > 16) {
990 ximage.bits_per_pixel = 32;
991 } else if (surface->depth > 8) {
992 ximage.bits_per_pixel = 16;
993 } else if (surface->depth > 1) {
994 ximage.bits_per_pixel = 8;
995 } else {
996 ximage.bits_per_pixel = 1;
998 stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width,
999 ximage.bits_per_pixel);
1000 ximage.bytes_per_line = stride;
1001 ximage.data = _cairo_malloc_ab (stride, ximage.height);
1002 if (unlikely (ximage.data == NULL))
1003 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1005 own_data = TRUE;
1007 ret = XInitImage (&ximage);
1008 assert (ret != 0);
1010 _characterize_field (image_masks.alpha_mask, &i_a_width, &i_a_shift);
1011 _characterize_field (image_masks.red_mask , &i_r_width, &i_r_shift);
1012 _characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift);
1013 _characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift);
1015 true_color = surface->visual == NULL ||
1016 surface->visual->class == TrueColor;
1017 if (true_color) {
1018 _characterize_field (surface->a_mask, &o_a_width, &o_a_shift);
1019 _characterize_field (surface->r_mask, &o_r_width, &o_r_shift);
1020 _characterize_field (surface->g_mask, &o_g_width, &o_g_shift);
1021 _characterize_field (surface->b_mask, &o_b_width, &o_b_shift);
1022 } else {
1023 status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
1024 surface->visual,
1025 &visual_info);
1026 if (unlikely (status))
1027 goto BAIL;
1030 rowstride = image->stride >> 2;
1031 row = (uint32_t *) image->data;
1032 x0 = dst_x + surface->base.device_transform.x0;
1033 y0 = dst_y + surface->base.device_transform.y0;
1034 for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
1035 y < ximage.height;
1036 y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern))
1038 const int8_t *dither_row = dither_pattern[y_off];
1040 for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
1041 x < ximage.width;
1042 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0]))
1044 int dither_adjustment = dither_row[x_off];
1045 int a, r, g, b;
1047 if (image_masks.bpp <= 8)
1048 in_pixel = ((uint8_t*)row)[x];
1049 else if (image_masks.bpp <= 16)
1050 in_pixel = ((uint16_t*)row)[x];
1051 else
1052 in_pixel = row[x];
1054 /* If the incoming image has no alpha channel, then the input
1055 * is opaque and the output should have the maximum alpha value.
1056 * For all other channels, their absence implies 0.
1058 if (image_masks.alpha_mask == 0x0)
1059 a = 0xff;
1060 else
1061 a = _field_to_8 (in_pixel & image_masks.alpha_mask, i_a_width, i_a_shift);
1062 r = _field_to_8 (in_pixel & image_masks.red_mask , i_r_width, i_r_shift);
1063 g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift);
1064 b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift);
1066 if (true_color) {
1067 out_pixel = _field_from_8 (a, o_a_width, o_a_shift) |
1068 _field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) |
1069 _field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) |
1070 _field_from_8_dither (b, o_b_width, o_b_shift, dither_adjustment);
1071 } else {
1072 out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment);
1075 XPutPixel (&ximage, x, y, out_pixel);
1078 row += rowstride;
1082 status = _cairo_xlib_surface_ensure_gc (surface);
1083 if (unlikely (status))
1084 goto BAIL;
1086 XPutImage(surface->dpy, surface->drawable, surface->gc,
1087 &ximage, src_x, src_y, dst_x, dst_y,
1088 width, height);
1090 _cairo_xlib_surface_maybe_put_gc (surface);
1092 BAIL:
1093 if (own_data)
1094 free (ximage.data);
1096 return status;
1099 static cairo_status_t
1100 _cairo_xlib_surface_acquire_source_image (void *abstract_surface,
1101 cairo_image_surface_t **image_out,
1102 void **image_extra)
1104 cairo_xlib_surface_t *surface = abstract_surface;
1105 cairo_image_surface_t *image;
1106 cairo_status_t status;
1108 _cairo_xlib_display_notify (surface->display);
1110 status = _get_image_surface (surface, NULL, &image, NULL);
1111 if (unlikely (status))
1112 return status;
1114 *image_out = image;
1115 *image_extra = NULL;
1117 return CAIRO_STATUS_SUCCESS;
1120 static cairo_surface_t *
1121 _cairo_xlib_surface_snapshot (void *abstract_surface)
1123 cairo_xlib_surface_t *surface = abstract_surface;
1124 cairo_image_surface_t *image;
1125 cairo_status_t status;
1127 _cairo_xlib_display_notify (surface->display);
1129 status = _get_image_surface (surface, NULL, &image, NULL);
1130 if (unlikely (status))
1131 return _cairo_surface_create_in_error (status);
1133 return &image->base;
1136 static void
1137 _cairo_xlib_surface_release_source_image (void *abstract_surface,
1138 cairo_image_surface_t *image,
1139 void *image_extra)
1141 cairo_surface_destroy (&image->base);
1144 static cairo_status_t
1145 _cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
1146 cairo_rectangle_int_t *interest_rect,
1147 cairo_image_surface_t **image_out,
1148 cairo_rectangle_int_t *image_rect_out,
1149 void **image_extra)
1151 cairo_xlib_surface_t *surface = abstract_surface;
1152 cairo_image_surface_t *image;
1153 cairo_status_t status;
1155 _cairo_xlib_display_notify (surface->display);
1157 status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
1158 if (unlikely (status))
1159 return status;
1161 *image_out = image;
1162 *image_extra = NULL;
1164 return CAIRO_STATUS_SUCCESS;
1167 static void
1168 _cairo_xlib_surface_release_dest_image (void *abstract_surface,
1169 cairo_rectangle_int_t *interest_rect,
1170 cairo_image_surface_t *image,
1171 cairo_rectangle_int_t *image_rect,
1172 void *image_extra)
1174 cairo_xlib_surface_t *surface = abstract_surface;
1175 cairo_status_t status;
1177 status = _draw_image_surface (surface, image,
1178 0, 0, image->width, image->height,
1179 image_rect->x, image_rect->y);
1180 status = _cairo_surface_set_error (&surface->base, status);
1182 cairo_surface_destroy (&image->base);
1186 * Return whether two xlib surfaces share the same
1187 * screen. Both core and Render drawing require this
1188 * when using multiple drawables in an operation.
1190 static cairo_bool_t
1191 _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
1192 cairo_xlib_surface_t *src)
1194 return dst->dpy == src->dpy && dst->screen == src->screen;
1197 static cairo_status_t
1198 _cairo_xlib_surface_clone_similar (void *abstract_surface,
1199 cairo_surface_t *src,
1200 cairo_content_t content,
1201 int src_x,
1202 int src_y,
1203 int width,
1204 int height,
1205 int *clone_offset_x,
1206 int *clone_offset_y,
1207 cairo_surface_t **clone_out)
1209 cairo_xlib_surface_t *surface = abstract_surface;
1210 cairo_xlib_surface_t *clone;
1211 cairo_status_t status;
1213 _cairo_xlib_display_notify (surface->display);
1215 if (src->backend == surface->base.backend ) {
1216 cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
1218 if (_cairo_xlib_surface_same_screen (surface, xlib_src)) {
1219 *clone_offset_x = 0;
1220 *clone_offset_y = 0;
1221 *clone_out = cairo_surface_reference (src);
1223 return CAIRO_STATUS_SUCCESS;
1225 } else if (_cairo_surface_is_image (src)) {
1226 cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
1227 cairo_format_t format;
1229 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1230 return CAIRO_INT_STATUS_UNSUPPORTED;
1232 format = image_src->format;
1233 if (format == CAIRO_FORMAT_INVALID ||
1234 (_cairo_content_from_format (format) & ~content))
1236 format = _cairo_format_from_content (image_src->base.content & content);
1238 clone = (cairo_xlib_surface_t *)
1239 _cairo_xlib_surface_create_similar_with_format (surface,
1240 format,
1241 width, height);
1242 if (clone == NULL)
1243 return CAIRO_INT_STATUS_UNSUPPORTED;
1245 if (clone->base.status)
1246 return clone->base.status;
1248 status = _draw_image_surface (clone, image_src,
1249 src_x, src_y,
1250 width, height,
1251 0, 0);
1252 if (unlikely (status)) {
1253 cairo_surface_destroy (&clone->base);
1254 return status;
1257 *clone_offset_x = src_x;
1258 *clone_offset_y = src_y;
1259 *clone_out = &clone->base;
1261 return CAIRO_STATUS_SUCCESS;
1264 return CAIRO_INT_STATUS_UNSUPPORTED;
1267 static cairo_surface_t *
1268 _cairo_xlib_surface_create_solid_pattern_surface (void *abstract_surface,
1269 const cairo_solid_pattern_t *solid_pattern)
1271 /* This function's only responsibility is to create a proper surface
1272 * for when XRender is not available. The proper surface is a xlib
1273 * surface (as opposed to image surface which is what create_similar
1274 * returns in those cases) and the size of the dithering pattern, not
1275 * 1x1. This surface can then be used in
1276 * _cairo_xlib_surface_solid_fill_rectangles() to do dithered "solid"
1277 * fills using core protocol */
1279 cairo_xlib_surface_t *other = abstract_surface;
1280 cairo_image_surface_t *image;
1281 cairo_xlib_surface_t *surface = NULL;
1282 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1284 int width = ARRAY_LENGTH (dither_pattern[0]);
1285 int height = ARRAY_LENGTH (dither_pattern);
1287 Pixmap pixmap = None;
1289 if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
1290 return NULL;
1292 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1293 return NULL;
1295 image = (cairo_image_surface_t *)
1296 _cairo_image_surface_create_with_content (solid_pattern->content,
1297 width, height);
1298 status = image->base.status;
1299 if (unlikely (status))
1300 goto BAIL;
1302 pixmap = XCreatePixmap (other->dpy,
1303 other->drawable,
1304 width, height,
1305 other->depth);
1307 surface = (cairo_xlib_surface_t *)
1308 _cairo_xlib_surface_create_internal (other->dpy,
1309 pixmap,
1310 other->screen, other->visual,
1311 other->xrender_format,
1312 width, height,
1313 other->depth);
1314 status = surface->base.status;
1315 if (unlikely (status))
1316 goto BAIL;
1318 status = _cairo_surface_paint (&image->base,
1319 CAIRO_OPERATOR_SOURCE,
1320 &solid_pattern->base, NULL);
1321 if (unlikely (status))
1322 goto BAIL;
1324 status = _draw_image_surface (surface, image,
1325 0, 0,
1326 width, height,
1327 0, 0);
1328 if (unlikely (status))
1329 goto BAIL;
1331 BAIL:
1332 cairo_surface_destroy (&image->base);
1334 if (unlikely (status)) {
1335 if (pixmap != None)
1336 XFreePixmap (other->dpy, pixmap);
1337 cairo_surface_destroy (&surface->base);
1339 return _cairo_surface_create_in_error (status);
1342 surface->owns_pixmap = TRUE;
1343 return &surface->base;
1346 static cairo_bool_t
1347 _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface,
1348 const cairo_solid_pattern_t *solid_pattern)
1350 cairo_xlib_surface_t *other = abstract_surface;
1351 return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other);
1355 static cairo_status_t
1356 _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
1357 cairo_matrix_t *matrix,
1358 double xc,
1359 double yc)
1361 XTransform xtransform;
1363 /* Casting between pixman_transform_t and XTransform is safe because
1364 * they happen to be the exact same type.
1366 _cairo_matrix_to_pixman_matrix (matrix,
1367 (pixman_transform_t *) &xtransform,
1368 xc, yc);
1370 if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
1371 return CAIRO_STATUS_SUCCESS;
1373 if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
1374 return CAIRO_INT_STATUS_UNSUPPORTED;
1376 XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
1377 surface->xtransform = xtransform;
1379 return CAIRO_STATUS_SUCCESS;
1382 static cairo_status_t
1383 _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
1384 cairo_filter_t filter)
1386 const char *render_filter;
1388 if (surface->filter == filter)
1389 return CAIRO_STATUS_SUCCESS;
1391 if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
1393 if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
1394 return CAIRO_STATUS_SUCCESS;
1396 return CAIRO_INT_STATUS_UNSUPPORTED;
1399 switch (filter) {
1400 case CAIRO_FILTER_FAST:
1401 render_filter = FilterFast;
1402 break;
1403 case CAIRO_FILTER_GOOD:
1404 render_filter = FilterGood;
1405 break;
1406 case CAIRO_FILTER_BEST:
1407 render_filter = FilterBest;
1408 break;
1409 case CAIRO_FILTER_NEAREST:
1410 render_filter = FilterNearest;
1411 break;
1412 case CAIRO_FILTER_BILINEAR:
1413 render_filter = FilterBilinear;
1414 break;
1415 case CAIRO_FILTER_GAUSSIAN:
1416 /* XXX: The GAUSSIAN value has no implementation in cairo
1417 * whatsoever, so it was really a mistake to have it in the
1418 * API. We could fix this by officially deprecating it, or
1419 * else inventing semantics and providing an actual
1420 * implementation for it. */
1421 default:
1422 render_filter = FilterBest;
1423 break;
1426 XRenderSetPictureFilter (surface->dpy, surface->src_picture,
1427 (char *) render_filter, NULL, 0);
1428 surface->filter = filter;
1430 return CAIRO_STATUS_SUCCESS;
1433 static void
1434 _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
1436 XRenderPictureAttributes pa;
1437 unsigned long mask;
1439 if (surface->repeat == repeat)
1440 return;
1442 mask = CPRepeat;
1443 pa.repeat = repeat;
1445 XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
1446 surface->repeat = repeat;
1449 static cairo_int_status_t
1450 _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
1451 cairo_surface_attributes_t *attributes,
1452 double xc,
1453 double yc)
1455 cairo_int_status_t status;
1457 _cairo_xlib_surface_ensure_src_picture (surface);
1459 status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix,
1460 xc, yc);
1461 if (unlikely (status))
1462 return status;
1464 switch (attributes->extend) {
1465 case CAIRO_EXTEND_NONE:
1466 _cairo_xlib_surface_set_repeat (surface, RepeatNone);
1467 break;
1468 case CAIRO_EXTEND_REPEAT:
1469 _cairo_xlib_surface_set_repeat (surface, RepeatNormal);
1470 break;
1471 case CAIRO_EXTEND_REFLECT:
1472 if (surface->buggy_pad_reflect)
1473 return CAIRO_INT_STATUS_UNSUPPORTED;
1474 _cairo_xlib_surface_set_repeat (surface, RepeatReflect);
1475 break;
1476 case CAIRO_EXTEND_PAD:
1477 if (surface->buggy_pad_reflect)
1478 return CAIRO_INT_STATUS_UNSUPPORTED;
1479 _cairo_xlib_surface_set_repeat (surface, RepeatPad);
1480 break;
1481 default:
1482 return CAIRO_INT_STATUS_UNSUPPORTED;
1485 status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
1486 if (unlikely (status))
1487 return status;
1489 return CAIRO_STATUS_SUCCESS;
1492 /* Checks whether we can can directly draw from src to dst with
1493 * the core protocol: either with CopyArea or using src as a
1494 * a tile in a GC.
1496 static cairo_bool_t
1497 _surfaces_compatible (cairo_xlib_surface_t *dst,
1498 cairo_xlib_surface_t *src)
1500 /* same screen */
1501 if (!_cairo_xlib_surface_same_screen (dst, src))
1502 return FALSE;
1504 /* same depth (for core) */
1505 if (src->depth != dst->depth)
1506 return FALSE;
1508 /* if Render is supported, match picture formats */
1509 if (src->xrender_format != dst->xrender_format)
1510 return FALSE;
1511 else if (src->xrender_format != NULL)
1512 return TRUE;
1514 /* Without Render, match visuals instead */
1515 if (src->visual == dst->visual)
1516 return TRUE;
1518 return FALSE;
1521 static cairo_bool_t
1522 _surface_has_alpha (cairo_xlib_surface_t *surface)
1524 if (surface->xrender_format) {
1525 if (surface->xrender_format->type == PictTypeDirect &&
1526 surface->xrender_format->direct.alphaMask != 0)
1527 return TRUE;
1528 else
1529 return FALSE;
1530 } else {
1532 /* In the no-render case, we never have alpha */
1533 return FALSE;
1537 /* Returns true if the given operator and source-alpha combination
1538 * requires alpha compositing to complete.
1540 static cairo_bool_t
1541 _operator_needs_alpha_composite (cairo_operator_t op,
1542 cairo_bool_t destination_has_alpha,
1543 cairo_bool_t source_has_alpha)
1545 if (op == CAIRO_OPERATOR_SOURCE ||
1546 (! source_has_alpha &&
1547 (op == CAIRO_OPERATOR_OVER ||
1548 op == CAIRO_OPERATOR_ATOP ||
1549 op == CAIRO_OPERATOR_IN)))
1550 return destination_has_alpha;
1552 return TRUE;
1555 /* There is a bug in most older X servers with compositing using a
1556 * untransformed repeating source pattern when the source is in off-screen
1557 * video memory, and another with repeated transformed images using a
1558 * general transform matrix. When these bugs could be triggered, we need a
1559 * fallback: in the common case where we have no transformation and the
1560 * source and destination have the same format/visual, we can do the
1561 * operation using the core protocol for the first bug, otherwise, we need
1562 * a software fallback.
1564 * We can also often optimize a compositing operation by calling XCopyArea
1565 * for some common cases where there is no alpha compositing to be done.
1566 * We figure that out here as well.
1568 typedef enum {
1569 DO_RENDER, /* use render */
1570 DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
1571 DO_XTILE, /* core protocol XSetTile optimization/fallback */
1572 DO_UNSUPPORTED /* software fallback */
1573 } composite_operation_t;
1575 /* Initial check for the render bugs; we need to recheck for the
1576 * offscreen-memory bug after we turn patterns into surfaces, since that
1577 * may introduce a repeating pattern for gradient patterns. We don't need
1578 * to check for the repeat+transform bug because gradient surfaces aren't
1579 * transformed.
1581 * All we do here is reject cases where we *know* are going to
1582 * hit the bug and won't be able to use a core protocol fallback.
1584 static composite_operation_t
1585 _categorize_composite_operation (cairo_xlib_surface_t *dst,
1586 cairo_operator_t op,
1587 const cairo_pattern_t *src_pattern,
1588 cairo_bool_t have_mask)
1591 if (!dst->buggy_repeat)
1592 return DO_RENDER;
1594 if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
1596 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
1598 if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
1599 src_pattern->extend == CAIRO_EXTEND_REPEAT)
1601 /* This is the case where we have the bug involving
1602 * untransformed repeating source patterns with off-screen
1603 * video memory; reject some cases where a core protocol
1604 * fallback is impossible.
1606 if (have_mask ||
1607 !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
1608 return DO_UNSUPPORTED;
1610 if (_cairo_surface_is_xlib (surface_pattern->surface)) {
1611 cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)surface_pattern->surface;
1613 if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
1614 return DO_UNSUPPORTED;
1616 /* If these are on the same screen but otherwise incompatible,
1617 * make a copy as core drawing can't cross depths and doesn't
1618 * work right across visuals of the same depth
1620 if (_cairo_xlib_surface_same_screen (dst, src) &&
1621 !_surfaces_compatible (dst, src))
1622 return DO_UNSUPPORTED;
1626 /* Check for the other bug involving repeat patterns with general
1627 * transforms. */
1628 if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
1629 src_pattern->extend == CAIRO_EXTEND_REPEAT)
1630 return DO_UNSUPPORTED;
1633 return DO_RENDER;
1636 /* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
1637 * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
1638 * did to turn gradients into a pattern, but most of the time we can handle
1639 * that case with core protocol fallback.
1641 * Also check here if we can just use XCopyArea, instead of going through
1642 * Render.
1644 static composite_operation_t
1645 _recategorize_composite_operation (cairo_xlib_surface_t *dst,
1646 cairo_operator_t op,
1647 cairo_xlib_surface_t *src,
1648 cairo_surface_attributes_t *src_attr,
1649 cairo_bool_t have_mask)
1651 cairo_bool_t is_integer_translation =
1652 _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
1653 cairo_bool_t needs_alpha_composite;
1655 if (! _cairo_surface_is_xlib (&src->base))
1656 return DO_UNSUPPORTED;
1658 needs_alpha_composite =
1659 _operator_needs_alpha_composite (op,
1660 _surface_has_alpha (dst),
1661 _surface_has_alpha (src));
1663 if (! have_mask &&
1664 is_integer_translation &&
1665 src_attr->extend == CAIRO_EXTEND_NONE &&
1666 ! needs_alpha_composite &&
1667 _surfaces_compatible (src, dst))
1669 return DO_XCOPYAREA;
1672 if (dst->buggy_repeat &&
1673 is_integer_translation &&
1674 src_attr->extend == CAIRO_EXTEND_REPEAT &&
1675 (src->width != 1 || src->height != 1))
1677 if (! have_mask &&
1678 ! needs_alpha_composite &&
1679 _surfaces_compatible (dst, src))
1681 return DO_XTILE;
1684 return DO_UNSUPPORTED;
1687 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
1688 return DO_UNSUPPORTED;
1690 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
1691 return DO_UNSUPPORTED;
1693 return DO_RENDER;
1696 static int
1697 _render_operator (cairo_operator_t op)
1699 switch (op) {
1700 case CAIRO_OPERATOR_CLEAR:
1701 return PictOpClear;
1703 case CAIRO_OPERATOR_SOURCE:
1704 return PictOpSrc;
1705 case CAIRO_OPERATOR_OVER:
1706 return PictOpOver;
1707 case CAIRO_OPERATOR_IN:
1708 return PictOpIn;
1709 case CAIRO_OPERATOR_OUT:
1710 return PictOpOut;
1711 case CAIRO_OPERATOR_ATOP:
1712 return PictOpAtop;
1714 case CAIRO_OPERATOR_DEST:
1715 return PictOpDst;
1716 case CAIRO_OPERATOR_DEST_OVER:
1717 return PictOpOverReverse;
1718 case CAIRO_OPERATOR_DEST_IN:
1719 return PictOpInReverse;
1720 case CAIRO_OPERATOR_DEST_OUT:
1721 return PictOpOutReverse;
1722 case CAIRO_OPERATOR_DEST_ATOP:
1723 return PictOpAtopReverse;
1725 case CAIRO_OPERATOR_XOR:
1726 return PictOpXor;
1727 case CAIRO_OPERATOR_ADD:
1728 return PictOpAdd;
1729 case CAIRO_OPERATOR_SATURATE:
1730 return PictOpSaturate;
1731 default:
1732 return PictOpOver;
1736 static cairo_int_status_t
1737 _cairo_xlib_surface_composite (cairo_operator_t op,
1738 const cairo_pattern_t *src_pattern,
1739 const cairo_pattern_t *mask_pattern,
1740 void *abstract_dst,
1741 int src_x,
1742 int src_y,
1743 int mask_x,
1744 int mask_y,
1745 int dst_x,
1746 int dst_y,
1747 unsigned int width,
1748 unsigned int height)
1750 cairo_surface_attributes_t src_attr, mask_attr;
1751 cairo_xlib_surface_t *dst = abstract_dst;
1752 cairo_xlib_surface_t *src;
1753 cairo_xlib_surface_t *mask;
1754 cairo_int_status_t status;
1755 composite_operation_t operation;
1756 int itx, ity;
1757 cairo_bool_t is_integer_translation;
1758 cairo_bool_t needs_alpha_composite;
1759 cairo_content_t src_content;
1761 _cairo_xlib_display_notify (dst->display);
1763 operation = _categorize_composite_operation (dst, op, src_pattern,
1764 mask_pattern != NULL);
1765 if (operation == DO_UNSUPPORTED)
1766 return CAIRO_INT_STATUS_UNSUPPORTED;
1768 needs_alpha_composite =
1769 _operator_needs_alpha_composite (op,
1770 _surface_has_alpha (dst),
1771 ! _cairo_pattern_is_opaque (src_pattern));
1772 src_content = CAIRO_CONTENT_COLOR_ALPHA;
1773 if (! needs_alpha_composite)
1774 src_content &= ~CAIRO_CONTENT_ALPHA;
1776 status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
1777 &dst->base,
1778 src_content,
1779 src_x, src_y,
1780 mask_x, mask_y,
1781 width, height,
1782 dst->buggy_pad_reflect ?
1783 CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
1784 CAIRO_PATTERN_ACQUIRE_NONE,
1785 (cairo_surface_t **) &src,
1786 (cairo_surface_t **) &mask,
1787 &src_attr, &mask_attr);
1788 if (unlikely (status))
1789 return status;
1791 /* check for fallback surfaces that we cannot handle ... */
1792 if (!_cairo_surface_is_xlib (&src->base)) {
1793 status = CAIRO_INT_STATUS_UNSUPPORTED;
1794 goto BAIL;
1796 if (mask != NULL &&
1797 (! _cairo_surface_is_xlib (&mask->base) ||
1798 ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)))
1800 status = CAIRO_INT_STATUS_UNSUPPORTED;
1801 goto BAIL;
1804 operation = _recategorize_composite_operation (dst, op, src, &src_attr,
1805 mask_pattern != NULL);
1806 if (operation == DO_UNSUPPORTED) {
1807 status = CAIRO_INT_STATUS_UNSUPPORTED;
1808 goto BAIL;
1811 switch (operation)
1813 case DO_RENDER:
1814 status = _cairo_xlib_surface_set_attributes (src, &src_attr,
1815 dst_x + width / 2.,
1816 dst_y + height / 2.);
1817 if (unlikely (status))
1818 goto BAIL;
1820 _cairo_xlib_surface_ensure_dst_picture (dst);
1821 if (mask) {
1822 status = _cairo_xlib_surface_set_attributes (mask, &mask_attr,
1823 dst_x + width / 2.,
1824 dst_y + height/ 2.);
1825 if (unlikely (status))
1826 goto BAIL;
1828 XRenderComposite (dst->dpy,
1829 _render_operator (op),
1830 src->src_picture,
1831 mask->src_picture,
1832 dst->dst_picture,
1833 src_x + src_attr.x_offset,
1834 src_y + src_attr.y_offset,
1835 mask_x + mask_attr.x_offset,
1836 mask_y + mask_attr.y_offset,
1837 dst_x, dst_y,
1838 width, height);
1839 } else {
1840 XRenderComposite (dst->dpy,
1841 _render_operator (op),
1842 src->src_picture,
1844 dst->dst_picture,
1845 src_x + src_attr.x_offset,
1846 src_y + src_attr.y_offset,
1847 0, 0,
1848 dst_x, dst_y,
1849 width, height);
1852 break;
1854 case DO_XCOPYAREA:
1855 status = _cairo_xlib_surface_ensure_gc (dst);
1856 if (unlikely (status))
1857 goto BAIL;
1859 is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
1860 &itx, &ity);
1861 /* This is a pre-condition for DO_XCOPYAREA. */
1862 assert (is_integer_translation);
1864 XCopyArea (dst->dpy,
1865 src->drawable,
1866 dst->drawable,
1867 dst->gc,
1868 src_x + src_attr.x_offset + itx,
1869 src_y + src_attr.y_offset + ity,
1870 width, height,
1871 dst_x, dst_y);
1873 _cairo_xlib_surface_maybe_put_gc (dst);
1874 break;
1876 case DO_XTILE:
1877 /* This case is only used for bug fallbacks, though we also use it for
1878 * the case where we don't have the RENDER extension, by forcing
1879 * buggy_repeat to TRUE.
1881 * We've checked that we have a repeating unscaled source in
1882 * _recategorize_composite_operation.
1885 status = _cairo_xlib_surface_ensure_gc (dst);
1886 if (unlikely (status))
1887 goto BAIL;
1888 is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
1889 &itx, &ity);
1890 /* This is a pre-condition for DO_XTILE. */
1891 assert (is_integer_translation);
1893 XSetTSOrigin (dst->dpy, dst->gc,
1894 - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
1895 XSetTile (dst->dpy, dst->gc, src->drawable);
1896 XSetFillStyle (dst->dpy, dst->gc, FillTiled);
1898 XFillRectangle (dst->dpy, dst->drawable, dst->gc,
1899 dst_x, dst_y, width, height);
1901 _cairo_xlib_surface_maybe_put_gc (dst);
1902 break;
1904 case DO_UNSUPPORTED:
1905 default:
1906 ASSERT_NOT_REACHED;
1909 if (!_cairo_operator_bounded_by_source (op))
1910 status = _cairo_surface_composite_fixup_unbounded (&dst->base,
1911 &src_attr, src->width, src->height,
1912 mask ? &mask_attr : NULL,
1913 mask ? mask->width : 0,
1914 mask ? mask->height : 0,
1915 src_x, src_y,
1916 mask_x, mask_y,
1917 dst_x, dst_y, width, height);
1919 BAIL:
1920 if (mask)
1921 _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
1923 _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
1925 return status;
1928 static cairo_int_status_t
1929 _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
1930 const cairo_color_t *color,
1931 cairo_rectangle_int_t *rects,
1932 int num_rects)
1934 cairo_status_t status;
1935 cairo_solid_pattern_t solid;
1936 cairo_surface_t *solid_surface = NULL;
1937 cairo_surface_attributes_t attrs;
1938 int i;
1940 _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR);
1942 status = _cairo_xlib_surface_ensure_gc (surface);
1943 if (unlikely (status))
1944 return status;
1946 status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
1947 CAIRO_CONTENT_COLOR_ALPHA,
1948 0, 0,
1949 ARRAY_LENGTH (dither_pattern[0]),
1950 ARRAY_LENGTH (dither_pattern),
1951 CAIRO_PATTERN_ACQUIRE_NONE,
1952 &solid_surface,
1953 &attrs);
1954 if (unlikely (status))
1955 return status;
1957 if (! _cairo_surface_is_xlib (solid_surface)) {
1958 status = CAIRO_INT_STATUS_UNSUPPORTED;
1959 goto BAIL;
1962 XSetTSOrigin (surface->dpy, surface->gc,
1963 - (surface->base.device_transform.x0 + attrs.x_offset),
1964 - (surface->base.device_transform.y0 + attrs.y_offset));
1965 XSetTile (surface->dpy, surface->gc,
1966 ((cairo_xlib_surface_t *) solid_surface)->drawable);
1967 XSetFillStyle (surface->dpy, surface->gc, FillTiled);
1969 for (i = 0; i < num_rects; i++) {
1970 XFillRectangle (surface->dpy, surface->drawable, surface->gc,
1971 rects[i].x, rects[i].y,
1972 rects[i].width, rects[i].height);
1975 _cairo_xlib_surface_maybe_put_gc (surface);
1977 BAIL:
1978 _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
1980 return status;
1983 static cairo_int_status_t
1984 _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
1985 cairo_operator_t op,
1986 const cairo_color_t *color,
1987 cairo_rectangle_int_t *rects,
1988 int num_rects)
1990 cairo_xlib_surface_t *surface = abstract_surface;
1991 XRenderColor render_color;
1992 int i;
1994 _cairo_xlib_display_notify (surface->display);
1996 if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
1997 if (op == CAIRO_OPERATOR_CLEAR ||
1998 ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
1999 CAIRO_COLOR_IS_OPAQUE (color)))
2001 return _cairo_xlib_surface_solid_fill_rectangles (surface, color,
2002 rects, num_rects);
2005 return CAIRO_INT_STATUS_UNSUPPORTED;
2008 render_color.red = color->red_short;
2009 render_color.green = color->green_short;
2010 render_color.blue = color->blue_short;
2011 render_color.alpha = color->alpha_short;
2013 _cairo_xlib_surface_ensure_dst_picture (surface);
2014 if (num_rects == 1) {
2015 /* Take advantage of the protocol compaction that libXrender performs
2016 * to amalgamate sequences of XRenderFillRectangle().
2018 XRenderFillRectangle (surface->dpy,
2019 _render_operator (op),
2020 surface->dst_picture,
2021 &render_color,
2022 rects->x,
2023 rects->y,
2024 rects->width,
2025 rects->height);
2026 } else {
2027 XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
2028 XRectangle *xrects = static_xrects;
2030 if (num_rects > ARRAY_LENGTH (static_xrects)) {
2031 xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
2032 if (unlikely (xrects == NULL))
2033 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2036 for (i = 0; i < num_rects; i++) {
2037 xrects[i].x = rects[i].x;
2038 xrects[i].y = rects[i].y;
2039 xrects[i].width = rects[i].width;
2040 xrects[i].height = rects[i].height;
2043 XRenderFillRectangles (surface->dpy,
2044 _render_operator (op),
2045 surface->dst_picture,
2046 &render_color, xrects, num_rects);
2048 if (xrects != static_xrects)
2049 free (xrects);
2052 return CAIRO_STATUS_SUCCESS;
2055 /* Creates an A8 picture of size @width x @height, initialized with @color
2057 static Picture
2058 _create_a8_picture (cairo_xlib_surface_t *surface,
2059 XRenderColor *color,
2060 int width,
2061 int height,
2062 cairo_bool_t repeat)
2064 XRenderPictureAttributes pa;
2065 unsigned long mask = 0;
2067 Pixmap pixmap;
2068 Picture picture;
2069 XRenderPictFormat *xrender_format;
2071 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
2072 return None;
2074 xrender_format =
2075 _cairo_xlib_display_get_xrender_format (surface->display,
2076 CAIRO_FORMAT_A8);
2077 if (xrender_format == NULL)
2078 return None;
2080 pixmap = XCreatePixmap (surface->dpy, surface->drawable,
2081 width <= 0 ? 1 : width,
2082 height <= 0 ? 1 : height,
2085 if (repeat) {
2086 pa.repeat = TRUE;
2087 mask = CPRepeat;
2090 picture = XRenderCreatePicture (surface->dpy, pixmap,
2091 xrender_format, mask, &pa);
2092 XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color,
2093 0, 0, width, height);
2094 XFreePixmap (surface->dpy, pixmap);
2096 return picture;
2099 /* Creates a temporary mask for the trapezoids covering the area
2100 * [@dst_x, @dst_y, @width, @height] of the destination surface.
2102 static Picture
2103 _create_trapezoid_mask (cairo_xlib_surface_t *dst,
2104 cairo_trapezoid_t *traps,
2105 int num_traps,
2106 int dst_x,
2107 int dst_y,
2108 int width,
2109 int height,
2110 XRenderPictFormat *pict_format)
2112 XRenderColor transparent = { 0, 0, 0, 0 };
2113 XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff };
2114 Picture mask_picture, solid_picture;
2115 XTrapezoid *offset_traps;
2116 int i;
2118 /* This would be considerably simpler using XRenderAddTraps(), but since
2119 * we are only using this in the unbounded-operator case, we stick with
2120 * XRenderCompositeTrapezoids, which is available on older versions
2121 * of RENDER rather than conditionalizing. We should still hit an
2122 * optimization that avoids creating another intermediate surface on
2123 * the servers that have XRenderAddTraps().
2125 mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
2126 if (mask_picture == None || num_traps == 0)
2127 return mask_picture;
2129 offset_traps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
2130 if (!offset_traps) {
2131 XRenderFreePicture (dst->dpy, mask_picture);
2132 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2133 return None;
2136 for (i = 0; i < num_traps; i++) {
2137 offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
2138 offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
2139 offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
2140 offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
2141 offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
2142 offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
2143 offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
2144 offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
2145 offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
2146 offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
2149 solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
2150 if (solid_picture == None) {
2151 XRenderFreePicture (dst->dpy, mask_picture);
2152 free (offset_traps);
2153 return None;
2156 XRenderCompositeTrapezoids (dst->dpy, PictOpAdd,
2157 solid_picture, mask_picture,
2158 pict_format,
2159 0, 0,
2160 offset_traps, num_traps);
2162 XRenderFreePicture (dst->dpy, solid_picture);
2163 free (offset_traps);
2165 return mask_picture;
2168 static cairo_int_status_t
2169 _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
2170 const cairo_pattern_t *pattern,
2171 void *abstract_dst,
2172 cairo_antialias_t antialias,
2173 int src_x,
2174 int src_y,
2175 int dst_x,
2176 int dst_y,
2177 unsigned int width,
2178 unsigned int height,
2179 cairo_trapezoid_t *traps,
2180 int num_traps)
2182 cairo_surface_attributes_t attributes;
2183 cairo_xlib_surface_t *dst = abstract_dst;
2184 cairo_xlib_surface_t *src;
2185 cairo_int_status_t status;
2186 composite_operation_t operation;
2187 int render_reference_x, render_reference_y;
2188 int render_src_x, render_src_y;
2189 XRenderPictFormat *pict_format;
2191 _cairo_xlib_display_notify (dst->display);
2193 if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
2194 return CAIRO_INT_STATUS_UNSUPPORTED;
2196 operation = _categorize_composite_operation (dst, op, pattern, TRUE);
2197 if (operation == DO_UNSUPPORTED)
2198 return CAIRO_INT_STATUS_UNSUPPORTED;
2200 status = _cairo_pattern_acquire_surface (pattern, &dst->base,
2201 CAIRO_CONTENT_COLOR_ALPHA,
2202 src_x, src_y, width, height,
2203 dst->buggy_pad_reflect ?
2204 CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
2205 CAIRO_PATTERN_ACQUIRE_NONE,
2206 (cairo_surface_t **) &src,
2207 &attributes);
2208 if (unlikely (status))
2209 return status;
2211 operation = _recategorize_composite_operation (dst, op, src,
2212 &attributes, TRUE);
2213 if (operation == DO_UNSUPPORTED) {
2214 status = CAIRO_INT_STATUS_UNSUPPORTED;
2215 goto BAIL;
2218 pict_format =
2219 _cairo_xlib_display_get_xrender_format (dst->display,
2220 (antialias == CAIRO_ANTIALIAS_NONE) ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
2222 if (traps[0].left.p1.y < traps[0].left.p2.y) {
2223 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
2224 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
2225 } else {
2226 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
2227 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
2230 render_src_x = src_x + render_reference_x - dst_x;
2231 render_src_y = src_y + render_reference_y - dst_y;
2233 _cairo_xlib_surface_ensure_dst_picture (dst);
2234 status = _cairo_xlib_surface_set_attributes (src, &attributes,
2235 dst_x + width / 2.,
2236 dst_y + height / 2.);
2237 if (unlikely (status))
2238 goto BAIL;
2240 if (!_cairo_operator_bounded_by_mask (op)) {
2241 /* XRenderCompositeTrapezoids() creates a mask only large enough for the
2242 * trapezoids themselves, but if the operator is unbounded, then we need
2243 * to actually composite all the way out to the bounds, so we create
2244 * the mask and composite ourselves. There actually would
2245 * be benefit to doing this in all cases, since RENDER implementations
2246 * will frequently create a too temporary big mask, ignoring destination
2247 * bounds and clip. (XRenderAddTraps() could be used to make creating
2248 * the mask somewhat cheaper.)
2250 Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps,
2251 dst_x, dst_y, width, height,
2252 pict_format);
2253 if (!mask_picture) {
2254 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2255 goto BAIL;
2258 XRenderComposite (dst->dpy,
2259 _render_operator (op),
2260 src->src_picture,
2261 mask_picture,
2262 dst->dst_picture,
2263 src_x + attributes.x_offset,
2264 src_y + attributes.y_offset,
2265 0, 0,
2266 dst_x, dst_y,
2267 width, height);
2269 XRenderFreePicture (dst->dpy, mask_picture);
2271 status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
2272 &attributes, src->width, src->height,
2273 width, height,
2274 src_x, src_y,
2275 0, 0,
2276 dst_x, dst_y, width, height);
2278 } else {
2279 XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
2280 XTrapezoid *xtraps = xtraps_stack;
2281 int i;
2283 if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
2284 xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
2285 if (unlikely (xtraps == NULL)) {
2286 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2287 goto BAIL;
2291 for (i = 0; i < num_traps; i++) {
2292 xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
2293 xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
2294 xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
2295 xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
2296 xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
2297 xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
2298 xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
2299 xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
2300 xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
2301 xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
2304 XRenderCompositeTrapezoids (dst->dpy,
2305 _render_operator (op),
2306 src->src_picture, dst->dst_picture,
2307 pict_format,
2308 render_src_x + attributes.x_offset,
2309 render_src_y + attributes.y_offset,
2310 xtraps, num_traps);
2312 if (xtraps != xtraps_stack)
2313 free(xtraps);
2316 BAIL:
2317 _cairo_pattern_release_surface (pattern, &src->base, &attributes);
2319 return status;
2322 static cairo_region_t *
2323 _surface_maybe_clip_region (cairo_xlib_surface_t *surface,
2324 cairo_region_t *clip,
2325 cairo_region_t *bounded)
2327 cairo_rectangle_int_t rect;
2329 cairo_region_get_extents (clip, &rect);
2330 if (rect.x >= 0 &&
2331 rect.y >= 0 &&
2332 rect.x + rect.width <= surface->width &&
2333 rect.y + rect.height <= surface->height)
2335 return clip;
2338 rect.x = rect.y = 0;
2339 rect.width = surface->width;
2340 rect.height = surface->height;
2341 _cairo_region_init_rectangle (bounded, &rect);
2343 bounded->status = cairo_region_intersect (bounded, clip);
2345 return bounded;
2348 static cairo_int_status_t
2349 _cairo_xlib_surface_set_clip_region (void *abstract_surface,
2350 cairo_region_t *region)
2352 cairo_xlib_surface_t *surface = abstract_surface;
2353 cairo_bool_t had_clip_rects = surface->have_clip_rects;
2355 if (had_clip_rects == FALSE && region == NULL)
2356 return CAIRO_STATUS_SUCCESS;
2358 if (surface->clip_rects != surface->embedded_clip_rects) {
2359 free (surface->clip_rects);
2360 surface->clip_rects = surface->embedded_clip_rects;
2363 surface->have_clip_rects = FALSE;
2364 surface->num_clip_rects = 0;
2366 if (region != NULL) {
2367 XRectangle *rects = NULL;
2368 int n_rects, i;
2369 cairo_region_t bounded;
2371 /* Intersect the region with the bounds of the surface. This
2372 * is necessary so we don't wrap around when we convert cairo's
2373 * 32 bit region into 16 bit rectangles.
2375 region = _surface_maybe_clip_region (surface, region, &bounded);
2376 if (unlikely (region->status))
2377 return region->status;
2379 n_rects = cairo_region_num_rectangles (region);
2380 if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
2381 rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
2382 if (unlikely (rects == NULL)) {
2383 if (unlikely (region == &bounded))
2384 _cairo_region_fini (&bounded);
2385 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2387 } else {
2388 rects = surface->embedded_clip_rects;
2391 for (i = 0; i < n_rects; i++) {
2392 cairo_rectangle_int_t rect;
2394 cairo_region_get_rectangle (region, i, &rect);
2396 rects[i].x = rect.x;
2397 rects[i].y = rect.y;
2398 rects[i].width = rect.width;
2399 rects[i].height = rect.height;
2402 if (unlikely (region == &bounded))
2403 _cairo_region_fini (&bounded);
2405 surface->have_clip_rects = TRUE;
2406 surface->clip_rects = rects;
2407 surface->num_clip_rects = n_rects;
2409 /* Discard the trivial clip rectangle that covers the entire surface */
2410 if (n_rects == 1 &&
2411 rects[0].x == 0 &&
2412 rects[0].y == 0 &&
2413 rects[0].width == surface->width &&
2414 rects[0].height == surface->height)
2416 surface->have_clip_rects = FALSE;
2417 surface->num_clip_rects = 0;
2419 if (! had_clip_rects)
2420 goto DONE;
2424 surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
2425 DONE:
2427 return CAIRO_STATUS_SUCCESS;
2430 static cairo_int_status_t
2431 _cairo_xlib_surface_get_extents (void *abstract_surface,
2432 cairo_rectangle_int_t *rectangle)
2434 cairo_xlib_surface_t *surface = abstract_surface;
2436 rectangle->x = 0;
2437 rectangle->y = 0;
2439 rectangle->width = surface->width;
2440 rectangle->height = surface->height;
2442 return CAIRO_STATUS_SUCCESS;
2445 static void
2446 _cairo_xlib_surface_get_font_options (void *abstract_surface,
2447 cairo_font_options_t *options)
2449 cairo_xlib_surface_t *surface = abstract_surface;
2451 *options = *_cairo_xlib_screen_get_font_options (surface->screen_info);
2454 static void
2455 _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
2457 static void
2458 _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
2459 cairo_scaled_font_t *scaled_font);
2461 static cairo_bool_t
2462 _cairo_xlib_surface_is_similar (void *surface_a,
2463 void *surface_b,
2464 cairo_content_t content)
2466 cairo_xlib_surface_t *a = surface_a;
2467 cairo_xlib_surface_t *b = surface_b;
2468 XRenderPictFormat *xrender_format = b->xrender_format;
2470 if (!_cairo_xlib_surface_same_screen (a, b))
2471 return FALSE;
2473 /* now inspect the content to check that a is similar to b */
2474 if (xrender_format == NULL && b->visual != NULL)
2475 xrender_format = XRenderFindVisualFormat (b->dpy, b->visual);
2477 if (xrender_format == NULL ||
2478 _xrender_format_to_content (xrender_format) != content)
2480 xrender_format = _cairo_xlib_display_get_xrender_format (
2481 b->display,
2482 _cairo_format_from_content (content));
2486 return a->xrender_format == xrender_format;
2489 static cairo_status_t
2490 _cairo_xlib_surface_reset (void *abstract_surface)
2492 cairo_xlib_surface_t *surface = abstract_surface;
2493 cairo_status_t status;
2495 status = _cairo_xlib_surface_set_clip_region (surface, NULL);
2496 if (unlikely (status))
2497 return status;
2499 return CAIRO_STATUS_SUCCESS;
2502 static void
2503 _cairo_xlib_surface_set_drawable(void* abstract_surface, unsigned long drawable, unsigned long visualid, cairo_bool_t double_buffered, int width, int height)
2505 cairo_xlib_surface_t * surface = abstract_surface;
2506 cairo_status_t status;
2508 /* XXX: and what about this case? */
2509 if (surface->owns_pixmap)
2510 return;
2512 if(!drawable)
2513 drawable = surface->drawable;
2515 if (surface->drawable != drawable) {
2516 if (surface->dst_picture != None) {
2517 status = _cairo_xlib_display_queue_resource (
2518 surface->display,
2519 XRenderFreePicture,
2520 surface->dst_picture);
2521 if (unlikely (status)) {
2522 status = _cairo_surface_set_error (&surface->base, status);
2523 return;
2526 surface->dst_picture = None;
2529 if (surface->src_picture != None) {
2530 status = _cairo_xlib_display_queue_resource (
2531 surface->display,
2532 XRenderFreePicture,
2533 surface->src_picture);
2534 if (unlikely (status)) {
2535 status = _cairo_surface_set_error (&surface->base, status);
2536 return;
2539 surface->src_picture = None;
2542 surface->drawable = drawable;
2544 surface->width = width;
2545 surface->height = height;
2548 static const cairo_surface_backend_t cairo_xlib_surface_backend = {
2549 CAIRO_SURFACE_TYPE_XLIB,
2550 _cairo_xlib_surface_create_similar,
2551 _cairo_xlib_surface_finish,
2552 _cairo_xlib_surface_acquire_source_image,
2553 _cairo_xlib_surface_release_source_image,
2554 _cairo_xlib_surface_acquire_dest_image,
2555 _cairo_xlib_surface_release_dest_image,
2556 _cairo_xlib_surface_clone_similar,
2557 _cairo_xlib_surface_composite,
2558 _cairo_xlib_surface_fill_rectangles,
2559 _cairo_xlib_surface_composite_trapezoids,
2560 NULL, /* create_span_renderer */
2561 NULL, /* check_span_renderer */
2562 NULL, /* copy_page */
2563 NULL, /* show_page */
2564 _cairo_xlib_surface_set_clip_region,
2565 NULL, /* intersect_clip_path */
2566 _cairo_xlib_surface_get_extents,
2567 NULL, /* old_show_glyphs */
2568 _cairo_xlib_surface_get_font_options,
2569 NULL, /* flush */
2570 NULL, /* mark_dirty_rectangle */
2571 _cairo_xlib_surface_scaled_font_fini,
2572 _cairo_xlib_surface_scaled_glyph_fini,
2574 NULL, /* paint */
2575 NULL, /* mask */
2576 NULL, /* stroke */
2577 NULL, /* fill */
2578 _cairo_xlib_surface_show_glyphs,
2580 _cairo_xlib_surface_snapshot,
2582 _cairo_xlib_surface_is_similar,
2583 _cairo_xlib_surface_reset,
2584 NULL, /* fill_stroke */
2585 _cairo_xlib_surface_create_solid_pattern_surface,
2586 _cairo_xlib_surface_can_repaint_solid_pattern_surface,
2587 NULL, /* has_show_text_glyphs */
2588 NULL, /* show_text_glyphs */
2592 * _cairo_surface_is_xlib:
2593 * @surface: a #cairo_surface_t
2595 * Checks if a surface is a #cairo_xlib_surface_t
2597 * Return value: True if the surface is an xlib surface
2599 static cairo_bool_t
2600 _cairo_surface_is_xlib (cairo_surface_t *surface)
2602 return surface->backend == &cairo_xlib_surface_backend;
2605 /* callback from CloseDisplay */
2606 static void
2607 _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
2609 cairo_xlib_surface_t *surface = cairo_container_of (data,
2610 cairo_xlib_surface_t,
2611 close_display_hook);
2612 Display *dpy;
2614 dpy = surface->dpy;
2615 surface->dpy = NULL;
2617 if (surface->dst_picture != None) {
2618 XRenderFreePicture (dpy, surface->dst_picture);
2619 surface->dst_picture = None;
2622 if (surface->src_picture != None) {
2623 XRenderFreePicture (dpy, surface->src_picture);
2624 surface->src_picture = None;
2627 if (surface->owns_pixmap) {
2628 XFreePixmap (dpy, surface->drawable);
2629 surface->drawable = None;
2630 surface->owns_pixmap = FALSE;
2633 if (surface->gc != NULL) {
2634 XFreeGC (dpy, surface->gc);
2635 surface->gc = NULL;
2639 static cairo_surface_t *
2640 _cairo_xlib_surface_init_internal (cairo_xlib_surface_t* surface,
2641 Display *dpy,
2642 Drawable drawable,
2643 Screen *screen,
2644 Visual *visual,
2645 XRenderPictFormat *xrender_format,
2646 int width,
2647 int height,
2648 int depth)
2650 cairo_xlib_display_t *display;
2651 cairo_xlib_screen_info_t *screen_info;
2652 cairo_status_t status;
2654 CAIRO_MUTEX_INITIALIZE ();
2656 if (xrender_format) {
2657 depth = xrender_format->depth;
2659 /* XXX find matching visual for core/dithering fallbacks? */
2660 } else if (visual) {
2661 int j, k;
2663 /* This is ugly, but we have to walk over all visuals
2664 * for the display to find the correct depth.
2666 depth = 0;
2667 for (j = 0; j < screen->ndepths; j++) {
2668 Depth *d = &screen->depths[j];
2669 for (k = 0; k < d->nvisuals; k++) {
2670 if (&d->visuals[k] == visual) {
2671 depth = d->depth;
2672 goto found;
2676 found:
2680 if (depth == 0)
2681 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
2683 status = _cairo_xlib_display_get (dpy, &display);
2684 if (unlikely (status))
2685 return _cairo_surface_create_in_error (status);
2687 status = _cairo_xlib_screen_info_get (display, screen, &screen_info);
2688 if (unlikely (status)) {
2689 _cairo_xlib_display_destroy (display);
2690 return _cairo_surface_create_in_error (status);
2693 if(surface->dpy)
2694 _cairo_xlib_surface_finish(surface);
2696 /* initialize and hook into the CloseDisplay callback */
2697 surface->close_display_hook.func = _cairo_xlib_surface_detach_display;
2698 _cairo_xlib_add_close_display_hook (display, &surface->close_display_hook);
2700 surface->render_major = display->render_major;
2701 surface->render_minor = display->render_minor;
2702 if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
2703 if (!xrender_format) {
2704 if (visual) {
2705 xrender_format = XRenderFindVisualFormat (dpy, visual);
2706 } else if (depth == 1) {
2707 xrender_format =
2708 _cairo_xlib_display_get_xrender_format (display,
2709 CAIRO_FORMAT_A1);
2712 } else {
2713 xrender_format = NULL;
2716 /* we cannot use XRender for this surface, so ensure we don't try */
2717 if (xrender_format == NULL) {
2718 surface->render_major = -1;
2719 surface->render_minor = -1;
2722 surface->base.content = _xrender_format_to_content (xrender_format);
2723 surface->dpy = dpy;
2724 surface->display = display;
2725 surface->screen_info = screen_info;
2727 surface->gc = NULL;
2728 surface->drawable = drawable;
2729 surface->screen = screen;
2730 surface->owns_pixmap = FALSE;
2731 surface->use_pixmap = 0;
2732 surface->width = width;
2733 surface->height = height;
2735 surface->buggy_repeat = screen_info->display->buggy_repeat;
2736 if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
2737 /* so we can use the XTile fallback */
2738 surface->buggy_repeat = TRUE;
2740 surface->buggy_pad_reflect = screen_info->display->buggy_pad_reflect;
2742 surface->dst_picture = None;
2743 surface->src_picture = None;
2745 surface->visual = visual;
2746 surface->xrender_format = xrender_format;
2747 surface->depth = depth;
2748 surface->filter = CAIRO_FILTER_NEAREST;
2749 surface->repeat = FALSE;
2750 surface->xtransform = identity;
2752 surface->have_clip_rects = FALSE;
2753 surface->gc_has_clip_rects = FALSE;
2754 surface->clip_rects = surface->embedded_clip_rects;
2755 surface->num_clip_rects = 0;
2756 surface->clip_dirty = 0;
2759 * Compute the pixel format masks from either a XrenderFormat or
2760 * else from a visual; failing that we assume the drawable is an
2761 * alpha-only pixmap as it could only have been created that way
2762 * through the cairo_xlib_surface_create_for_bitmap function.
2764 if (xrender_format) {
2765 surface->a_mask = (unsigned long)
2766 surface->xrender_format->direct.alphaMask
2767 << surface->xrender_format->direct.alpha;
2768 surface->r_mask = (unsigned long)
2769 surface->xrender_format->direct.redMask
2770 << surface->xrender_format->direct.red;
2771 surface->g_mask = (unsigned long)
2772 surface->xrender_format->direct.greenMask
2773 << surface->xrender_format->direct.green;
2774 surface->b_mask = (unsigned long)
2775 surface->xrender_format->direct.blueMask
2776 << surface->xrender_format->direct.blue;
2777 } else if (visual) {
2778 surface->a_mask = 0;
2779 surface->r_mask = visual->red_mask;
2780 surface->g_mask = visual->green_mask;
2781 surface->b_mask = visual->blue_mask;
2782 } else {
2783 if (depth < 32)
2784 surface->a_mask = (1 << depth) - 1;
2785 else
2786 surface->a_mask = 0xffffffff;
2787 surface->r_mask = 0;
2788 surface->g_mask = 0;
2789 surface->b_mask = 0;
2792 return (cairo_surface_t *) surface;
2795 static cairo_surface_t *
2796 _cairo_xlib_surface_create_internal (Display *dpy,
2797 Drawable drawable,
2798 Screen *screen,
2799 Visual *visual,
2800 XRenderPictFormat *xrender_format,
2801 int width,
2802 int height,
2803 int depth)
2805 cairo_xlib_surface_t * surface = malloc (sizeof (cairo_xlib_surface_t));
2806 cairo_surface_t* ret;
2807 if (unlikely (surface == NULL))
2808 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2810 _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend, 0);
2811 surface->dpy = 0;
2813 ret = _cairo_xlib_surface_init_internal(surface, dpy, drawable, screen, visual, xrender_format, width, height, depth);
2814 if(ret != &surface->base)
2815 free(surface);
2817 return ret;
2820 static Screen *
2821 _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
2823 int s;
2824 int d;
2825 int v;
2826 Screen *screen;
2827 Depth *depth;
2829 for (s = 0; s < ScreenCount (dpy); s++) {
2830 screen = ScreenOfDisplay (dpy, s);
2831 if (visual == DefaultVisualOfScreen (screen))
2832 return screen;
2833 for (d = 0; d < screen->ndepths; d++) {
2834 depth = &screen->depths[d];
2835 for (v = 0; v < depth->nvisuals; v++)
2836 if (visual == &depth->visuals[v])
2837 return screen;
2840 return NULL;
2844 * cairo_xlib_surface_create:
2845 * @dpy: an X Display
2846 * @drawable: an X Drawable, (a Pixmap or a Window)
2847 * @visual: the visual to use for drawing to @drawable. The depth
2848 * of the visual must match the depth of the drawable.
2849 * Currently, only TrueColor visuals are fully supported.
2850 * @width: the current width of @drawable.
2851 * @height: the current height of @drawable.
2853 * Creates an Xlib surface that draws to the given drawable.
2854 * The way that colors are represented in the drawable is specified
2855 * by the provided visual.
2857 * Note: If @drawable is a Window, then the function
2858 * cairo_xlib_surface_set_size() must be called whenever the size of the
2859 * window changes.
2861 * When @drawable is a Window containing child windows then drawing to
2862 * the created surface will be clipped by those child windows. When
2863 * the created surface is used as a source, the contents of the
2864 * children will be included.
2866 * Return value: the newly created surface
2868 cairo_surface_t *
2869 cairo_xlib_surface_create (Display *dpy,
2870 Drawable drawable,
2871 Visual *visual,
2872 int width,
2873 int height)
2875 Screen *screen;
2877 screen = _cairo_xlib_screen_from_visual (dpy, visual);
2879 if (screen == NULL)
2880 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
2882 return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
2883 visual, NULL, width, height, 0);
2885 slim_hidden_def (cairo_xlib_surface_create);
2888 * cairo_xlib_surface_create_for_bitmap:
2889 * @dpy: an X Display
2890 * @bitmap: an X Drawable, (a depth-1 Pixmap)
2891 * @screen: the X Screen associated with @bitmap
2892 * @width: the current width of @bitmap.
2893 * @height: the current height of @bitmap.
2895 * Creates an Xlib surface that draws to the given bitmap.
2896 * This will be drawn to as a %CAIRO_FORMAT_A1 object.
2898 * Return value: the newly created surface
2900 cairo_surface_t *
2901 cairo_xlib_surface_create_for_bitmap (Display *dpy,
2902 Pixmap bitmap,
2903 Screen *screen,
2904 int width,
2905 int height)
2907 return _cairo_xlib_surface_create_internal (dpy, bitmap, screen,
2908 NULL, NULL, width, height, 1);
2911 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
2913 * cairo_xlib_surface_create_with_xrender_format:
2914 * @dpy: an X Display
2915 * @drawable: an X Drawable, (a Pixmap or a Window)
2916 * @screen: the X Screen associated with @drawable
2917 * @format: the picture format to use for drawing to @drawable. The depth
2918 * of @format must match the depth of the drawable.
2919 * @width: the current width of @drawable.
2920 * @height: the current height of @drawable.
2922 * Creates an Xlib surface that draws to the given drawable.
2923 * The way that colors are represented in the drawable is specified
2924 * by the provided picture format.
2926 * Note: If @drawable is a Window, then the function
2927 * cairo_xlib_surface_set_size() must be called whenever the size of the
2928 * window changes.
2930 * Return value: the newly created surface
2932 cairo_surface_t *
2933 cairo_xlib_surface_create_with_xrender_format (Display *dpy,
2934 Drawable drawable,
2935 Screen *screen,
2936 XRenderPictFormat *format,
2937 int width,
2938 int height)
2940 return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
2941 NULL, format, width, height, 0);
2943 slim_hidden_def (cairo_xlib_surface_create_with_xrender_format);
2946 * cairo_xlib_surface_get_xrender_format:
2947 * @surface: an xlib surface
2949 * Gets the X Render picture format that @surface uses for rendering with the
2950 * X Render extension. If the surface was created by
2951 * cairo_xlib_surface_create_with_xrender_format() originally, the return
2952 * value is the format passed to that constructor.
2954 * Return value: the XRenderPictFormat* associated with @surface,
2955 * or %NULL if the surface is not an xlib surface
2956 * or if the X Render extension is not available.
2958 * Since: 1.6
2960 XRenderPictFormat *
2961 cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
2963 cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
2965 /* Throw an error for a non-xlib surface */
2966 if (! _cairo_surface_is_xlib (surface)) {
2967 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2968 return NULL;
2971 return xlib_surface->xrender_format;
2973 #endif
2976 * cairo_xlib_surface_set_size:
2977 * @surface: a #cairo_surface_t for the XLib backend
2978 * @width: the new width of the surface
2979 * @height: the new height of the surface
2981 * Informs cairo of the new size of the X Drawable underlying the
2982 * surface. For a surface created for a Window (rather than a Pixmap),
2983 * this function must be called each time the size of the window
2984 * changes. (For a subwindow, you are normally resizing the window
2985 * yourself, but for a toplevel window, it is necessary to listen for
2986 * ConfigureNotify events.)
2988 * A Pixmap can never change size, so it is never necessary to call
2989 * this function on a surface created for a Pixmap.
2991 void
2992 cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
2993 int width,
2994 int height)
2996 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
2998 if (! _cairo_surface_is_xlib (abstract_surface)) {
2999 (void)cairo_surface_create_for_drawable(0, abstract_surface, 0, ~0L, 0, 0, width, height);
3000 return;
3003 surface->width = width;
3004 surface->height = height;
3008 * cairo_xlib_surface_set_drawable:
3009 * @surface: a #cairo_surface_t for the XLib backend
3010 * @drawable: the new drawable for the surface
3011 * @width: the width of the new drawable
3012 * @height: the height of the new drawable
3014 * Informs cairo of a new X Drawable underlying the
3015 * surface. The drawable must match the display, screen
3016 * and format of the existing drawable or the application
3017 * will get X protocol errors and will probably terminate.
3018 * No checks are done by this function to ensure this
3019 * compatibility.
3021 void
3022 cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
3023 Drawable drawable,
3024 int width,
3025 int height)
3027 if (! _cairo_surface_is_xlib (abstract_surface))
3028 cairo_surface_create_for_drawable(0, abstract_surface, 0, drawable, 0, 0, width, height);
3029 else
3030 _cairo_xlib_surface_set_drawable(abstract_surface, drawable, 0, 0, width, height);
3034 * cairo_xlib_surface_get_display:
3035 * @surface: a #cairo_xlib_surface_t
3037 * Get the X Display for the underlying X Drawable.
3039 * Return value: the display.
3041 * Since: 1.2
3043 Display *
3044 cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
3046 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3048 if (! _cairo_surface_is_xlib (abstract_surface)) {
3049 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3050 return NULL;
3053 return surface->dpy;
3057 * cairo_xlib_surface_get_drawable:
3058 * @surface: a #cairo_xlib_surface_t
3060 * Get the underlying X Drawable used for the surface.
3062 * Return value: the drawable.
3064 * Since: 1.2
3066 Drawable
3067 cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
3069 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3071 if (! _cairo_surface_is_xlib (abstract_surface)) {
3072 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3073 return 0;
3076 return surface->drawable;
3080 * cairo_xlib_surface_get_screen:
3081 * @surface: a #cairo_xlib_surface_t
3083 * Get the X Screen for the underlying X Drawable.
3085 * Return value: the screen.
3087 * Since: 1.2
3089 Screen *
3090 cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
3092 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3094 if (! _cairo_surface_is_xlib (abstract_surface)) {
3095 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3096 return NULL;
3099 return surface->screen;
3103 * cairo_xlib_surface_get_visual:
3104 * @surface: a #cairo_xlib_surface_t
3106 * Get the X Visual used for underlying X Drawable.
3108 * Return value: the visual.
3110 * Since: 1.2
3112 Visual *
3113 cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
3115 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3117 if (! _cairo_surface_is_xlib (abstract_surface)) {
3118 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3119 return NULL;
3122 return surface->visual;
3126 * cairo_xlib_surface_get_depth:
3127 * @surface: a #cairo_xlib_surface_t
3129 * Get the number of bits used to represent each pixel value.
3131 * Return value: the depth of the surface in bits.
3133 * Since: 1.2
3136 cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
3138 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3140 if (! _cairo_surface_is_xlib (abstract_surface)) {
3141 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3142 return 0;
3145 return surface->depth;
3149 * cairo_xlib_surface_get_width:
3150 * @surface: a #cairo_xlib_surface_t
3152 * Get the width of the X Drawable underlying the surface in pixels.
3154 * Return value: the width of the surface in pixels.
3156 * Since: 1.2
3159 cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
3161 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3163 if (! _cairo_surface_is_xlib (abstract_surface)) {
3164 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3165 return -1;
3168 return surface->width;
3172 * cairo_xlib_surface_get_height:
3173 * @surface: a #cairo_xlib_surface_t
3175 * Get the height of the X Drawable underlying the surface in pixels.
3177 * Return value: the height of the surface in pixels.
3179 * Since: 1.2
3182 cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
3184 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3186 if (! _cairo_surface_is_xlib (abstract_surface)) {
3187 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3188 return -1;
3191 return surface->height;
3194 enum {
3195 GLYPHSET_INDEX_ARGB32,
3196 GLYPHSET_INDEX_A8,
3197 GLYPHSET_INDEX_A1,
3198 NUM_GLYPHSETS
3201 typedef struct _cairo_xlib_font_glyphset_free_glyphs {
3202 GlyphSet glyphset;
3203 int glyph_count;
3204 unsigned long glyph_indices[128];
3205 } cairo_xlib_font_glyphset_free_glyphs_t;
3207 typedef struct _cairo_xlib_font_glyphset_info {
3208 GlyphSet glyphset;
3209 cairo_format_t format;
3210 XRenderPictFormat *xrender_format;
3211 cairo_xlib_font_glyphset_free_glyphs_t *pending_free_glyphs;
3212 } cairo_xlib_font_glyphset_info_t;
3214 typedef struct _cairo_xlib_surface_font_private {
3215 cairo_scaled_font_t *scaled_font;
3216 cairo_xlib_hook_t close_display_hook;
3217 cairo_xlib_display_t *display;
3218 cairo_xlib_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
3219 } cairo_xlib_surface_font_private_t;
3221 /* callback from CloseDisplay */
3222 static void
3223 _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t *display,
3224 void *data)
3226 cairo_xlib_surface_font_private_t *font_private;
3227 cairo_scaled_font_t *scaled_font;
3229 font_private = cairo_container_of (data,
3230 cairo_xlib_surface_font_private_t,
3231 close_display_hook);
3232 scaled_font = font_private->scaled_font;
3234 CAIRO_MUTEX_LOCK (scaled_font->mutex);
3235 font_private = scaled_font->surface_private;
3236 scaled_font->surface_private = NULL;
3238 _cairo_scaled_font_reset_cache (scaled_font);
3239 CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
3241 if (font_private != NULL) {
3242 Display *dpy;
3243 int i;
3245 dpy = display->display;
3246 for (i = 0; i < NUM_GLYPHSETS; i++) {
3247 cairo_xlib_font_glyphset_info_t *glyphset_info;
3249 glyphset_info = &font_private->glyphset_info[i];
3250 if (glyphset_info->glyphset)
3251 XRenderFreeGlyphSet (dpy, glyphset_info->glyphset);
3253 if (glyphset_info->pending_free_glyphs != NULL)
3254 free (glyphset_info->pending_free_glyphs);
3257 _cairo_xlib_display_destroy (font_private->display);
3258 free (font_private);
3262 static cairo_status_t
3263 _cairo_xlib_surface_font_init (Display *dpy,
3264 cairo_scaled_font_t *scaled_font)
3266 cairo_xlib_surface_font_private_t *font_private;
3267 cairo_status_t status;
3268 int i;
3270 font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
3271 if (unlikely (font_private == NULL))
3272 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3274 font_private->scaled_font = scaled_font;
3275 status = _cairo_xlib_display_get (dpy, &font_private->display);
3276 if (unlikely (status)) {
3277 free (font_private);
3278 return status;
3281 /* initialize and hook into the CloseDisplay callback */
3282 font_private->close_display_hook.func =
3283 _cairo_xlib_surface_remove_scaled_font;
3284 _cairo_xlib_add_close_display_hook (font_private->display,
3285 &font_private->close_display_hook);
3288 for (i = 0; i < NUM_GLYPHSETS; i++) {
3289 cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
3290 switch (i) {
3291 case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
3292 case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
3293 case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
3294 default: ASSERT_NOT_REACHED; break;
3296 glyphset_info->xrender_format = NULL;
3297 glyphset_info->glyphset = None;
3298 glyphset_info->pending_free_glyphs = NULL;
3301 scaled_font->surface_private = font_private;
3302 scaled_font->surface_backend = &cairo_xlib_surface_backend;
3304 return CAIRO_STATUS_SUCCESS;
3307 static void
3308 _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
3310 cairo_xlib_surface_font_private_t *font_private;
3312 font_private = scaled_font->surface_private;
3313 if (font_private != NULL) {
3314 cairo_xlib_display_t *display;
3315 int i;
3317 display = font_private->display;
3318 _cairo_xlib_remove_close_display_hook (display,
3319 &font_private->close_display_hook);
3321 for (i = 0; i < NUM_GLYPHSETS; i++) {
3322 cairo_xlib_font_glyphset_info_t *glyphset_info;
3324 glyphset_info = &font_private->glyphset_info[i];
3326 if (glyphset_info->pending_free_glyphs != NULL)
3327 free (glyphset_info->pending_free_glyphs);
3329 if (glyphset_info->glyphset) {
3330 cairo_status_t status;
3332 status = _cairo_xlib_display_queue_resource (display,
3333 XRenderFreeGlyphSet,
3334 glyphset_info->glyphset);
3335 (void) status; /* XXX cannot propagate failure */
3339 _cairo_xlib_display_destroy (display);
3340 free (font_private);
3344 static void
3345 _cairo_xlib_render_free_glyphs (Display *dpy,
3346 cairo_xlib_font_glyphset_free_glyphs_t *to_free)
3348 XRenderFreeGlyphs (dpy,
3349 to_free->glyphset,
3350 to_free->glyph_indices,
3351 to_free->glyph_count);
3354 static cairo_xlib_font_glyphset_info_t *
3355 _cairo_xlib_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
3357 return scaled_glyph->surface_private;
3360 static void
3361 _cairo_xlib_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
3362 cairo_xlib_font_glyphset_info_t *glyphset_info)
3364 scaled_glyph->surface_private = glyphset_info;
3367 static void
3368 _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
3369 cairo_scaled_font_t *scaled_font)
3371 cairo_xlib_surface_font_private_t *font_private;
3372 cairo_xlib_font_glyphset_info_t *glyphset_info;
3374 if (scaled_font->finished)
3375 return;
3377 font_private = scaled_font->surface_private;
3378 glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
3379 if (font_private != NULL && glyphset_info != NULL) {
3380 cairo_xlib_font_glyphset_free_glyphs_t *to_free;
3381 cairo_status_t status;
3383 to_free = glyphset_info->pending_free_glyphs;
3384 if (to_free != NULL &&
3385 to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
3387 status = _cairo_xlib_display_queue_work (font_private->display,
3388 (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs,
3389 to_free,
3390 free);
3391 /* XXX cannot propagate failure */
3392 if (unlikely (status))
3393 free (to_free);
3395 to_free = glyphset_info->pending_free_glyphs = NULL;
3398 if (to_free == NULL) {
3399 to_free = malloc (sizeof (cairo_xlib_font_glyphset_free_glyphs_t));
3400 if (unlikely (to_free == NULL)) {
3401 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
3402 return; /* XXX cannot propagate failure */
3405 to_free->glyphset = glyphset_info->glyphset;
3406 to_free->glyph_count = 0;
3407 glyphset_info->pending_free_glyphs = to_free;
3410 to_free->glyph_indices[to_free->glyph_count++] =
3411 _cairo_scaled_glyph_index (scaled_glyph);
3415 static cairo_bool_t
3416 _native_byte_order_lsb (void)
3418 int x = 1;
3420 return *((char *) &x) == 1;
3423 static cairo_xlib_font_glyphset_info_t *
3424 _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
3425 cairo_format_t format)
3427 cairo_xlib_surface_font_private_t *font_private;
3428 cairo_xlib_font_glyphset_info_t *glyphset_info;
3429 int glyphset_index;
3431 switch (format) {
3432 default:
3433 case CAIRO_FORMAT_RGB24:
3434 case CAIRO_FORMAT_ARGB32: glyphset_index = GLYPHSET_INDEX_ARGB32; break;
3435 case CAIRO_FORMAT_A8: glyphset_index = GLYPHSET_INDEX_A8; break;
3436 case CAIRO_FORMAT_A1: glyphset_index = GLYPHSET_INDEX_A1; break;
3439 font_private = scaled_font->surface_private;
3440 glyphset_info = &font_private->glyphset_info[glyphset_index];
3441 if (glyphset_info->glyphset == None) {
3442 cairo_xlib_display_t *display = font_private->display;
3444 glyphset_info->xrender_format =
3445 _cairo_xlib_display_get_xrender_format (display,
3446 glyphset_info->format);
3447 glyphset_info->glyphset = XRenderCreateGlyphSet (display->display,
3448 glyphset_info->xrender_format);
3451 return glyphset_info;
3454 static cairo_bool_t
3455 _cairo_xlib_glyphset_info_has_pending_free_glyph (
3456 cairo_xlib_font_glyphset_info_t *glyphset_info,
3457 unsigned long glyph_index)
3459 if (glyphset_info->pending_free_glyphs != NULL) {
3460 cairo_xlib_font_glyphset_free_glyphs_t *to_free;
3461 int i;
3463 to_free = glyphset_info->pending_free_glyphs;
3464 for (i = 0; i < to_free->glyph_count; i++) {
3465 if (to_free->glyph_indices[i] == glyph_index) {
3466 to_free->glyph_count--;
3467 memmove (&to_free->glyph_indices[i],
3468 &to_free->glyph_indices[i+1],
3469 (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
3470 return TRUE;
3475 return FALSE;
3478 static cairo_xlib_font_glyphset_info_t *
3479 _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (
3480 cairo_scaled_font_t *scaled_font,
3481 unsigned long glyph_index,
3482 cairo_image_surface_t *surface)
3484 cairo_xlib_surface_font_private_t *font_private;
3485 int i;
3487 font_private = scaled_font->surface_private;
3488 if (font_private == NULL)
3489 return NULL;
3491 if (surface != NULL) {
3492 switch (surface->format) {
3493 default:
3494 case CAIRO_FORMAT_RGB24:
3495 case CAIRO_FORMAT_ARGB32: i = GLYPHSET_INDEX_ARGB32; break;
3496 case CAIRO_FORMAT_A8: i = GLYPHSET_INDEX_A8; break;
3497 case CAIRO_FORMAT_A1: i = GLYPHSET_INDEX_A1; break;
3499 if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
3500 &font_private->glyphset_info[i],
3501 glyph_index))
3503 return &font_private->glyphset_info[i];
3505 } else {
3506 for (i = 0; i < NUM_GLYPHSETS; i++) {
3507 if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
3508 &font_private->glyphset_info[i],
3509 glyph_index))
3511 return &font_private->glyphset_info[i];
3516 return NULL;
3519 static cairo_status_t
3520 _cairo_xlib_surface_add_glyph (Display *dpy,
3521 cairo_scaled_font_t *scaled_font,
3522 cairo_scaled_glyph_t **pscaled_glyph)
3524 XGlyphInfo glyph_info;
3525 unsigned long glyph_index;
3526 unsigned char *data;
3527 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3528 cairo_scaled_glyph_t *scaled_glyph = *pscaled_glyph;
3529 cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
3530 cairo_bool_t already_had_glyph_surface;
3531 cairo_xlib_font_glyphset_info_t *glyphset_info;
3533 glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
3535 /* check to see if we have a pending XRenderFreeGlyph for this glyph */
3536 glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
3537 if (glyphset_info != NULL) {
3538 _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
3539 return CAIRO_STATUS_SUCCESS;
3542 if (!glyph_surface) {
3543 status = _cairo_scaled_glyph_lookup (scaled_font,
3544 glyph_index,
3545 CAIRO_SCALED_GLYPH_INFO_METRICS |
3546 CAIRO_SCALED_GLYPH_INFO_SURFACE,
3547 pscaled_glyph);
3548 if (unlikely (status))
3549 return status;
3551 scaled_glyph = *pscaled_glyph;
3552 glyph_surface = scaled_glyph->surface;
3553 already_had_glyph_surface = FALSE;
3554 } else {
3555 already_had_glyph_surface = TRUE;
3558 if (scaled_font->surface_private == NULL) {
3559 status = _cairo_xlib_surface_font_init (dpy, scaled_font);
3560 if (unlikely (status))
3561 return status;
3564 glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_format (scaled_font,
3565 glyph_surface->format);
3567 /* XRenderAddGlyph does not handle a glyph surface larger than the extended maximum XRequest size. */
3569 int len = cairo_format_stride_for_width (glyphset_info->format, glyph_surface->width) * glyph_surface->height;
3570 int max_request_size = (XExtendedMaxRequestSize (dpy) ? XExtendedMaxRequestSize (dpy) : XMaxRequestSize (dpy)) * 4 -
3571 sz_xRenderAddGlyphsReq -
3572 sz_xGlyphInfo -
3574 if (len >= max_request_size)
3575 return CAIRO_INT_STATUS_UNSUPPORTED;
3578 /* If the glyph surface has zero height or width, we create
3579 * a clear 1x1 surface, to avoid various X server bugs.
3581 if (glyph_surface->width == 0 || glyph_surface->height == 0) {
3582 cairo_t *cr;
3583 cairo_surface_t *tmp_surface;
3585 tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
3586 status = tmp_surface->status;
3587 if (unlikely (status))
3588 goto BAIL;
3590 cr = cairo_create (tmp_surface);
3591 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3592 cairo_paint (cr);
3593 status = cairo_status (cr);
3594 cairo_destroy (cr);
3596 tmp_surface->device_transform = glyph_surface->base.device_transform;
3597 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
3599 glyph_surface = (cairo_image_surface_t *) tmp_surface;
3601 if (unlikely (status))
3602 goto BAIL;
3605 /* If the glyph format does not match the font format, then we
3606 * create a temporary surface for the glyph image with the font's
3607 * format.
3609 if (glyph_surface->format != glyphset_info->format) {
3610 cairo_t *cr;
3611 cairo_surface_t *tmp_surface;
3613 tmp_surface = cairo_image_surface_create (glyphset_info->format,
3614 glyph_surface->width,
3615 glyph_surface->height);
3616 status = tmp_surface->status;
3617 if (unlikely (status))
3618 goto BAIL;
3620 tmp_surface->device_transform = glyph_surface->base.device_transform;
3621 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
3623 cr = cairo_create (tmp_surface);
3624 cairo_set_source_surface (cr, &glyph_surface->base, 0, 0);
3625 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3626 cairo_paint (cr);
3627 status = cairo_status (cr);
3628 cairo_destroy (cr);
3630 glyph_surface = (cairo_image_surface_t *) tmp_surface;
3632 if (unlikely (status))
3633 goto BAIL;
3636 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
3637 glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
3638 glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
3639 glyph_info.width = glyph_surface->width;
3640 glyph_info.height = glyph_surface->height;
3641 glyph_info.xOff = scaled_glyph->x_advance;
3642 glyph_info.yOff = scaled_glyph->y_advance;
3644 data = glyph_surface->data;
3646 /* flip formats around */
3647 switch (scaled_glyph->surface->format) {
3648 case CAIRO_FORMAT_A1:
3649 /* local bitmaps are always stored with bit == byte */
3650 if (_native_byte_order_lsb() != (BitmapBitOrder (dpy) == LSBFirst)) {
3651 int c = glyph_surface->stride * glyph_surface->height;
3652 unsigned char *d;
3653 unsigned char *new, *n;
3655 new = malloc (c);
3656 if (!new) {
3657 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3658 goto BAIL;
3660 n = new;
3661 d = data;
3662 do {
3663 char b = *d++;
3664 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
3665 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
3666 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
3667 *n++ = b;
3668 } while (--c);
3669 data = new;
3671 break;
3672 case CAIRO_FORMAT_A8:
3673 break;
3674 case CAIRO_FORMAT_ARGB32:
3675 if (_native_byte_order_lsb() != (ImageByteOrder (dpy) == LSBFirst)) {
3676 unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
3677 const uint32_t *d;
3678 uint32_t *new, *n;
3680 new = malloc (4 * c);
3681 if (unlikely (new == NULL)) {
3682 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3683 goto BAIL;
3685 n = new;
3686 d = (uint32_t *) data;
3687 do {
3688 *n++ = bswap_32 (*d++);
3689 } while (--c);
3690 data = (uint8_t *) new;
3692 break;
3693 case CAIRO_FORMAT_RGB24:
3694 default:
3695 ASSERT_NOT_REACHED;
3696 break;
3698 /* XXX assume X server wants pixman padding. Xft assumes this as well */
3700 XRenderAddGlyphs (dpy, glyphset_info->glyphset,
3701 &glyph_index, &glyph_info, 1,
3702 (char *) data,
3703 glyph_surface->stride * glyph_surface->height);
3705 if (data != glyph_surface->data)
3706 free (data);
3708 _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
3710 BAIL:
3711 if (glyph_surface != scaled_glyph->surface)
3712 cairo_surface_destroy (&glyph_surface->base);
3714 /* if the scaled glyph didn't already have a surface attached
3715 * to it, release the created surface now that we have it
3716 * uploaded to the X server. If the surface has already been
3717 * there (eg. because image backend requested it), leave it in
3718 * the cache
3720 if (!already_had_glyph_surface)
3721 _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
3723 return status;
3726 typedef void (*cairo_xrender_composite_text_func_t)
3727 (Display *dpy,
3728 int op,
3729 Picture src,
3730 Picture dst,
3731 _Xconst XRenderPictFormat *maskFormat,
3732 int xSrc,
3733 int ySrc,
3734 int xDst,
3735 int yDst,
3736 _Xconst XGlyphElt8 *elts,
3737 int nelt);
3739 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
3740 * an input glyph with double coordinates, and as "working" glyph with
3741 * integer from-current-point offsets. */
3742 typedef union {
3743 cairo_glyph_t d;
3744 unsigned long index;
3745 struct {
3746 unsigned long index;
3747 int x;
3748 int y;
3749 } i;
3750 } cairo_xlib_glyph_t;
3752 /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
3753 COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
3755 /* Start a new element for the first glyph,
3756 * or for any glyph that has unexpected position,
3757 * or if current element has too many glyphs
3758 * (Xrender limits each element to 252 glyphs, we limit them to 128)
3760 * These same conditions need to be mirrored between
3761 * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
3763 #define _start_new_glyph_elt(count, glyph) \
3764 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
3766 static cairo_status_t
3767 _emit_glyphs_chunk (cairo_xlib_surface_t *dst,
3768 cairo_xlib_glyph_t *glyphs,
3769 int num_glyphs,
3770 cairo_scaled_font_t *scaled_font,
3771 cairo_operator_t op,
3772 cairo_xlib_surface_t *src,
3773 cairo_surface_attributes_t *attributes,
3774 /* info for this chunk */
3775 int num_elts,
3776 int width,
3777 cairo_xlib_font_glyphset_info_t *glyphset_info)
3779 /* Which XRenderCompositeText function to use */
3780 cairo_xrender_composite_text_func_t composite_text_func;
3781 int size;
3783 /* Element buffer stuff */
3784 XGlyphElt8 *elts;
3785 XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
3787 /* Reuse the input glyph array for output char generation */
3788 char *char8 = (char *) glyphs;
3789 unsigned short *char16 = (unsigned short *) glyphs;
3790 unsigned int *char32 = (unsigned int *) glyphs;
3792 int i;
3793 int nelt; /* Element index */
3794 int n; /* Num output glyphs in current element */
3795 int j; /* Num output glyphs so far */
3797 switch (width) {
3798 case 1:
3799 /* don't cast the 8-variant, to catch possible mismatches */
3800 composite_text_func = XRenderCompositeText8;
3801 size = sizeof (char);
3802 break;
3803 case 2:
3804 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
3805 size = sizeof (unsigned short);
3806 break;
3807 default:
3808 case 4:
3809 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
3810 size = sizeof (unsigned int);
3813 /* Allocate element array */
3814 if (num_elts <= ARRAY_LENGTH (stack_elts)) {
3815 elts = stack_elts;
3816 } else {
3817 elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
3818 if (unlikely (elts == NULL))
3819 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3822 /* Fill them in */
3823 nelt = 0;
3824 n = 0;
3825 j = 0;
3826 for (i = 0; i < num_glyphs; i++) {
3828 /* Start a new element for first output glyph,
3829 * or for any glyph that has unexpected position,
3830 * or if current element has too many glyphs.
3832 * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
3834 if (_start_new_glyph_elt (j, &glyphs[i])) {
3835 if (j) {
3836 elts[nelt].nchars = n;
3837 nelt++;
3838 n = 0;
3840 elts[nelt].chars = char8 + size * j;
3841 elts[nelt].glyphset = glyphset_info->glyphset;
3842 elts[nelt].xOff = glyphs[i].i.x;
3843 elts[nelt].yOff = glyphs[i].i.y;
3846 switch (width) {
3847 case 1: char8 [j] = (char) glyphs[i].index; break;
3848 case 2: char16[j] = (unsigned short) glyphs[i].index; break;
3849 default:
3850 case 4: char32[j] = (unsigned int) glyphs[i].index; break;
3853 n++;
3854 j++;
3857 if (n) {
3858 elts[nelt].nchars = n;
3859 nelt++;
3860 n = 0;
3863 /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
3864 * expected number of xGlyphElts. */
3865 assert (nelt == num_elts);
3867 composite_text_func (dst->dpy,
3868 _render_operator (op),
3869 src->src_picture,
3870 dst->dst_picture,
3871 glyphset_info->xrender_format,
3872 attributes->x_offset + elts[0].xOff,
3873 attributes->y_offset + elts[0].yOff,
3874 elts[0].xOff, elts[0].yOff,
3875 (XGlyphElt8 *) elts, nelt);
3877 if (elts != stack_elts)
3878 free (elts);
3880 return CAIRO_STATUS_SUCCESS;
3884 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
3885 * enough room for padding */
3886 #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
3888 static cairo_status_t
3889 _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
3890 cairo_xlib_glyph_t *glyphs,
3891 int num_glyphs,
3892 cairo_scaled_font_t *scaled_font,
3893 cairo_operator_t op,
3894 cairo_xlib_surface_t *src,
3895 cairo_surface_attributes_t *attributes,
3896 int *remaining_glyphs)
3898 int i;
3899 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3900 cairo_scaled_glyph_t *scaled_glyph;
3901 cairo_fixed_t x = 0, y = 0;
3902 cairo_xlib_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
3904 unsigned long max_index = 0;
3905 int width = 1;
3906 int num_elts = 0;
3907 int num_out_glyphs = 0;
3909 int max_request_size = XMaxRequestSize (dst->dpy) * 4
3910 - MAX (sz_xRenderCompositeGlyphs8Req,
3911 MAX(sz_xRenderCompositeGlyphs16Req,
3912 sz_xRenderCompositeGlyphs32Req));
3913 int request_size = 0;
3915 _cairo_xlib_surface_ensure_dst_picture (dst);
3916 _cairo_xlib_display_notify (dst->display);
3918 for (i = 0; i < num_glyphs; i++) {
3919 int this_x, this_y;
3920 int old_width;
3922 status = _cairo_scaled_glyph_lookup (scaled_font,
3923 glyphs[i].index,
3924 CAIRO_SCALED_GLYPH_INFO_METRICS,
3925 &scaled_glyph);
3926 if (status != CAIRO_STATUS_SUCCESS)
3927 return status;
3929 this_x = _cairo_lround (glyphs[i].d.x);
3930 this_y = _cairo_lround (glyphs[i].d.y);
3932 /* Glyph skipping:
3934 * We skip any glyphs that have troublesome coordinates. We want
3935 * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
3936 * a signed 16bit integer, otherwise it will overflow in the render
3937 * protocol.
3938 * To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
3939 * a signed 15bit integer. The trivial option would be to allow
3940 * coordinates -8192..8192, but that's kinda dull. It probably will
3941 * take a decade or so to get monitors 8192x4096 or something. A
3942 * negative value of -8192 on the other hand, is absolutely useless.
3943 * Note that we do want to allow some negative positions. The glyph
3944 * may start off the screen but part of it make it to the screen.
3945 * Anyway, we will allow positions in the range -4096..122887. That
3946 * will buy us a few more years before this stops working.
3948 * Update: upon seeing weird glyphs, we just return and let fallback
3949 * code do the job.
3951 if (((this_x+4096)|(this_y+4096))&~0x3fffu)
3952 break;
3954 /* Send unsent glyphs to the server */
3955 if (_cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
3956 status = _cairo_xlib_surface_add_glyph (dst->dpy,
3957 scaled_font,
3958 &scaled_glyph);
3959 if (unlikely (status)) {
3960 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
3961 /* Break so we flush glyphs so far and let fallback code
3962 * handle the rest */
3963 break;
3965 return status;
3969 this_glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
3970 if (!glyphset_info)
3971 glyphset_info = this_glyphset_info;
3973 /* The invariant here is that we can always flush the glyphs
3974 * accumulated before this one, using old_width, and they
3975 * would fit in the request.
3977 old_width = width;
3979 /* Update max glyph index */
3980 if (glyphs[i].index > max_index) {
3981 max_index = glyphs[i].index;
3982 if (max_index >= 65536)
3983 width = 4;
3984 else if (max_index >= 256)
3985 width = 2;
3986 if (width != old_width)
3987 request_size += (width - old_width) * num_out_glyphs;
3990 /* If we will pass the max request size by adding this glyph,
3991 * flush current glyphs. Note that we account for a
3992 * possible element being added below.
3994 * Also flush if changing glyphsets, as Xrender limits one mask
3995 * format per request, so we can either break up, or use a
3996 * wide-enough mask format. We do the former. One reason to
3997 * prefer the latter is the fact that Xserver ADDs all glyphs
3998 * to the mask first, and then composes that to final surface,
3999 * though it's not a big deal.
4001 if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
4002 (this_glyphset_info != glyphset_info)) {
4003 status = _emit_glyphs_chunk (dst, glyphs, i,
4004 scaled_font, op, src, attributes,
4005 num_elts, old_width, glyphset_info);
4006 if (status != CAIRO_STATUS_SUCCESS)
4007 return status;
4009 glyphs += i;
4010 num_glyphs -= i;
4011 i = 0;
4012 max_index = glyphs[i].index;
4013 width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
4014 request_size = 0;
4015 num_elts = 0;
4016 num_out_glyphs = 0;
4017 x = y = 0;
4018 glyphset_info = this_glyphset_info;
4021 /* Convert absolute glyph position to relative-to-current-point
4022 * position */
4023 glyphs[i].i.x = this_x - x;
4024 glyphs[i].i.y = this_y - y;
4026 /* Start a new element for the first glyph,
4027 * or for any glyph that has unexpected position,
4028 * or if current element has too many glyphs.
4030 * These same conditions are mirrored in _emit_glyphs_chunk().
4032 if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
4033 num_elts++;
4034 request_size += _cairo_sz_xGlyphElt;
4037 /* adjust current-position */
4038 x = this_x + scaled_glyph->x_advance;
4039 y = this_y + scaled_glyph->y_advance;
4041 num_out_glyphs++;
4042 request_size += width;
4045 if (num_elts)
4046 status = _emit_glyphs_chunk (dst, glyphs, i,
4047 scaled_font, op, src, attributes,
4048 num_elts, width, glyphset_info);
4050 *remaining_glyphs = num_glyphs - i;
4051 if (*remaining_glyphs && status == CAIRO_STATUS_SUCCESS)
4052 status = CAIRO_INT_STATUS_UNSUPPORTED;
4054 return status;
4057 static cairo_bool_t
4058 _cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst,
4059 cairo_scaled_font_t *scaled_font)
4061 cairo_xlib_surface_font_private_t *font_private;
4063 font_private = scaled_font->surface_private;
4064 if ((scaled_font->surface_backend != NULL &&
4065 scaled_font->surface_backend != &cairo_xlib_surface_backend) ||
4066 (font_private != NULL && font_private->display != dst->display))
4068 return FALSE;
4071 return TRUE;
4074 static cairo_int_status_t
4075 _cairo_xlib_surface_show_glyphs (void *abstract_dst,
4076 cairo_operator_t op,
4077 const cairo_pattern_t *src_pattern,
4078 cairo_glyph_t *glyphs,
4079 int num_glyphs,
4080 cairo_scaled_font_t *scaled_font,
4081 int *remaining_glyphs,
4082 cairo_rectangle_int_t *extents)
4084 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
4085 cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst;
4087 composite_operation_t operation;
4088 cairo_surface_attributes_t attributes;
4089 cairo_xlib_surface_t *src = NULL;
4091 cairo_solid_pattern_t solid_pattern;
4093 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
4094 return CAIRO_INT_STATUS_UNSUPPORTED;
4096 /* Just let unbounded operators go through the fallback code
4097 * instead of trying to do the fixups here */
4098 if (!_cairo_operator_bounded_by_mask (op))
4099 return CAIRO_INT_STATUS_UNSUPPORTED;
4101 /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
4102 * the solid source seems to be multiplied by the glyph mask, and
4103 * then the entire thing is copied to the destination surface,
4104 * including the fully transparent "background" of the rectangular
4105 * glyph surface. */
4106 if (op == CAIRO_OPERATOR_SOURCE &&
4107 !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
4108 return CAIRO_INT_STATUS_UNSUPPORTED;
4110 /* We can only use our code if we either have no clip or
4111 * have a real native clip region set. If we're using
4112 * fallback clip masking, we have to go through the full
4113 * fallback path.
4115 if (dst->base.clip &&
4116 (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
4117 dst->base.clip->surface != NULL))
4118 return CAIRO_INT_STATUS_UNSUPPORTED;
4120 operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
4121 if (operation == DO_UNSUPPORTED)
4122 return CAIRO_INT_STATUS_UNSUPPORTED;
4124 if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
4125 return CAIRO_INT_STATUS_UNSUPPORTED;
4127 /* After passing all those tests, we're now committed to rendering
4128 * these glyphs or to fail trying. We first upload any glyphs to
4129 * the X server that it doesn't have already, then we draw
4130 * them.
4133 /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
4134 * the mask (the glyphs). This code below was executed as a side effect
4135 * of going through the _clip_and_composite fallback code for old_show_glyphs,
4136 * so PictOpClear was never used with CompositeText before.
4138 if (op == CAIRO_OPERATOR_CLEAR) {
4139 _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
4140 CAIRO_CONTENT_COLOR);
4141 src_pattern = &solid_pattern.base;
4142 op = CAIRO_OPERATOR_DEST_OUT;
4145 if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
4146 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
4147 CAIRO_CONTENT_COLOR_ALPHA,
4148 0, 0, 1, 1,
4149 CAIRO_PATTERN_ACQUIRE_NONE,
4150 (cairo_surface_t **) &src,
4151 &attributes);
4152 if (unlikely (status))
4153 goto BAIL0;
4154 } else {
4155 cairo_rectangle_int_t glyph_extents;
4157 status = _cairo_scaled_font_glyph_device_extents (scaled_font,
4158 glyphs,
4159 num_glyphs,
4160 &glyph_extents);
4161 if (unlikely (status))
4162 goto BAIL0;
4164 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
4165 CAIRO_CONTENT_COLOR_ALPHA,
4166 glyph_extents.x, glyph_extents.y,
4167 glyph_extents.width, glyph_extents.height,
4168 dst->buggy_pad_reflect ?
4169 CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
4170 CAIRO_PATTERN_ACQUIRE_NONE,
4171 (cairo_surface_t **) &src,
4172 &attributes);
4173 if (unlikely (status))
4174 goto BAIL0;
4177 operation = _recategorize_composite_operation (dst, op, src,
4178 &attributes, TRUE);
4179 if (operation == DO_UNSUPPORTED) {
4180 status = CAIRO_INT_STATUS_UNSUPPORTED;
4181 goto BAIL1;
4184 status = _cairo_xlib_surface_set_attributes (src, &attributes, 0, 0);
4185 if (unlikely (status))
4186 goto BAIL1;
4188 _cairo_scaled_font_freeze_cache (scaled_font);
4189 if (_cairo_xlib_surface_owns_font (dst, scaled_font)) {
4190 status = _cairo_xlib_surface_emit_glyphs (dst,
4191 (cairo_xlib_glyph_t *) glyphs,
4192 num_glyphs,
4193 scaled_font,
4195 src,
4196 &attributes,
4197 remaining_glyphs);
4198 } else
4199 status = CAIRO_INT_STATUS_UNSUPPORTED;
4200 _cairo_scaled_font_thaw_cache (scaled_font);
4202 BAIL1:
4203 if (src)
4204 _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
4205 if (src_pattern == &solid_pattern.base)
4206 _cairo_pattern_fini (&solid_pattern.base);
4207 BAIL0:
4208 _cairo_xlib_display_notify (dst->display);
4210 return status;
4214 typedef struct
4216 cairo_space_t base;
4217 Display* dpy;
4218 Screen* screen;
4219 int owns_dpy;
4220 } cairo_xlib_space_t;
4222 static void
4223 _cairo_xlib_space_destroy(void* abstract_space)
4225 cairo_xlib_space_t* space = abstract_space;
4226 if(space->owns_dpy)
4227 XCloseDisplay(space->dpy);
4228 free(space);
4231 static cairo_surface_t*
4232 _cairo_xlib_surface_create_offscreen(Display* dpy, cairo_xlib_surface_t* surface, cairo_content_t content, double width, double height)
4234 cairo_xlib_display_t* display;
4235 Screen* screen;
4236 Pixmap pix;
4237 XRenderPictFormat *xrender_format;
4239 screen = DefaultScreenOfDisplay(dpy);
4241 assert (width <= XLIB_COORD_MAX && height <= XLIB_COORD_MAX);
4243 if(_cairo_xlib_display_get(dpy, &display))
4244 return _cairo_surface_create_in_error(CAIRO_STATUS_NO_MEMORY);
4246 /* As a good first approximation, if the display doesn't have even
4247 * the most elementary RENDER operation, then we're better off
4248 * using image surfaces for all temporary operations, so return NULL
4249 * and let the fallback code happen.
4252 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (display))
4253 return _cairo_surface_create_in_error(CAIRO_STATUS_NO_MEMORY);
4255 xrender_format = _cairo_xlib_display_get_xrender_format (display,
4256 _cairo_format_from_content(content));
4257 if (xrender_format == NULL)
4258 return _cairo_surface_create_in_error(CAIRO_STATUS_NO_MEMORY);
4260 pix = XCreatePixmap (dpy, RootWindowOfScreen(screen),
4261 width <= 0 ? 1 : width, height <= 0 ? 1 : height,
4262 xrender_format->depth);
4264 surface = (cairo_xlib_surface_t *)
4265 _cairo_xlib_surface_init_internal (surface, dpy, pix,
4266 screen, NULL,
4267 xrender_format,
4268 width, height,
4269 xrender_format->depth);
4270 if (surface->base.status) {
4271 XFreePixmap (dpy, pix);
4272 return &surface->base;
4275 surface->owns_pixmap = TRUE;
4277 return &surface->base;
4280 static XVisualInfo*
4281 _cairo_get_xvisualinfo(Display* dpy, unsigned long drawable, unsigned long visualid)
4283 XVisualInfo vit;
4284 XVisualInfo *vi;
4285 int nvi;
4287 if(!visualid)
4289 XWindowAttributes attr;
4290 XGetWindowAttributes(dpy, drawable, &attr);
4291 visualid = XVisualIDFromVisual(attr.visual);
4294 vit.visualid = visualid;
4295 vi = XGetVisualInfo(dpy, VisualIDMask, &vit, &nvi);
4297 if(!nvi)
4298 return 0;
4300 return vi;
4303 static cairo_surface_t*
4304 _cairo_xlib_surface_create_for_drawable(Display* dpy, cairo_xlib_surface_t* surface, cairo_content_t content, unsigned long drawable, unsigned long visualid, double width, double height)
4306 XVisualInfo* vi;
4307 Screen *screen;
4308 Visual* visual;
4310 vi = _cairo_get_xvisualinfo(dpy, drawable, visualid);
4311 if(!vi)
4312 return _cairo_surface_create_in_error(CAIRO_STATUS_INVALID_VISUAL);
4314 visual = vi->visual;
4316 screen = _cairo_xlib_screen_from_visual (dpy, vi->visual);
4317 XFree(vi);
4319 if (screen == NULL)
4320 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
4322 return _cairo_xlib_surface_init_internal (surface, dpy, (Drawable)drawable, screen,
4323 visual, NULL, width, height, 0);
4326 static cairo_surface_t*
4327 _cairo_xlib_space_surface_create(void *abstract_space, void* abstract_surface, cairo_content_t content,
4328 unsigned long drawable, unsigned long visualid, cairo_bool_t double_buffered,
4329 double width, double height, int color_mantissa_bits, int alpha_mantissa_bits, int exponent_bits, int shared_exponent_bits)
4331 Display* dpy;
4332 cairo_xlib_space_t* space = abstract_space;
4333 cairo_xlib_surface_t* surface = abstract_surface;
4334 if(surface && surface->base.backend != &cairo_xlib_surface_backend)
4335 return _cairo_surface_create_in_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
4337 if(!surface && !space)
4338 return _cairo_surface_create_in_error(CAIRO_STATUS_SURFACE_FINISHED);
4340 dpy = space ? space->dpy : surface->dpy;
4342 if(drawable == ~0UL)
4343 drawable = surface ? (unsigned long)surface->drawable : 0;
4345 if(width < 0)
4347 if(!surface)
4348 return _cairo_surface_create_in_error(CAIRO_STATUS_SURFACE_FINISHED);
4349 width = surface->width;
4352 if(height < 0)
4354 if(!surface)
4355 return _cairo_surface_create_in_error(CAIRO_STATUS_SURFACE_FINISHED);
4356 height = surface->height;
4359 if(!surface)
4361 surface = malloc (sizeof (cairo_xlib_surface_t));
4363 if (unlikely (surface == NULL))
4364 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
4366 _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend, 0);
4367 surface->dpy = 0;
4370 if(drawable)
4371 return _cairo_xlib_surface_create_for_drawable(dpy, surface, content, drawable, visualid, width, height);
4372 else
4373 return _cairo_xlib_surface_create_offscreen(dpy, surface, content, width, height);
4376 static cairo_status_t
4377 _cairo_xlib_space_sync(void* abstract_space)
4379 cairo_xlib_space_t* space = abstract_space;
4380 XSync(space->dpy, 0);
4381 return CAIRO_STATUS_SUCCESS;
4384 static cairo_space_backend_t _cairo_xlib_space_backend =
4386 _cairo_xlib_space_destroy,
4387 _cairo_xlib_space_surface_create,
4388 _cairo_xlib_space_sync,
4391 cairo_public cairo_space_t *
4392 cairo_xlib_space_create(const char* name)
4394 Display* dpy;
4395 dpy = XOpenDisplay(name);
4396 if(!dpy)
4397 return 0;
4398 return cairo_xlib_space_wrap(dpy, DefaultScreen(dpy), 1);
4401 cairo_public cairo_space_t *
4402 cairo_xlib_space_wrap(Display *dpy, int screen, int owns_dpy)
4404 cairo_xlib_space_t* space;
4405 if(!dpy)
4406 return cairo_xlib_space_create(0);
4408 space = calloc(sizeof(cairo_xlib_space_t), 1);
4410 CAIRO_REFERENCE_COUNT_INIT(&space->base.ref_count, 1);
4411 space->base.backend = &_cairo_xlib_space_backend;
4412 space->dpy = dpy;
4413 space->screen = ScreenOfDisplay(dpy, screen);
4414 space->owns_dpy = owns_dpy;
4416 return &space->base;