2009-12-07 Rolf Bjarne Kvinge <RKvinge@novell.com>
[moon.git] / cairo / src / cairo-xlib-surface.c
blobfd111fff2780e68050829aca1354613b3c28b9ac
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_ensure_src_picture (cairo_xlib_surface_t *surface);
73 static void
74 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface);
76 static cairo_bool_t
77 _cairo_surface_is_xlib (cairo_surface_t *surface);
79 static cairo_bool_t
80 _native_byte_order_lsb (void);
82 static cairo_int_status_t
83 _cairo_xlib_surface_show_glyphs (void *abstract_dst,
84 cairo_operator_t op,
85 cairo_pattern_t *src_pattern,
86 cairo_glyph_t *glyphs,
87 int num_glyphs,
88 cairo_scaled_font_t *scaled_font,
89 int *remaining_glyphs);
92 * Instead of taking two round trips for each blending request,
93 * assume that if a particular drawable fails GetImage that it will
94 * fail for a "while"; use temporary pixmaps to avoid the errors
97 #define CAIRO_ASSUME_PIXMAP 20
99 static const XTransform identity = { {
100 { 1 << 16, 0x00000, 0x00000 },
101 { 0x00000, 1 << 16, 0x00000 },
102 { 0x00000, 0x00000, 1 << 16 },
103 } };
105 #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
106 (((surface)->render_major > major) || \
107 (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
109 #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
110 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
111 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
113 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
115 #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
116 #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
118 #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
119 #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
120 #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
121 #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
123 #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
124 #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
126 static cairo_surface_t *
127 _cairo_xlib_surface_create_similar_with_format (void *abstract_src,
128 cairo_format_t format,
129 int width,
130 int height)
132 cairo_xlib_surface_t *src = abstract_src;
133 Display *dpy = src->dpy;
134 Pixmap pix;
135 cairo_xlib_surface_t *surface;
136 XRenderPictFormat *xrender_format;
138 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
139 return NULL;
141 /* As a good first approximation, if the display doesn't have even
142 * the most elementary RENDER operation, then we're better off
143 * using image surfaces for all temporary operations, so return NULL
144 * and let the fallback code happen.
146 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
147 return NULL;
149 xrender_format = _cairo_xlib_display_get_xrender_format (
150 src->display,
151 format);
152 if (xrender_format == NULL)
153 return NULL;
155 pix = XCreatePixmap (dpy, src->drawable,
156 width <= 0 ? 1 : width, height <= 0 ? 1 : height,
157 xrender_format->depth);
159 surface = (cairo_xlib_surface_t *)
160 _cairo_xlib_surface_create_internal (dpy, pix,
161 src->screen, NULL,
162 xrender_format,
163 width, height,
164 xrender_format->depth);
165 if (surface->base.status) {
166 XFreePixmap (dpy, pix);
167 return &surface->base;
170 surface->owns_pixmap = TRUE;
172 return &surface->base;
175 static cairo_content_t
176 _xrender_format_to_content (XRenderPictFormat *xrender_format)
178 cairo_bool_t xrender_format_has_alpha;
179 cairo_bool_t xrender_format_has_color;
181 /* This only happens when using a non-Render server. Let's punt
182 * and say there's no alpha here. */
183 if (xrender_format == NULL)
184 return CAIRO_CONTENT_COLOR;
186 xrender_format_has_alpha = (xrender_format->direct.alphaMask != 0);
187 xrender_format_has_color = (xrender_format->direct.redMask != 0 ||
188 xrender_format->direct.greenMask != 0 ||
189 xrender_format->direct.blueMask != 0);
191 if (xrender_format_has_alpha)
192 if (xrender_format_has_color)
193 return CAIRO_CONTENT_COLOR_ALPHA;
194 else
195 return CAIRO_CONTENT_ALPHA;
196 else
197 return CAIRO_CONTENT_COLOR;
200 static cairo_surface_t *
201 _cairo_xlib_surface_create_similar (void *abstract_src,
202 cairo_content_t content,
203 int width,
204 int height)
206 cairo_xlib_surface_t *src = abstract_src;
207 XRenderPictFormat *xrender_format = src->xrender_format;
208 cairo_xlib_surface_t *surface;
209 Pixmap pix;
211 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
212 return _cairo_surface_create_in_error (_cairo_error(CAIRO_STATUS_NO_MEMORY));
214 _cairo_xlib_display_notify (src->display);
216 /* Start by examining the surface's XRenderFormat, or if it
217 * doesn't have one, then look one up through its visual (in the
218 * case of a bitmap, it won't even have that). */
219 if (xrender_format == NULL && src->visual != NULL)
220 xrender_format = XRenderFindVisualFormat (src->dpy, src->visual);
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 if (xrender_format == NULL ||
228 _xrender_format_to_content (xrender_format) != content)
230 return _cairo_xlib_surface_create_similar_with_format (abstract_src,
231 _cairo_format_from_content (content),
232 width, height);
235 /* We've got a compatible XRenderFormat now, which means the
236 * similar surface will match the existing surface as closely in
237 * visual/depth etc. as possible. */
238 pix = XCreatePixmap (src->dpy, src->drawable,
239 width <= 0 ? 1 : width, height <= 0 ? 1 : height,
240 xrender_format->depth);
242 surface = (cairo_xlib_surface_t *)
243 _cairo_xlib_surface_create_internal (src->dpy, pix,
244 src->screen, src->visual,
245 xrender_format,
246 width, height,
247 xrender_format->depth);
248 if (surface->base.status != CAIRO_STATUS_SUCCESS) {
249 XFreePixmap (src->dpy, pix);
250 return &surface->base;
253 surface->owns_pixmap = TRUE;
255 return &surface->base;
258 static cairo_status_t
259 _cairo_xlib_surface_finish (void *abstract_surface)
261 cairo_xlib_surface_t *surface = abstract_surface;
262 cairo_xlib_display_t *display = surface->display;
263 cairo_status_t status = CAIRO_STATUS_SUCCESS;
265 if (surface->owns_pixmap) {
266 cairo_status_t status2;
268 if (surface->dst_picture != None) {
269 status2 = _cairo_xlib_display_queue_resource (display,
270 XRenderFreePicture,
271 surface->dst_picture);
272 if (status2 == CAIRO_STATUS_SUCCESS)
273 surface->dst_picture = None;
274 else if (status == CAIRO_STATUS_SUCCESS)
275 status = status2;
278 if (surface->src_picture != None) {
279 status2 = _cairo_xlib_display_queue_resource (display,
280 XRenderFreePicture,
281 surface->src_picture);
282 if (status2 == CAIRO_STATUS_SUCCESS)
283 surface->src_picture = None;
284 else if (status == CAIRO_STATUS_SUCCESS)
285 status = status2;
288 status2 = _cairo_xlib_display_queue_resource (display,
289 (cairo_xlib_notify_resource_func) XFreePixmap,
290 surface->drawable);
291 if (status2 == CAIRO_STATUS_SUCCESS) {
292 surface->owns_pixmap = FALSE;
293 surface->drawable = None;
294 } else if (status == CAIRO_STATUS_SUCCESS)
295 status = status2;
296 } else {
297 if (surface->dst_picture != None)
298 XRenderFreePicture (surface->dpy, surface->dst_picture);
300 if (surface->src_picture != None)
301 XRenderFreePicture (surface->dpy, surface->src_picture);
304 if (surface->gc != NULL) {
305 cairo_status_t status2;
306 status2 = _cairo_xlib_screen_put_gc (surface->screen_info,
307 surface->depth,
308 surface->gc,
309 surface->have_clip_rects);
310 surface->gc = NULL;
311 if (status == CAIRO_STATUS_SUCCESS)
312 status = status2;
315 if (surface->clip_rects != surface->embedded_clip_rects)
316 free (surface->clip_rects);
318 if (surface->screen_info != NULL)
319 _cairo_xlib_screen_info_destroy (surface->screen_info);
321 if (surface->display != NULL) {
322 _cairo_xlib_remove_close_display_hook (surface->display,
323 &surface->close_display_hook);
324 _cairo_xlib_display_destroy (surface->display);
327 surface->dpy = NULL;
329 return status;
332 static int
333 _noop_error_handler (Display *display,
334 XErrorEvent *event)
336 return False; /* return value is ignored */
339 static void
340 _swap_ximage_2bytes (XImage *ximage)
342 int i, j;
343 char *line = ximage->data;
345 for (j = ximage->height; j; j--) {
346 uint16_t *p = (uint16_t *) line;
347 for (i = ximage->width; i; i--) {
348 *p = bswap_16 (*p);
349 p++;
352 line += ximage->bytes_per_line;
356 static void
357 _swap_ximage_3bytes (XImage *ximage)
359 int i, j;
360 char *line = ximage->data;
362 for (j = ximage->height; j; j--) {
363 uint8_t *p = (uint8_t *) line;
364 for (i = ximage->width; i; i--) {
365 uint8_t tmp;
366 tmp = p[2];
367 p[2] = p[0];
368 p[0] = tmp;
369 p += 3;
372 line += ximage->bytes_per_line;
376 static void
377 _swap_ximage_4bytes (XImage *ximage)
379 int i, j;
380 char *line = ximage->data;
382 for (j = ximage->height; j; j--) {
383 uint32_t *p = (uint32_t *) line;
384 for (i = ximage->width; i; i--) {
385 *p = bswap_32 (*p);
386 p++;
389 line += ximage->bytes_per_line;
393 static void
394 _swap_ximage_nibbles (XImage *ximage)
396 int i, j;
397 char *line = ximage->data;
399 for (j = ximage->height; j; j--) {
400 uint8_t *p = (uint8_t *) line;
401 for (i = (ximage->width + 1) / 2; i; i--) {
402 *p = ((*p >> 4) & 0xf) | ((*p << 4) & ~0xf);
403 p++;
406 line += ximage->bytes_per_line;
410 static void
411 _swap_ximage_bits (XImage *ximage)
413 int i, j;
414 char *line = ximage->data;
415 int unit = ximage->bitmap_unit;
416 int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8;
418 for (j = ximage->height; j; j--) {
419 char *p = line;
421 for (i = line_bytes; i; i--) {
422 char b = *p;
423 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
424 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
425 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
426 *p = b;
428 p++;
431 line += ximage->bytes_per_line;
435 static void
436 _swap_ximage_to_native (XImage *ximage)
438 int unit_bytes = 0;
439 int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
441 if (ximage->bits_per_pixel == 1 &&
442 ximage->bitmap_bit_order != native_byte_order)
444 _swap_ximage_bits (ximage);
445 if (ximage->bitmap_bit_order == ximage->byte_order)
446 return;
449 if (ximage->byte_order == native_byte_order)
450 return;
452 switch (ximage->bits_per_pixel) {
453 case 1:
454 unit_bytes = ximage->bitmap_unit / 8;
455 break;
456 case 4:
457 _swap_ximage_nibbles (ximage);
458 /* fall-through */
459 case 8:
460 case 16:
461 case 20:
462 case 24:
463 case 28:
464 case 30:
465 case 32:
466 unit_bytes = (ximage->bits_per_pixel + 7) / 8;
467 break;
468 default:
469 /* This could be hit on some rare but possible cases. */
470 ASSERT_NOT_REACHED;
473 switch (unit_bytes) {
474 case 1:
475 break;
476 case 2:
477 _swap_ximage_2bytes (ximage);
478 break;
479 case 3:
480 _swap_ximage_3bytes (ximage);
481 break;
482 case 4:
483 _swap_ximage_4bytes (ximage);
484 break;
485 default:
486 ASSERT_NOT_REACHED;
491 /* Given a mask, (with a single sequence of contiguous 1 bits), return
492 * the number of 1 bits in 'width' and the number of 0 bits to its
493 * right in 'shift'. */
494 static void
495 _characterize_field (uint32_t mask, int *width, int *shift)
497 *width = _cairo_popcount (mask);
498 /* The final '& 31' is to force a 0 mask to result in 0 shift. */
499 *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
503 /* Convert a field of 'width' bits to 'new_width' bits with correct
504 * rounding. */
505 static inline uint32_t
506 _resize_field (uint32_t field, int width, int new_width)
508 if (width == 0)
509 return 0;
511 if (width >= new_width) {
512 return field >> (width - new_width);
513 } else {
514 uint32_t result = field << (new_width - width);
516 while (width < new_width) {
517 result |= result >> width;
518 width <<= 1;
520 return result;
524 static inline uint32_t
525 _adjust_field (uint32_t field, int adjustment)
527 return MIN (255, MAX(0, (int)field + adjustment));
530 /* Given a shifted field value, (described by 'width' and 'shift),
531 * resize it 8-bits and return that value.
533 * Note that the original field value must not have any non-field bits
534 * set.
536 static inline uint32_t
537 _field_to_8 (uint32_t field, int width, int shift)
539 return _resize_field (field >> shift, width, 8);
542 static inline uint32_t
543 _field_to_8_undither (uint32_t field, int width, int shift,
544 int dither_adjustment)
546 return _adjust_field (_field_to_8 (field, width, shift), - dither_adjustment>>width);
549 /* Given an 8-bit value, convert it to a field of 'width', shift it up
550 * to 'shift, and return it. */
551 static inline uint32_t
552 _field_from_8 (uint32_t field, int width, int shift)
554 return _resize_field (field, 8, width) << shift;
557 static inline uint32_t
558 _field_from_8_dither (uint32_t field, int width, int shift,
559 int8_t dither_adjustment)
561 return _field_from_8 (_adjust_field (field, dither_adjustment>>width), width, shift);
564 static inline uint32_t
565 _pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info,
566 uint32_t r, uint32_t g, uint32_t b,
567 int8_t dither_adjustment)
569 if (r == g && g == b) {
570 dither_adjustment /= RAMP_SIZE;
571 return visual_info->gray8_to_pseudocolor[_adjust_field (r, dither_adjustment)];
572 } else {
573 dither_adjustment = visual_info->dither8_to_cube[dither_adjustment+128];
574 return visual_info->cube_to_pseudocolor[visual_info->field8_to_cube[_adjust_field (r, dither_adjustment)]]
575 [visual_info->field8_to_cube[_adjust_field (g, dither_adjustment)]]
576 [visual_info->field8_to_cube[_adjust_field (b, dither_adjustment)]];
580 static inline uint32_t
581 _pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info,
582 uint32_t pixel)
584 uint32_t r, g, b;
585 pixel &= 0xff;
586 r = visual_info->colors[pixel].r;
587 g = visual_info->colors[pixel].g;
588 b = visual_info->colors[pixel].b;
589 return (r << 16) |
590 (g << 8) |
591 (b );
595 /* should range from -128 to 127 */
596 #define X 16
597 static const int8_t dither_pattern[4][4] = {
598 {-8*X, +0*X, -6*X, +2*X},
599 {+4*X, -4*X, +6*X, -2*X},
600 {-5*X, +4*X, -7*X, +1*X},
601 {+7*X, -1*X, +5*X, -3*X}
603 #undef X
606 static cairo_status_t
607 _get_image_surface (cairo_xlib_surface_t *surface,
608 cairo_rectangle_int_t *interest_rect,
609 cairo_image_surface_t **image_out,
610 cairo_rectangle_int_t *image_rect)
612 cairo_int_status_t status;
613 cairo_image_surface_t *image = NULL;
614 XImage *ximage;
615 cairo_rectangle_int_t extents;
616 pixman_format_code_t pixman_format;
617 cairo_format_masks_t xlib_masks;
619 extents.x = 0;
620 extents.y = 0;
621 extents.width = surface->width;
622 extents.height = surface->height;
624 if (interest_rect) {
625 if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
626 *image_out = NULL;
627 return CAIRO_STATUS_SUCCESS;
631 if (image_rect)
632 *image_rect = extents;
634 /* XXX: This should try to use the XShm extension if available */
636 if (surface->use_pixmap == 0)
638 cairo_xlib_error_func_t old_handler;
640 old_handler = XSetErrorHandler (_noop_error_handler);
642 ximage = XGetImage (surface->dpy,
643 surface->drawable,
644 extents.x, extents.y,
645 extents.width, extents.height,
646 AllPlanes, ZPixmap);
648 XSetErrorHandler (old_handler);
650 /* If we get an error, the surface must have been a window,
651 * so retry with the safe code path.
653 if (!ximage)
654 surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
656 else
658 surface->use_pixmap--;
659 ximage = NULL;
662 if (!ximage)
665 /* XGetImage from a window is dangerous because it can
666 * produce errors if the window is unmapped or partially
667 * outside the screen. We could check for errors and
668 * retry, but to keep things simple, we just create a
669 * temporary pixmap
671 Pixmap pixmap;
672 cairo_status_t status = _cairo_xlib_surface_ensure_gc (surface);
673 if (status)
674 return status;
676 pixmap = XCreatePixmap (surface->dpy,
677 surface->drawable,
678 extents.width, extents.height,
679 surface->depth);
680 if (pixmap) {
681 XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
682 extents.x, extents.y,
683 extents.width, extents.height,
684 0, 0);
686 ximage = XGetImage (surface->dpy,
687 pixmap,
688 0, 0,
689 extents.width, extents.height,
690 AllPlanes, ZPixmap);
692 XFreePixmap (surface->dpy, pixmap);
695 if (!ximage)
696 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
698 _swap_ximage_to_native (ximage);
700 xlib_masks.bpp = ximage->bits_per_pixel;
701 xlib_masks.alpha_mask = surface->a_mask;
702 xlib_masks.red_mask = surface->r_mask;
703 xlib_masks.green_mask = surface->g_mask;
704 xlib_masks.blue_mask = surface->b_mask;
706 if (_pixman_format_from_masks (&xlib_masks, &pixman_format) &&
707 xlib_masks.bpp >= 24 &&
708 ximage->bitmap_unit == 32 &&
709 ximage->bitmap_pad == 32)
711 image = (cairo_image_surface_t*)
712 _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
713 pixman_format,
714 ximage->width,
715 ximage->height,
716 ximage->bytes_per_line);
717 status = image->base.status;
718 if (status)
719 goto BAIL;
721 /* Let the surface take ownership of the data */
722 _cairo_image_surface_assume_ownership_of_data (image);
723 ximage->data = NULL;
724 } else {
725 /* The visual we are dealing with is not supported by the
726 * standard pixman formats. So we must first convert the data
727 * to a supported format. */
729 cairo_format_t format;
730 unsigned char *data;
731 uint32_t *row;
732 uint32_t in_pixel, out_pixel;
733 unsigned int rowstride;
734 uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0;
735 int a_width=0, r_width=0, g_width=0, b_width=0;
736 int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
737 int x, y, x0, y0, x_off, y_off;
738 cairo_xlib_visual_info_t *visual_info;
740 if (surface->visual == NULL || surface->visual->class == TrueColor) {
741 cairo_bool_t has_alpha;
742 cairo_bool_t has_color;
744 has_alpha = surface->a_mask;
745 has_color = (surface->r_mask ||
746 surface->g_mask ||
747 surface->b_mask);
749 if (has_color) {
750 if (has_alpha) {
751 format = CAIRO_FORMAT_ARGB32;
752 } else {
753 format = CAIRO_FORMAT_RGB24;
755 } else {
756 /* XXX: Using CAIRO_FORMAT_A8 here would be more
757 * efficient, but would require slightly different code in
758 * the image conversion to put the alpha channel values
759 * into the right place. */
760 format = CAIRO_FORMAT_ARGB32;
763 a_mask = surface->a_mask;
764 r_mask = surface->r_mask;
765 g_mask = surface->g_mask;
766 b_mask = surface->b_mask;
768 _characterize_field (a_mask, &a_width, &a_shift);
769 _characterize_field (r_mask, &r_width, &r_shift);
770 _characterize_field (g_mask, &g_width, &g_shift);
771 _characterize_field (b_mask, &b_width, &b_shift);
773 } else {
774 format = CAIRO_FORMAT_RGB24;
776 status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
777 surface->visual,
778 &visual_info);
779 if (status)
780 goto BAIL;
783 image = (cairo_image_surface_t *) cairo_image_surface_create
784 (format, ximage->width, ximage->height);
785 status = image->base.status;
786 if (status)
787 goto BAIL;
789 data = cairo_image_surface_get_data (&image->base);
790 rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
791 row = (uint32_t *) data;
792 x0 = extents.x + surface->base.device_transform.x0;
793 y0 = extents.y + surface->base.device_transform.y0;
794 for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
795 y < ximage->height;
796 y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
797 const int8_t *dither_row = dither_pattern[y_off];
798 for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
799 x < ximage->width;
800 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) {
801 int dither_adjustment = dither_row[x_off];
803 in_pixel = XGetPixel (ximage, x, y);
804 if (surface->visual == NULL || surface->visual->class == TrueColor) {
805 out_pixel = (
806 _field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
807 _field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
808 _field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 |
809 _field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment));
810 } else {
811 /* Undithering pseudocolor does not look better */
812 out_pixel = _pseudocolor_to_rgb888 (visual_info, in_pixel);
814 row[x] = out_pixel;
816 row += rowstride;
820 BAIL:
821 XDestroyImage (ximage);
823 if (status) {
824 if (image) {
825 cairo_surface_destroy (&image->base);
826 image = NULL;
829 *image_out = image;
830 return status;
833 static void
834 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface)
836 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 if (surface->have_clip_rects) {
873 XSetClipRectangles(surface->dpy, surface->gc,
874 0, 0,
875 surface->clip_rects,
876 surface->num_clip_rects, YXSorted);
877 } else
878 XSetClipMask (surface->dpy, surface->gc, None);
880 surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
883 static void
884 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface)
886 if (!surface->dst_picture) {
887 surface->dst_picture = XRenderCreatePicture (surface->dpy,
888 surface->drawable,
889 surface->xrender_format,
890 0, NULL);
891 _cairo_xlib_surface_set_picture_clip_rects (surface);
892 } else if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE)
893 _cairo_xlib_surface_set_picture_clip_rects (surface);
896 static cairo_status_t
897 _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
899 XGCValues gcv;
901 if (surface->gc == NULL) {
902 surface->gc = _cairo_xlib_screen_get_gc (surface->screen_info,
903 surface->depth);
904 if (surface->gc == NULL) {
905 gcv.graphics_exposures = False;
906 surface->gc = XCreateGC (surface->dpy, surface->drawable,
907 GCGraphicsExposures, &gcv);
908 if (!surface->gc)
909 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
912 _cairo_xlib_surface_set_gc_clip_rects (surface);
913 } else if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)
914 _cairo_xlib_surface_set_gc_clip_rects (surface);
916 return CAIRO_STATUS_SUCCESS;
919 static cairo_status_t
920 _draw_image_surface (cairo_xlib_surface_t *surface,
921 cairo_image_surface_t *image,
922 int src_x,
923 int src_y,
924 int width,
925 int height,
926 int dst_x,
927 int dst_y)
929 XImage ximage;
930 cairo_format_masks_t image_masks;
931 int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
932 cairo_status_t status;
933 cairo_bool_t own_data;
935 _pixman_format_to_masks (image->pixman_format, &image_masks);
937 ximage.width = image->width;
938 ximage.height = image->height;
939 ximage.format = ZPixmap;
940 ximage.byte_order = native_byte_order;
941 ximage.bitmap_unit = 32; /* always for libpixman */
942 ximage.bitmap_bit_order = native_byte_order;
943 ximage.bitmap_pad = 32; /* always for libpixman */
944 ximage.depth = surface->depth;
945 ximage.red_mask = surface->r_mask;
946 ximage.green_mask = surface->g_mask;
947 ximage.blue_mask = surface->b_mask;
948 ximage.xoffset = 0;
950 if (image_masks.red_mask == surface->r_mask &&
951 image_masks.green_mask == surface->g_mask &&
952 image_masks.blue_mask == surface->b_mask)
954 int ret;
956 ximage.bits_per_pixel = image_masks.bpp;
957 ximage.bytes_per_line = image->stride;
958 ximage.data = (char *)image->data;
959 own_data = FALSE;
961 ret = XInitImage (&ximage);
962 assert (ret != 0);
963 } else {
964 unsigned int stride, rowstride;
965 int x, y, x0, y0, x_off, y_off;
966 uint32_t in_pixel, out_pixel, *row;
967 int i_a_width=0, i_r_width=0, i_g_width=0, i_b_width=0;
968 int i_a_shift=0, i_r_shift=0, i_g_shift=0, i_b_shift=0;
969 int o_a_width=0, o_r_width=0, o_g_width=0, o_b_width=0;
970 int o_a_shift=0, o_r_shift=0, o_g_shift=0, o_b_shift=0;
971 cairo_xlib_visual_info_t *visual_info = NULL;
972 cairo_bool_t true_color;
973 int ret;
975 if (surface->depth > 16) {
976 ximage.bits_per_pixel = 32;
977 } else if (surface->depth > 8) {
978 ximage.bits_per_pixel = 16;
979 } else if (surface->depth > 1) {
980 ximage.bits_per_pixel = 8;
981 } else {
982 ximage.bits_per_pixel = 1;
984 stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width,
985 ximage.bits_per_pixel);
986 ximage.bytes_per_line = stride;
987 ximage.data = _cairo_malloc_ab (stride, ximage.height);
988 if (ximage.data == NULL)
989 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
991 own_data = TRUE;
993 ret = XInitImage (&ximage);
994 assert (ret != 0);
996 _characterize_field (image_masks.alpha_mask, &i_a_width, &i_a_shift);
997 _characterize_field (image_masks.red_mask , &i_r_width, &i_r_shift);
998 _characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift);
999 _characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift);
1001 true_color = surface->visual == NULL ||
1002 surface->visual->class == TrueColor;
1003 if (true_color) {
1004 _characterize_field (surface->a_mask, &o_a_width, &o_a_shift);
1005 _characterize_field (surface->r_mask, &o_r_width, &o_r_shift);
1006 _characterize_field (surface->g_mask, &o_g_width, &o_g_shift);
1007 _characterize_field (surface->b_mask, &o_b_width, &o_b_shift);
1008 } else {
1009 status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
1010 surface->visual,
1011 &visual_info);
1012 if (status)
1013 goto BAIL;
1016 rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
1017 row = (uint32_t *) cairo_image_surface_get_data (&image->base);
1018 x0 = dst_x + surface->base.device_transform.x0;
1019 y0 = dst_y + surface->base.device_transform.y0;
1020 for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
1021 y < ximage.height;
1022 y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern))
1024 const int8_t *dither_row = dither_pattern[y_off];
1026 for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
1027 x < ximage.width;
1028 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0]))
1030 int dither_adjustment = dither_row[x_off];
1031 int a, r, g, b;
1033 if (image_masks.bpp <= 8)
1034 in_pixel = ((uint8_t*)row)[x];
1035 else if (image_masks.bpp <= 16)
1036 in_pixel = ((uint16_t*)row)[x];
1037 else
1038 in_pixel = row[x];
1040 /* If the incoming image has no alpha channel, then the input
1041 * is opaque and the output should have the maximum alpha value.
1042 * For all other channels, their absence implies 0.
1044 if (image_masks.alpha_mask == 0x0)
1045 a = 0xff;
1046 else
1047 a = _field_to_8 (in_pixel & image_masks.alpha_mask, i_a_width, i_a_shift);
1048 r = _field_to_8 (in_pixel & image_masks.red_mask , i_r_width, i_r_shift);
1049 g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift);
1050 b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift);
1052 if (true_color) {
1053 out_pixel = _field_from_8 (a, o_a_width, o_a_shift) |
1054 _field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) |
1055 _field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) |
1056 _field_from_8_dither (b, o_b_width, o_b_shift, dither_adjustment);
1057 } else {
1058 out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment);
1061 XPutPixel (&ximage, x, y, out_pixel);
1064 row += rowstride;
1068 status = _cairo_xlib_surface_ensure_gc (surface);
1069 if (status)
1070 goto BAIL;
1072 XPutImage(surface->dpy, surface->drawable, surface->gc,
1073 &ximage, src_x, src_y, dst_x, dst_y,
1074 width, height);
1076 BAIL:
1077 if (own_data)
1078 free (ximage.data);
1080 return status;
1083 static cairo_status_t
1084 _cairo_xlib_surface_acquire_source_image (void *abstract_surface,
1085 cairo_image_surface_t **image_out,
1086 void **image_extra)
1088 cairo_xlib_surface_t *surface = abstract_surface;
1089 cairo_image_surface_t *image;
1090 cairo_status_t status;
1092 _cairo_xlib_display_notify (surface->display);
1094 status = _get_image_surface (surface, NULL, &image, NULL);
1095 if (status)
1096 return status;
1098 *image_out = image;
1099 *image_extra = NULL;
1101 return CAIRO_STATUS_SUCCESS;
1104 static void
1105 _cairo_xlib_surface_release_source_image (void *abstract_surface,
1106 cairo_image_surface_t *image,
1107 void *image_extra)
1109 cairo_surface_destroy (&image->base);
1112 static cairo_status_t
1113 _cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
1114 cairo_rectangle_int_t *interest_rect,
1115 cairo_image_surface_t **image_out,
1116 cairo_rectangle_int_t *image_rect_out,
1117 void **image_extra)
1119 cairo_xlib_surface_t *surface = abstract_surface;
1120 cairo_image_surface_t *image;
1121 cairo_status_t status;
1123 _cairo_xlib_display_notify (surface->display);
1125 status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
1126 if (status)
1127 return status;
1129 *image_out = image;
1130 *image_extra = NULL;
1132 return CAIRO_STATUS_SUCCESS;
1135 static void
1136 _cairo_xlib_surface_release_dest_image (void *abstract_surface,
1137 cairo_rectangle_int_t *interest_rect,
1138 cairo_image_surface_t *image,
1139 cairo_rectangle_int_t *image_rect,
1140 void *image_extra)
1142 cairo_xlib_surface_t *surface = abstract_surface;
1143 cairo_status_t status;
1145 status = _draw_image_surface (surface, image,
1146 0, 0, image->width, image->height,
1147 image_rect->x, image_rect->y);
1148 status = _cairo_surface_set_error (&surface->base, status);
1150 cairo_surface_destroy (&image->base);
1154 * Return whether two xlib surfaces share the same
1155 * screen. Both core and Render drawing require this
1156 * when using multiple drawables in an operation.
1158 static cairo_bool_t
1159 _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
1160 cairo_xlib_surface_t *src)
1162 return dst->dpy == src->dpy && dst->screen == src->screen;
1165 static cairo_status_t
1166 _cairo_xlib_surface_clone_similar (void *abstract_surface,
1167 cairo_surface_t *src,
1168 int src_x,
1169 int src_y,
1170 int width,
1171 int height,
1172 int *clone_offset_x,
1173 int *clone_offset_y,
1174 cairo_surface_t **clone_out)
1176 cairo_xlib_surface_t *surface = abstract_surface;
1177 cairo_xlib_surface_t *clone;
1178 cairo_status_t status;
1180 _cairo_xlib_display_notify (surface->display);
1182 if (src->backend == surface->base.backend ) {
1183 cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
1185 if (_cairo_xlib_surface_same_screen (surface, xlib_src)) {
1186 *clone_offset_x = 0;
1187 *clone_offset_y = 0;
1188 *clone_out = cairo_surface_reference (src);
1190 return CAIRO_STATUS_SUCCESS;
1192 } else if (_cairo_surface_is_image (src)) {
1193 cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
1195 if (! CAIRO_FORMAT_VALID (image_src->format))
1196 return CAIRO_INT_STATUS_UNSUPPORTED;
1198 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1199 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1201 clone = (cairo_xlib_surface_t *)
1202 _cairo_xlib_surface_create_similar_with_format (surface,
1203 image_src->format,
1204 width, height);
1205 if (clone == NULL)
1206 return CAIRO_INT_STATUS_UNSUPPORTED;
1208 if (clone->base.status)
1209 return clone->base.status;
1211 status = _draw_image_surface (clone, image_src,
1212 src_x, src_y,
1213 width, height,
1214 0, 0);
1215 if (status) {
1216 cairo_surface_destroy (&clone->base);
1217 return status;
1220 *clone_offset_x = src_x;
1221 *clone_offset_y = src_y;
1222 *clone_out = &clone->base;
1224 return CAIRO_STATUS_SUCCESS;
1227 return CAIRO_INT_STATUS_UNSUPPORTED;
1230 static cairo_surface_t *
1231 _cairo_xlib_surface_create_solid_pattern_surface (void *abstract_surface,
1232 cairo_solid_pattern_t *solid_pattern)
1234 /* This function's only responsibility is to create a proper surface
1235 * for when XRender is not available. The proper surface is a xlib
1236 * surface (as opposed to image surface which is what create_similar
1237 * returns in those cases) and the size of the dithering pattern, not
1238 * 1x1. This surface can then be used in
1239 * _cairo_xlib_surface_solid_fill_rectangles() to do dithered "solid"
1240 * fills using core protocol */
1242 cairo_xlib_surface_t *other = abstract_surface;
1243 cairo_image_surface_t *image;
1244 cairo_xlib_surface_t *surface = NULL;
1245 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1247 int width = ARRAY_LENGTH (dither_pattern[0]);
1248 int height = ARRAY_LENGTH (dither_pattern);
1250 Pixmap pixmap = None;
1252 if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
1253 return NULL;
1255 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1256 return NULL;
1258 image = (cairo_image_surface_t *)
1259 _cairo_image_surface_create_with_content (solid_pattern->content,
1260 width, height);
1261 status = image->base.status;
1262 if (status)
1263 goto BAIL;
1265 pixmap = XCreatePixmap (other->dpy,
1266 other->drawable,
1267 width, height,
1268 other->depth);
1270 surface = (cairo_xlib_surface_t *)
1271 _cairo_xlib_surface_create_internal (other->dpy,
1272 pixmap,
1273 other->screen, other->visual,
1274 other->xrender_format,
1275 width, height,
1276 other->depth);
1277 status = surface->base.status;
1278 if (status)
1279 goto BAIL;
1281 status = _cairo_surface_paint (&image->base,
1282 CAIRO_OPERATOR_SOURCE,
1283 &solid_pattern->base);
1284 if (status)
1285 goto BAIL;
1287 status = _draw_image_surface (surface, image,
1288 0, 0,
1289 width, height,
1290 0, 0);
1291 if (status)
1292 goto BAIL;
1294 BAIL:
1295 cairo_surface_destroy (&image->base);
1297 if (status) {
1298 if (pixmap != None)
1299 XFreePixmap (other->dpy, pixmap);
1300 cairo_surface_destroy (&surface->base);
1302 return _cairo_surface_create_in_error (status);
1305 surface->owns_pixmap = TRUE;
1306 return &surface->base;
1309 static cairo_status_t
1310 _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
1311 cairo_matrix_t *matrix)
1313 XTransform xtransform;
1315 if (!surface->src_picture)
1316 return CAIRO_STATUS_SUCCESS;
1318 /* Casting between pixman_transform_t and XTransform is safe because
1319 * they happen to be the exact same type.
1321 _cairo_matrix_to_pixman_matrix (matrix, (pixman_transform_t *)&xtransform);
1323 if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
1324 return CAIRO_STATUS_SUCCESS;
1326 if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
1327 return CAIRO_INT_STATUS_UNSUPPORTED;
1329 XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
1330 surface->xtransform = xtransform;
1332 return CAIRO_STATUS_SUCCESS;
1335 static cairo_status_t
1336 _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
1337 cairo_filter_t filter)
1339 const char *render_filter;
1341 if (!surface->src_picture)
1342 return CAIRO_STATUS_SUCCESS;
1344 if (surface->filter == filter)
1345 return CAIRO_STATUS_SUCCESS;
1347 if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
1349 if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
1350 return CAIRO_STATUS_SUCCESS;
1352 return CAIRO_INT_STATUS_UNSUPPORTED;
1355 switch (filter) {
1356 case CAIRO_FILTER_FAST:
1357 render_filter = FilterFast;
1358 break;
1359 case CAIRO_FILTER_GOOD:
1360 render_filter = FilterGood;
1361 break;
1362 case CAIRO_FILTER_BEST:
1363 render_filter = FilterBest;
1364 break;
1365 case CAIRO_FILTER_NEAREST:
1366 render_filter = FilterNearest;
1367 break;
1368 case CAIRO_FILTER_BILINEAR:
1369 render_filter = FilterBilinear;
1370 break;
1371 case CAIRO_FILTER_GAUSSIAN:
1372 /* XXX: The GAUSSIAN value has no implementation in cairo
1373 * whatsoever, so it was really a mistake to have it in the
1374 * API. We could fix this by officially deprecating it, or
1375 * else inventing semantics and providing an actual
1376 * implementation for it. */
1377 default:
1378 render_filter = FilterBest;
1379 break;
1382 XRenderSetPictureFilter (surface->dpy, surface->src_picture,
1383 (char *) render_filter, NULL, 0);
1384 surface->filter = filter;
1386 return CAIRO_STATUS_SUCCESS;
1389 static void
1390 _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
1392 XRenderPictureAttributes pa;
1393 unsigned long mask;
1395 if (!surface->src_picture)
1396 return;
1398 if (surface->repeat == repeat)
1399 return;
1401 mask = CPRepeat;
1402 pa.repeat = repeat;
1404 XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
1405 surface->repeat = repeat;
1408 static cairo_int_status_t
1409 _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
1410 cairo_surface_attributes_t *attributes)
1412 cairo_int_status_t status;
1414 _cairo_xlib_surface_ensure_src_picture (surface);
1416 status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
1417 if (status)
1418 return status;
1420 switch (attributes->extend) {
1421 case CAIRO_EXTEND_NONE:
1422 _cairo_xlib_surface_set_repeat (surface, RepeatNone);
1423 break;
1424 case CAIRO_EXTEND_REPEAT:
1425 _cairo_xlib_surface_set_repeat (surface, RepeatNormal);
1426 break;
1427 case CAIRO_EXTEND_REFLECT:
1428 case CAIRO_EXTEND_PAD:
1429 default:
1430 return CAIRO_INT_STATUS_UNSUPPORTED;
1433 status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
1434 if (status)
1435 return status;
1437 return CAIRO_STATUS_SUCCESS;
1440 /* Checks whether we can can directly draw from src to dst with
1441 * the core protocol: either with CopyArea or using src as a
1442 * a tile in a GC.
1444 static cairo_bool_t
1445 _surfaces_compatible (cairo_xlib_surface_t *dst,
1446 cairo_xlib_surface_t *src)
1448 /* same screen */
1449 if (!_cairo_xlib_surface_same_screen (dst, src))
1450 return FALSE;
1452 /* same depth (for core) */
1453 if (src->depth != dst->depth)
1454 return FALSE;
1456 /* if Render is supported, match picture formats */
1457 if (src->xrender_format != dst->xrender_format)
1458 return FALSE;
1459 else if (src->xrender_format != NULL)
1460 return TRUE;
1462 /* Without Render, match visuals instead */
1463 if (src->visual == dst->visual)
1464 return TRUE;
1466 return FALSE;
1469 static cairo_bool_t
1470 _surface_has_alpha (cairo_xlib_surface_t *surface)
1472 if (surface->xrender_format) {
1473 if (surface->xrender_format->type == PictTypeDirect &&
1474 surface->xrender_format->direct.alphaMask != 0)
1475 return TRUE;
1476 else
1477 return FALSE;
1478 } else {
1480 /* In the no-render case, we never have alpha */
1481 return FALSE;
1485 /* Returns true if the given operator and source-alpha combination
1486 * requires alpha compositing to complete.
1488 static cairo_bool_t
1489 _operator_needs_alpha_composite (cairo_operator_t op,
1490 cairo_bool_t surface_has_alpha)
1492 if (op == CAIRO_OPERATOR_SOURCE ||
1493 (!surface_has_alpha &&
1494 (op == CAIRO_OPERATOR_OVER ||
1495 op == CAIRO_OPERATOR_ATOP ||
1496 op == CAIRO_OPERATOR_IN)))
1497 return FALSE;
1499 return TRUE;
1502 /* There is a bug in most older X servers with compositing using a
1503 * untransformed repeating source pattern when the source is in off-screen
1504 * video memory, and another with repeated transformed images using a
1505 * general transform matrix. When these bugs could be triggered, we need a
1506 * fallback: in the common case where we have no transformation and the
1507 * source and destination have the same format/visual, we can do the
1508 * operation using the core protocol for the first bug, otherwise, we need
1509 * a software fallback.
1511 * We can also often optimize a compositing operation by calling XCopyArea
1512 * for some common cases where there is no alpha compositing to be done.
1513 * We figure that out here as well.
1515 typedef enum {
1516 DO_RENDER, /* use render */
1517 DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
1518 DO_XTILE, /* core protocol XSetTile optimization/fallback */
1519 DO_UNSUPPORTED /* software fallback */
1520 } composite_operation_t;
1522 /* Initial check for the render bugs; we need to recheck for the
1523 * offscreen-memory bug after we turn patterns into surfaces, since that
1524 * may introduce a repeating pattern for gradient patterns. We don't need
1525 * to check for the repeat+transform bug because gradient surfaces aren't
1526 * transformed.
1528 * All we do here is reject cases where we *know* are going to
1529 * hit the bug and won't be able to use a core protocol fallback.
1531 static composite_operation_t
1532 _categorize_composite_operation (cairo_xlib_surface_t *dst,
1533 cairo_operator_t op,
1534 cairo_pattern_t *src_pattern,
1535 cairo_bool_t have_mask)
1538 if (!dst->buggy_repeat)
1539 return DO_RENDER;
1541 if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
1543 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
1545 if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
1546 src_pattern->extend == CAIRO_EXTEND_REPEAT)
1548 /* This is the case where we have the bug involving
1549 * untransformed repeating source patterns with off-screen
1550 * video memory; reject some cases where a core protocol
1551 * fallback is impossible.
1553 if (have_mask ||
1554 !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
1555 return DO_UNSUPPORTED;
1557 if (_cairo_surface_is_xlib (surface_pattern->surface)) {
1558 cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)surface_pattern->surface;
1560 if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
1561 return DO_UNSUPPORTED;
1563 /* If these are on the same screen but otherwise incompatible,
1564 * make a copy as core drawing can't cross depths and doesn't
1565 * work right across visuals of the same depth
1567 if (_cairo_xlib_surface_same_screen (dst, src) &&
1568 !_surfaces_compatible (dst, src))
1569 return DO_UNSUPPORTED;
1573 /* Check for the other bug involving repeat patterns with general
1574 * transforms. */
1575 if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
1576 src_pattern->extend == CAIRO_EXTEND_REPEAT)
1577 return DO_UNSUPPORTED;
1580 return DO_RENDER;
1583 /* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
1584 * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
1585 * did to turn gradients into a pattern, but most of the time we can handle
1586 * that case with core protocol fallback.
1588 * Also check here if we can just use XCopyArea, instead of going through
1589 * Render.
1591 static composite_operation_t
1592 _recategorize_composite_operation (cairo_xlib_surface_t *dst,
1593 cairo_operator_t op,
1594 cairo_xlib_surface_t *src,
1595 cairo_surface_attributes_t *src_attr,
1596 cairo_bool_t have_mask)
1598 cairo_bool_t is_integer_translation =
1599 _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
1600 cairo_bool_t needs_alpha_composite;
1602 if (! _cairo_surface_is_xlib (&src->base))
1603 return DO_UNSUPPORTED;
1605 needs_alpha_composite =
1606 _operator_needs_alpha_composite (op, _surface_has_alpha (src));
1608 if (! have_mask &&
1609 is_integer_translation &&
1610 src_attr->extend == CAIRO_EXTEND_NONE &&
1611 ! needs_alpha_composite &&
1612 _surfaces_compatible (src, dst))
1614 return DO_XCOPYAREA;
1617 if (dst->buggy_repeat &&
1618 is_integer_translation &&
1619 src_attr->extend == CAIRO_EXTEND_REPEAT &&
1620 (src->width != 1 || src->height != 1))
1622 if (! have_mask &&
1623 ! needs_alpha_composite &&
1624 _surfaces_compatible (dst, src))
1626 return DO_XTILE;
1629 return DO_UNSUPPORTED;
1632 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
1633 return DO_UNSUPPORTED;
1635 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
1636 return DO_UNSUPPORTED;
1638 return DO_RENDER;
1641 static int
1642 _render_operator (cairo_operator_t op)
1644 switch (op) {
1645 case CAIRO_OPERATOR_CLEAR:
1646 return PictOpClear;
1648 case CAIRO_OPERATOR_SOURCE:
1649 return PictOpSrc;
1650 case CAIRO_OPERATOR_OVER:
1651 return PictOpOver;
1652 case CAIRO_OPERATOR_IN:
1653 return PictOpIn;
1654 case CAIRO_OPERATOR_OUT:
1655 return PictOpOut;
1656 case CAIRO_OPERATOR_ATOP:
1657 return PictOpAtop;
1659 case CAIRO_OPERATOR_DEST:
1660 return PictOpDst;
1661 case CAIRO_OPERATOR_DEST_OVER:
1662 return PictOpOverReverse;
1663 case CAIRO_OPERATOR_DEST_IN:
1664 return PictOpInReverse;
1665 case CAIRO_OPERATOR_DEST_OUT:
1666 return PictOpOutReverse;
1667 case CAIRO_OPERATOR_DEST_ATOP:
1668 return PictOpAtopReverse;
1670 case CAIRO_OPERATOR_XOR:
1671 return PictOpXor;
1672 case CAIRO_OPERATOR_ADD:
1673 return PictOpAdd;
1674 case CAIRO_OPERATOR_SATURATE:
1675 return PictOpSaturate;
1676 default:
1677 return PictOpOver;
1681 static cairo_int_status_t
1682 _cairo_xlib_surface_composite (cairo_operator_t op,
1683 cairo_pattern_t *src_pattern,
1684 cairo_pattern_t *mask_pattern,
1685 void *abstract_dst,
1686 int src_x,
1687 int src_y,
1688 int mask_x,
1689 int mask_y,
1690 int dst_x,
1691 int dst_y,
1692 unsigned int width,
1693 unsigned int height)
1695 cairo_surface_attributes_t src_attr, mask_attr;
1696 cairo_xlib_surface_t *dst = abstract_dst;
1697 cairo_xlib_surface_t *src;
1698 cairo_xlib_surface_t *mask;
1699 cairo_int_status_t status;
1700 composite_operation_t operation;
1701 int itx, ity;
1702 cairo_bool_t is_integer_translation;
1704 _cairo_xlib_display_notify (dst->display);
1706 operation = _categorize_composite_operation (dst, op, src_pattern,
1707 mask_pattern != NULL);
1708 if (operation == DO_UNSUPPORTED)
1709 return CAIRO_INT_STATUS_UNSUPPORTED;
1711 status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
1712 &dst->base,
1713 src_x, src_y,
1714 mask_x, mask_y,
1715 width, height,
1716 (cairo_surface_t **) &src,
1717 (cairo_surface_t **) &mask,
1718 &src_attr, &mask_attr);
1719 if (status)
1720 return status;
1722 /* check for fallback surfaces that we cannot handle ... */
1723 if (!_cairo_surface_is_xlib (&src->base)) {
1724 status = CAIRO_INT_STATUS_UNSUPPORTED;
1725 goto BAIL;
1727 if (mask != NULL &&
1728 (! _cairo_surface_is_xlib (&mask->base) ||
1729 ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)))
1731 status = CAIRO_INT_STATUS_UNSUPPORTED;
1732 goto BAIL;
1735 operation = _recategorize_composite_operation (dst, op, src, &src_attr,
1736 mask_pattern != NULL);
1737 if (operation == DO_UNSUPPORTED) {
1738 status = CAIRO_INT_STATUS_UNSUPPORTED;
1739 goto BAIL;
1742 switch (operation)
1744 case DO_RENDER:
1745 status = _cairo_xlib_surface_set_attributes (src, &src_attr);
1746 if (status)
1747 goto BAIL;
1749 _cairo_xlib_surface_ensure_dst_picture (dst);
1750 if (mask) {
1751 status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
1752 if (status)
1753 goto BAIL;
1755 XRenderComposite (dst->dpy,
1756 _render_operator (op),
1757 src->src_picture,
1758 mask->src_picture,
1759 dst->dst_picture,
1760 src_x + src_attr.x_offset,
1761 src_y + src_attr.y_offset,
1762 mask_x + mask_attr.x_offset,
1763 mask_y + mask_attr.y_offset,
1764 dst_x, dst_y,
1765 width, height);
1766 } else {
1767 XRenderComposite (dst->dpy,
1768 _render_operator (op),
1769 src->src_picture,
1771 dst->dst_picture,
1772 src_x + src_attr.x_offset,
1773 src_y + src_attr.y_offset,
1774 0, 0,
1775 dst_x, dst_y,
1776 width, height);
1779 break;
1781 case DO_XCOPYAREA:
1782 status = _cairo_xlib_surface_ensure_gc (dst);
1783 if (status)
1784 goto BAIL;
1786 is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
1787 &itx, &ity);
1788 /* This is a pre-condition for DO_XCOPYAREA. */
1789 assert (is_integer_translation);
1791 XCopyArea (dst->dpy,
1792 src->drawable,
1793 dst->drawable,
1794 dst->gc,
1795 src_x + src_attr.x_offset + itx,
1796 src_y + src_attr.y_offset + ity,
1797 width, height,
1798 dst_x, dst_y);
1799 break;
1801 case DO_XTILE:
1802 /* This case is only used for bug fallbacks, though we also use it for
1803 * the case where we don't have the RENDER extension, by forcing
1804 * buggy_repeat to TRUE.
1806 * We've checked that we have a repeating unscaled source in
1807 * _recategorize_composite_operation.
1810 status = _cairo_xlib_surface_ensure_gc (dst);
1811 if (status)
1812 goto BAIL;
1813 is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
1814 &itx, &ity);
1815 /* This is a pre-condition for DO_XTILE. */
1816 assert (is_integer_translation);
1818 XSetTSOrigin (dst->dpy, dst->gc,
1819 - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
1820 XSetTile (dst->dpy, dst->gc, src->drawable);
1821 XSetFillStyle (dst->dpy, dst->gc, FillTiled);
1823 XFillRectangle (dst->dpy, dst->drawable, dst->gc,
1824 dst_x, dst_y, width, height);
1825 break;
1827 case DO_UNSUPPORTED:
1828 default:
1829 ASSERT_NOT_REACHED;
1832 if (!_cairo_operator_bounded_by_source (op))
1833 status = _cairo_surface_composite_fixup_unbounded (&dst->base,
1834 &src_attr, src->width, src->height,
1835 mask ? &mask_attr : NULL,
1836 mask ? mask->width : 0,
1837 mask ? mask->height : 0,
1838 src_x, src_y,
1839 mask_x, mask_y,
1840 dst_x, dst_y, width, height);
1842 BAIL:
1843 if (mask)
1844 _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
1846 _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
1848 return status;
1851 static cairo_int_status_t
1852 _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
1853 const cairo_color_t *color,
1854 cairo_rectangle_int_t *rects,
1855 int num_rects)
1857 cairo_status_t status;
1858 cairo_solid_pattern_t solid;
1859 cairo_surface_t *solid_surface = NULL;
1860 cairo_surface_attributes_t attrs;
1861 int i;
1863 _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR);
1865 status = _cairo_xlib_surface_ensure_gc (surface);
1866 if (status)
1867 return status;
1869 status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
1870 0, 0,
1871 ARRAY_LENGTH (dither_pattern[0]),
1872 ARRAY_LENGTH (dither_pattern),
1873 &solid_surface,
1874 &attrs);
1875 if (status)
1876 return status;
1878 if (! _cairo_surface_is_xlib (solid_surface)) {
1879 status = CAIRO_INT_STATUS_UNSUPPORTED;
1880 goto BAIL;
1883 XSetTSOrigin (surface->dpy, surface->gc,
1884 - (surface->base.device_transform.x0 + attrs.x_offset),
1885 - (surface->base.device_transform.y0 + attrs.y_offset));
1886 XSetTile (surface->dpy, surface->gc,
1887 ((cairo_xlib_surface_t *) solid_surface)->drawable);
1888 XSetFillStyle (surface->dpy, surface->gc, FillTiled);
1890 for (i = 0; i < num_rects; i++) {
1891 XFillRectangle (surface->dpy, surface->drawable, surface->gc,
1892 rects[i].x, rects[i].y,
1893 rects[i].width, rects[i].height);
1896 BAIL:
1897 _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
1899 return status;
1902 static cairo_int_status_t
1903 _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
1904 cairo_operator_t op,
1905 const cairo_color_t *color,
1906 cairo_rectangle_int_t *rects,
1907 int num_rects)
1909 cairo_xlib_surface_t *surface = abstract_surface;
1910 XRenderColor render_color;
1911 XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
1912 XRectangle *xrects = static_xrects;
1913 int i;
1915 _cairo_xlib_display_notify (surface->display);
1917 if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
1918 if (op == CAIRO_OPERATOR_CLEAR ||
1919 ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
1920 CAIRO_COLOR_IS_OPAQUE (color)))
1922 return _cairo_xlib_surface_solid_fill_rectangles (surface, color,
1923 rects, num_rects);
1926 return CAIRO_INT_STATUS_UNSUPPORTED;
1929 render_color.red = color->red_short;
1930 render_color.green = color->green_short;
1931 render_color.blue = color->blue_short;
1932 render_color.alpha = color->alpha_short;
1934 if (num_rects > ARRAY_LENGTH (static_xrects)) {
1935 xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
1936 if (xrects == NULL)
1937 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1940 for (i = 0; i < num_rects; i++) {
1941 xrects[i].x = rects[i].x;
1942 xrects[i].y = rects[i].y;
1943 xrects[i].width = rects[i].width;
1944 xrects[i].height = rects[i].height;
1947 _cairo_xlib_surface_ensure_dst_picture (surface);
1948 XRenderFillRectangles (surface->dpy,
1949 _render_operator (op),
1950 surface->dst_picture,
1951 &render_color, xrects, num_rects);
1953 if (xrects != static_xrects)
1954 free (xrects);
1956 return CAIRO_STATUS_SUCCESS;
1959 /* Creates an A8 picture of size @width x @height, initialized with @color
1961 static Picture
1962 _create_a8_picture (cairo_xlib_surface_t *surface,
1963 XRenderColor *color,
1964 int width,
1965 int height,
1966 cairo_bool_t repeat)
1968 XRenderPictureAttributes pa;
1969 unsigned long mask = 0;
1971 Pixmap pixmap;
1972 Picture picture;
1973 XRenderPictFormat *xrender_format;
1975 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1976 return None;
1978 xrender_format =
1979 _cairo_xlib_display_get_xrender_format (surface->display,
1980 CAIRO_FORMAT_A8);
1981 if (xrender_format == NULL)
1982 return None;
1984 pixmap = XCreatePixmap (surface->dpy, surface->drawable,
1985 width <= 0 ? 1 : width,
1986 height <= 0 ? 1 : height,
1989 if (repeat) {
1990 pa.repeat = TRUE;
1991 mask = CPRepeat;
1994 picture = XRenderCreatePicture (surface->dpy, pixmap,
1995 xrender_format, mask, &pa);
1996 XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color,
1997 0, 0, width, height);
1998 XFreePixmap (surface->dpy, pixmap);
2000 return picture;
2003 /* Creates a temporary mask for the trapezoids covering the area
2004 * [@dst_x, @dst_y, @width, @height] of the destination surface.
2006 static Picture
2007 _create_trapezoid_mask (cairo_xlib_surface_t *dst,
2008 cairo_trapezoid_t *traps,
2009 int num_traps,
2010 int dst_x,
2011 int dst_y,
2012 int width,
2013 int height,
2014 XRenderPictFormat *pict_format)
2016 XRenderColor transparent = { 0, 0, 0, 0 };
2017 XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff };
2018 Picture mask_picture, solid_picture;
2019 XTrapezoid *offset_traps;
2020 int i;
2022 /* This would be considerably simpler using XRenderAddTraps(), but since
2023 * we are only using this in the unbounded-operator case, we stick with
2024 * XRenderCompositeTrapezoids, which is available on older versions
2025 * of RENDER rather than conditionalizing. We should still hit an
2026 * optimization that avoids creating another intermediate surface on
2027 * the servers that have XRenderAddTraps().
2029 mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
2030 if (mask_picture == None || num_traps == 0)
2031 return mask_picture;
2033 offset_traps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
2034 if (!offset_traps) {
2035 XRenderFreePicture (dst->dpy, mask_picture);
2036 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2037 return None;
2040 for (i = 0; i < num_traps; i++) {
2041 offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
2042 offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
2043 offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
2044 offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
2045 offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
2046 offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
2047 offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
2048 offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
2049 offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
2050 offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
2053 solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
2054 if (solid_picture == None) {
2055 XRenderFreePicture (dst->dpy, mask_picture);
2056 free (offset_traps);
2057 return None;
2060 XRenderCompositeTrapezoids (dst->dpy, PictOpAdd,
2061 solid_picture, mask_picture,
2062 pict_format,
2063 0, 0,
2064 offset_traps, num_traps);
2066 XRenderFreePicture (dst->dpy, solid_picture);
2067 free (offset_traps);
2069 return mask_picture;
2072 static cairo_int_status_t
2073 _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
2074 cairo_pattern_t *pattern,
2075 void *abstract_dst,
2076 cairo_antialias_t antialias,
2077 int src_x,
2078 int src_y,
2079 int dst_x,
2080 int dst_y,
2081 unsigned int width,
2082 unsigned int height,
2083 cairo_trapezoid_t *traps,
2084 int num_traps)
2086 cairo_surface_attributes_t attributes;
2087 cairo_xlib_surface_t *dst = abstract_dst;
2088 cairo_xlib_surface_t *src;
2089 cairo_int_status_t status;
2090 composite_operation_t operation;
2091 int render_reference_x, render_reference_y;
2092 int render_src_x, render_src_y;
2093 XRenderPictFormat *pict_format;
2095 _cairo_xlib_display_notify (dst->display);
2097 if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
2098 return CAIRO_INT_STATUS_UNSUPPORTED;
2100 operation = _categorize_composite_operation (dst, op, pattern, TRUE);
2101 if (operation == DO_UNSUPPORTED)
2102 return CAIRO_INT_STATUS_UNSUPPORTED;
2104 status = _cairo_pattern_acquire_surface (pattern, &dst->base,
2105 src_x, src_y, width, height,
2106 (cairo_surface_t **) &src,
2107 &attributes);
2108 if (status)
2109 return status;
2111 operation = _recategorize_composite_operation (dst, op, src,
2112 &attributes, TRUE);
2113 if (operation == DO_UNSUPPORTED) {
2114 status = CAIRO_INT_STATUS_UNSUPPORTED;
2115 goto BAIL;
2118 switch (antialias) {
2119 case CAIRO_ANTIALIAS_NONE:
2120 pict_format =
2121 _cairo_xlib_display_get_xrender_format (dst->display,
2122 CAIRO_FORMAT_A1);
2123 break;
2124 case CAIRO_ANTIALIAS_GRAY:
2125 case CAIRO_ANTIALIAS_SUBPIXEL:
2126 case CAIRO_ANTIALIAS_DEFAULT:
2127 default:
2128 pict_format =
2129 _cairo_xlib_display_get_xrender_format (dst->display,
2130 CAIRO_FORMAT_A8);
2131 break;
2134 if (traps[0].left.p1.y < traps[0].left.p2.y) {
2135 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
2136 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
2137 } else {
2138 render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
2139 render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
2142 render_src_x = src_x + render_reference_x - dst_x;
2143 render_src_y = src_y + render_reference_y - dst_y;
2145 _cairo_xlib_surface_ensure_dst_picture (dst);
2146 status = _cairo_xlib_surface_set_attributes (src, &attributes);
2147 if (status)
2148 goto BAIL;
2150 if (!_cairo_operator_bounded_by_mask (op)) {
2151 /* XRenderCompositeTrapezoids() creates a mask only large enough for the
2152 * trapezoids themselves, but if the operator is unbounded, then we need
2153 * to actually composite all the way out to the bounds, so we create
2154 * the mask and composite ourselves. There actually would
2155 * be benefit to doing this in all cases, since RENDER implementations
2156 * will frequently create a too temporary big mask, ignoring destination
2157 * bounds and clip. (XRenderAddTraps() could be used to make creating
2158 * the mask somewhat cheaper.)
2160 Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps,
2161 dst_x, dst_y, width, height,
2162 pict_format);
2163 if (!mask_picture) {
2164 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2165 goto BAIL;
2168 XRenderComposite (dst->dpy,
2169 _render_operator (op),
2170 src->src_picture,
2171 mask_picture,
2172 dst->dst_picture,
2173 src_x + attributes.x_offset,
2174 src_y + attributes.y_offset,
2175 0, 0,
2176 dst_x, dst_y,
2177 width, height);
2179 XRenderFreePicture (dst->dpy, mask_picture);
2181 status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
2182 &attributes, src->width, src->height,
2183 width, height,
2184 src_x, src_y,
2185 0, 0,
2186 dst_x, dst_y, width, height);
2188 } else {
2189 XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
2190 XTrapezoid *xtraps = xtraps_stack;
2191 int i;
2193 if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
2194 xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
2195 if (xtraps == NULL) {
2196 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2197 goto BAIL;
2201 for (i = 0; i < num_traps; i++) {
2202 xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
2203 xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
2204 xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
2205 xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
2206 xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
2207 xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
2208 xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
2209 xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
2210 xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
2211 xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
2214 XRenderCompositeTrapezoids (dst->dpy,
2215 _render_operator (op),
2216 src->src_picture, dst->dst_picture,
2217 pict_format,
2218 render_src_x + attributes.x_offset,
2219 render_src_y + attributes.y_offset,
2220 xtraps, num_traps);
2222 if (xtraps != xtraps_stack)
2223 free(xtraps);
2226 BAIL:
2227 _cairo_pattern_release_surface (pattern, &src->base, &attributes);
2229 return status;
2232 static cairo_int_status_t
2233 _cairo_xlib_surface_set_clip_region (void *abstract_surface,
2234 cairo_region_t *region)
2236 cairo_xlib_surface_t *surface = abstract_surface;
2237 cairo_bool_t had_clip_rects = surface->have_clip_rects;
2239 if (had_clip_rects == FALSE && region == NULL)
2240 return CAIRO_STATUS_SUCCESS;
2242 if (surface->clip_rects != surface->embedded_clip_rects) {
2243 free (surface->clip_rects);
2244 surface->clip_rects = surface->embedded_clip_rects;
2247 surface->have_clip_rects = FALSE;
2248 surface->num_clip_rects = 0;
2250 if (region != NULL) {
2251 cairo_box_int_t *boxes;
2252 cairo_status_t status;
2253 XRectangle *rects = NULL;
2254 int n_boxes, i;
2255 cairo_rectangle_int_t rect;
2256 cairo_region_t bound, bounded;
2258 rect.x = rect.y = 0;
2259 rect.width = surface->width;
2260 rect.height = surface->height;
2262 /* Intersect the region with the bounds of the surface. This
2263 * is necessary so we don't wrap around when we convert cairo's
2264 * 32 bit region into 16 bit rectangles.
2266 _cairo_region_init_rect (&bound, &rect);
2267 _cairo_region_init (&bounded);
2268 status = _cairo_region_intersect (&bounded, &bound, region);
2269 if (status) {
2270 _cairo_region_fini (&bound);
2271 _cairo_region_fini (&bounded);
2272 return status;
2275 status = _cairo_region_get_boxes (&bounded, &n_boxes, &boxes);
2276 if (status) {
2277 _cairo_region_fini (&bound);
2278 _cairo_region_fini (&bounded);
2279 return status;
2282 if (n_boxes > ARRAY_LENGTH (surface->embedded_clip_rects)) {
2283 rects = _cairo_malloc_ab (n_boxes, sizeof (XRectangle));
2284 if (rects == NULL) {
2285 _cairo_region_boxes_fini (&bounded, boxes);
2286 _cairo_region_fini (&bound);
2287 _cairo_region_fini (&bounded);
2288 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2290 } else {
2291 rects = surface->embedded_clip_rects;
2294 for (i = 0; i < n_boxes; i++) {
2295 rects[i].x = boxes[i].p1.x;
2296 rects[i].y = boxes[i].p1.y;
2297 rects[i].width = boxes[i].p2.x - boxes[i].p1.x;
2298 rects[i].height = boxes[i].p2.y - boxes[i].p1.y;
2301 _cairo_region_boxes_fini (&bounded, boxes);
2302 _cairo_region_fini (&bounded);
2303 _cairo_region_fini (&bound);
2305 surface->have_clip_rects = TRUE;
2306 surface->clip_rects = rects;
2307 surface->num_clip_rects = n_boxes;
2309 /* Discard the trivial clip rectangle that covers the entire surface */
2310 if (n_boxes == 1 &&
2311 rects[0].x == 0 &&
2312 rects[0].y == 0 &&
2313 rects[0].width == surface->width &&
2314 rects[0].height == surface->height)
2316 surface->have_clip_rects = FALSE;
2317 surface->num_clip_rects = 0;
2319 if (! had_clip_rects)
2320 goto DONE;
2324 surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
2325 DONE:
2327 return CAIRO_STATUS_SUCCESS;
2330 static cairo_int_status_t
2331 _cairo_xlib_surface_get_extents (void *abstract_surface,
2332 cairo_rectangle_int_t *rectangle)
2334 cairo_xlib_surface_t *surface = abstract_surface;
2336 rectangle->x = 0;
2337 rectangle->y = 0;
2339 rectangle->width = surface->width;
2340 rectangle->height = surface->height;
2342 return CAIRO_STATUS_SUCCESS;
2345 static void
2346 _cairo_xlib_surface_get_font_options (void *abstract_surface,
2347 cairo_font_options_t *options)
2349 cairo_xlib_surface_t *surface = abstract_surface;
2351 *options = surface->screen_info->font_options;
2354 static void
2355 _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
2357 static void
2358 _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
2359 cairo_scaled_font_t *scaled_font);
2361 static cairo_bool_t
2362 _cairo_xlib_surface_is_similar (void *surface_a,
2363 void *surface_b,
2364 cairo_content_t content)
2366 cairo_xlib_surface_t *a = surface_a;
2367 cairo_xlib_surface_t *b = surface_b;
2368 XRenderPictFormat *xrender_format = b->xrender_format;
2370 if (!_cairo_xlib_surface_same_screen (a, b))
2371 return FALSE;
2373 /* now inspect the content to check that a is similar to b */
2374 if (xrender_format == NULL && b->visual != NULL)
2375 xrender_format = XRenderFindVisualFormat (b->dpy, b->visual);
2377 if (xrender_format == NULL ||
2378 _xrender_format_to_content (xrender_format) != content)
2380 xrender_format = _cairo_xlib_display_get_xrender_format (
2381 b->display,
2382 _cairo_format_from_content (content));
2386 return a->xrender_format == xrender_format;
2389 static cairo_status_t
2390 _cairo_xlib_surface_reset (void *abstract_surface)
2392 cairo_xlib_surface_t *surface = abstract_surface;
2393 cairo_status_t status;
2395 status = _cairo_xlib_surface_set_clip_region (surface, NULL);
2396 if (status)
2397 return status;
2399 return CAIRO_STATUS_SUCCESS;
2402 static const cairo_surface_backend_t cairo_xlib_surface_backend = {
2403 CAIRO_SURFACE_TYPE_XLIB,
2404 _cairo_xlib_surface_create_similar,
2405 _cairo_xlib_surface_finish,
2406 _cairo_xlib_surface_acquire_source_image,
2407 _cairo_xlib_surface_release_source_image,
2408 _cairo_xlib_surface_acquire_dest_image,
2409 _cairo_xlib_surface_release_dest_image,
2410 _cairo_xlib_surface_clone_similar,
2411 _cairo_xlib_surface_composite,
2412 _cairo_xlib_surface_fill_rectangles,
2413 _cairo_xlib_surface_composite_trapezoids,
2414 NULL, /* copy_page */
2415 NULL, /* show_page */
2416 _cairo_xlib_surface_set_clip_region,
2417 NULL, /* intersect_clip_path */
2418 _cairo_xlib_surface_get_extents,
2419 NULL, /* old_show_glyphs */
2420 _cairo_xlib_surface_get_font_options,
2421 NULL, /* flush */
2422 NULL, /* mark_dirty_rectangle */
2423 _cairo_xlib_surface_scaled_font_fini,
2424 _cairo_xlib_surface_scaled_glyph_fini,
2426 NULL, /* paint */
2427 NULL, /* mask */
2428 NULL, /* stroke */
2429 NULL, /* fill */
2430 _cairo_xlib_surface_show_glyphs,
2431 NULL, /* snapshot */
2432 _cairo_xlib_surface_is_similar,
2433 _cairo_xlib_surface_reset,
2434 NULL, /* fill_stroke */
2435 _cairo_xlib_surface_create_solid_pattern_surface
2439 * _cairo_surface_is_xlib:
2440 * @surface: a #cairo_surface_t
2442 * Checks if a surface is a #cairo_xlib_surface_t
2444 * Return value: True if the surface is an xlib surface
2446 static cairo_bool_t
2447 _cairo_surface_is_xlib (cairo_surface_t *surface)
2449 return surface->backend == &cairo_xlib_surface_backend;
2452 /* callback from CloseDisplay */
2453 static void
2454 _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
2456 cairo_xlib_surface_t *surface = cairo_container_of (data,
2457 cairo_xlib_surface_t,
2458 close_display_hook);
2459 Display *dpy;
2461 dpy = surface->dpy;
2462 surface->dpy = NULL;
2464 if (surface->dst_picture != None) {
2465 XRenderFreePicture (dpy, surface->dst_picture);
2466 surface->dst_picture = None;
2469 if (surface->src_picture != None) {
2470 XRenderFreePicture (dpy, surface->src_picture);
2471 surface->src_picture = None;
2474 if (surface->owns_pixmap) {
2475 XFreePixmap (dpy, surface->drawable);
2476 surface->drawable = None;
2477 surface->owns_pixmap = FALSE;
2480 if (surface->gc != NULL) {
2481 XFreeGC (dpy, surface->gc);
2482 surface->gc = NULL;
2486 static cairo_surface_t *
2487 _cairo_xlib_surface_create_internal (Display *dpy,
2488 Drawable drawable,
2489 Screen *screen,
2490 Visual *visual,
2491 XRenderPictFormat *xrender_format,
2492 int width,
2493 int height,
2494 int depth)
2496 cairo_xlib_surface_t *surface;
2497 cairo_xlib_display_t *display;
2498 cairo_xlib_screen_info_t *screen_info;
2500 CAIRO_MUTEX_INITIALIZE ();
2502 if (xrender_format) {
2503 depth = xrender_format->depth;
2505 /* XXX find matching visual for core/dithering fallbacks? */
2506 } else if (visual) {
2507 int j, k;
2509 /* This is ugly, but we have to walk over all visuals
2510 * for the display to find the correct depth.
2512 depth = 0;
2513 for (j = 0; j < screen->ndepths; j++) {
2514 Depth *d = &screen->depths[j];
2515 for (k = 0; k < d->nvisuals; k++) {
2516 if (&d->visuals[k] == visual) {
2517 depth = d->depth;
2518 goto found;
2522 found:
2526 if (depth == 0)
2527 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
2529 display = _cairo_xlib_display_get (dpy);
2530 if (display == NULL)
2531 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2533 screen_info = _cairo_xlib_screen_info_get (display, screen);
2534 if (screen_info == NULL) {
2535 _cairo_xlib_display_destroy (display);
2536 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2539 surface = malloc (sizeof (cairo_xlib_surface_t));
2540 if (surface == NULL) {
2541 _cairo_xlib_screen_info_destroy (screen_info);
2542 _cairo_xlib_display_destroy (display);
2543 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2546 /* initialize and hook into the CloseDisplay callback */
2547 surface->close_display_hook.func = _cairo_xlib_surface_detach_display;
2548 _cairo_xlib_add_close_display_hook (display, &surface->close_display_hook);
2550 if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
2551 surface->render_major = -1;
2552 surface->render_minor = -1;
2555 if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
2556 if (!xrender_format) {
2557 if (visual) {
2558 xrender_format = XRenderFindVisualFormat (dpy, visual);
2559 } else if (depth == 1) {
2560 xrender_format =
2561 _cairo_xlib_display_get_xrender_format (display,
2562 CAIRO_FORMAT_A1);
2565 } else {
2566 xrender_format = NULL;
2569 /* we cannot use XRender for this surface, so ensure we don't try */
2570 if (xrender_format == NULL) {
2571 surface->render_major = -1;
2572 surface->render_minor = -1;
2575 _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend,
2576 _xrender_format_to_content (xrender_format));
2578 surface->dpy = dpy;
2579 surface->display = display;
2580 surface->screen_info = screen_info;
2582 surface->gc = NULL;
2583 surface->drawable = drawable;
2584 surface->screen = screen;
2585 surface->owns_pixmap = FALSE;
2586 surface->use_pixmap = 0;
2587 surface->width = width;
2588 surface->height = height;
2590 surface->buggy_repeat = screen_info->display->buggy_repeat;
2591 if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
2592 /* so we can use the XTile fallback */
2593 surface->buggy_repeat = TRUE;
2596 surface->dst_picture = None;
2597 surface->src_picture = None;
2599 surface->visual = visual;
2600 surface->xrender_format = xrender_format;
2601 surface->depth = depth;
2602 surface->filter = CAIRO_FILTER_NEAREST;
2603 surface->repeat = FALSE;
2604 surface->xtransform = identity;
2606 surface->have_clip_rects = FALSE;
2607 surface->clip_rects = surface->embedded_clip_rects;
2608 surface->num_clip_rects = 0;
2611 * Compute the pixel format masks from either a XrenderFormat or
2612 * else from a visual; failing that we assume the drawable is an
2613 * alpha-only pixmap as it could only have been created that way
2614 * through the cairo_xlib_surface_create_for_bitmap function.
2616 if (xrender_format) {
2617 surface->a_mask = (unsigned long)
2618 surface->xrender_format->direct.alphaMask
2619 << surface->xrender_format->direct.alpha;
2620 surface->r_mask = (unsigned long)
2621 surface->xrender_format->direct.redMask
2622 << surface->xrender_format->direct.red;
2623 surface->g_mask = (unsigned long)
2624 surface->xrender_format->direct.greenMask
2625 << surface->xrender_format->direct.green;
2626 surface->b_mask = (unsigned long)
2627 surface->xrender_format->direct.blueMask
2628 << surface->xrender_format->direct.blue;
2629 } else if (visual) {
2630 surface->a_mask = 0;
2631 surface->r_mask = visual->red_mask;
2632 surface->g_mask = visual->green_mask;
2633 surface->b_mask = visual->blue_mask;
2634 } else {
2635 if (depth < 32)
2636 surface->a_mask = (1 << depth) - 1;
2637 else
2638 surface->a_mask = 0xffffffff;
2639 surface->r_mask = 0;
2640 surface->g_mask = 0;
2641 surface->b_mask = 0;
2644 return (cairo_surface_t *) surface;
2647 static Screen *
2648 _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
2650 int s;
2651 int d;
2652 int v;
2653 Screen *screen;
2654 Depth *depth;
2656 for (s = 0; s < ScreenCount (dpy); s++) {
2657 screen = ScreenOfDisplay (dpy, s);
2658 if (visual == DefaultVisualOfScreen (screen))
2659 return screen;
2660 for (d = 0; d < screen->ndepths; d++) {
2661 depth = &screen->depths[d];
2662 for (v = 0; v < depth->nvisuals; v++)
2663 if (visual == &depth->visuals[v])
2664 return screen;
2667 return NULL;
2671 * cairo_xlib_surface_create:
2672 * @dpy: an X Display
2673 * @drawable: an X Drawable, (a Pixmap or a Window)
2674 * @visual: the visual to use for drawing to @drawable. The depth
2675 * of the visual must match the depth of the drawable.
2676 * Currently, only TrueColor visuals are fully supported.
2677 * @width: the current width of @drawable.
2678 * @height: the current height of @drawable.
2680 * Creates an Xlib surface that draws to the given drawable.
2681 * The way that colors are represented in the drawable is specified
2682 * by the provided visual.
2684 * Note: If @drawable is a Window, then the function
2685 * cairo_xlib_surface_set_size() must be called whenever the size of the
2686 * window changes.
2688 * When @drawable is a Window containing child windows then drawing to
2689 * the created surface will be clipped by those child windows. When
2690 * the created surface is used as a source, the contents of the
2691 * children will be included.
2693 * Return value: the newly created surface
2695 cairo_surface_t *
2696 cairo_xlib_surface_create (Display *dpy,
2697 Drawable drawable,
2698 Visual *visual,
2699 int width,
2700 int height)
2702 Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual);
2704 if (screen == NULL)
2705 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
2707 return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
2708 visual, NULL, width, height, 0);
2712 * cairo_xlib_surface_create_for_bitmap:
2713 * @dpy: an X Display
2714 * @bitmap: an X Drawable, (a depth-1 Pixmap)
2715 * @screen: the X Screen associated with @bitmap
2716 * @width: the current width of @bitmap.
2717 * @height: the current height of @bitmap.
2719 * Creates an Xlib surface that draws to the given bitmap.
2720 * This will be drawn to as a %CAIRO_FORMAT_A1 object.
2722 * Return value: the newly created surface
2724 cairo_surface_t *
2725 cairo_xlib_surface_create_for_bitmap (Display *dpy,
2726 Pixmap bitmap,
2727 Screen *screen,
2728 int width,
2729 int height)
2731 return _cairo_xlib_surface_create_internal (dpy, bitmap, screen,
2732 NULL, NULL, width, height, 1);
2735 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
2737 * cairo_xlib_surface_create_with_xrender_format:
2738 * @dpy: an X Display
2739 * @drawable: an X Drawable, (a Pixmap or a Window)
2740 * @screen: the X Screen associated with @drawable
2741 * @format: the picture format to use for drawing to @drawable. The depth
2742 * of @format must match the depth of the drawable.
2743 * @width: the current width of @drawable.
2744 * @height: the current height of @drawable.
2746 * Creates an Xlib surface that draws to the given drawable.
2747 * The way that colors are represented in the drawable is specified
2748 * by the provided picture format.
2750 * Note: If @drawable is a Window, then the function
2751 * cairo_xlib_surface_set_size() must be called whenever the size of the
2752 * window changes.
2754 * Return value: the newly created surface
2756 cairo_surface_t *
2757 cairo_xlib_surface_create_with_xrender_format (Display *dpy,
2758 Drawable drawable,
2759 Screen *screen,
2760 XRenderPictFormat *format,
2761 int width,
2762 int height)
2764 return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
2765 NULL, format, width, height, 0);
2769 * cairo_xlib_surface_get_xrender_format:
2770 * @surface: an xlib surface
2772 * Gets the X Render picture format that @surface uses for rendering with the
2773 * X Render extension. If the surface was created by
2774 * cairo_xlib_surface_create_with_xrender_format() originally, the return
2775 * value is the format passed to that constructor.
2777 * Return value: the XRenderPictFormat* associated with @surface,
2778 * or %NULL if the surface is not an xlib surface
2779 * or if the X Render extension is not available.
2781 * Since: 1.6
2783 XRenderPictFormat *
2784 cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
2786 cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
2788 /* Throw an error for a non-xlib surface */
2789 if (! _cairo_surface_is_xlib (surface)) {
2790 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2791 return NULL;
2794 return xlib_surface->xrender_format;
2796 #endif
2799 * cairo_xlib_surface_set_size:
2800 * @surface: a #cairo_surface_t for the XLib backend
2801 * @width: the new width of the surface
2802 * @height: the new height of the surface
2804 * Informs cairo of the new size of the X Drawable underlying the
2805 * surface. For a surface created for a Window (rather than a Pixmap),
2806 * this function must be called each time the size of the window
2807 * changes. (For a subwindow, you are normally resizing the window
2808 * yourself, but for a toplevel window, it is necessary to listen for
2809 * ConfigureNotify events.)
2811 * A Pixmap can never change size, so it is never necessary to call
2812 * this function on a surface created for a Pixmap.
2814 void
2815 cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
2816 int width,
2817 int height)
2819 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
2820 cairo_status_t status;
2822 if (! _cairo_surface_is_xlib (abstract_surface)) {
2823 status = _cairo_surface_set_error (abstract_surface,
2824 CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2825 return;
2828 surface->width = width;
2829 surface->height = height;
2832 * cairo_xlib_surface_set_drawable:
2833 * @surface: a #cairo_surface_t for the XLib backend
2834 * @drawable: the new drawable for the surface
2835 * @width: the width of the new drawable
2836 * @height: the height of the new drawable
2838 * Informs cairo of a new X Drawable underlying the
2839 * surface. The drawable must match the display, screen
2840 * and format of the existing drawable or the application
2841 * will get X protocol errors and will probably terminate.
2842 * No checks are done by this function to ensure this
2843 * compatibility.
2845 void
2846 cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
2847 Drawable drawable,
2848 int width,
2849 int height)
2851 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface;
2852 cairo_status_t status;
2854 if (! _cairo_surface_is_xlib (abstract_surface)) {
2855 status = _cairo_surface_set_error (abstract_surface,
2856 CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2857 return;
2860 /* XXX: and what about this case? */
2861 if (surface->owns_pixmap)
2862 return;
2864 if (surface->drawable != drawable) {
2865 if (surface->dst_picture != None) {
2866 status = _cairo_xlib_display_queue_resource (
2867 surface->display,
2868 XRenderFreePicture,
2869 surface->dst_picture);
2870 if (status) {
2871 status = _cairo_surface_set_error (&surface->base, status);
2872 return;
2875 surface->dst_picture = None;
2878 if (surface->src_picture != None) {
2879 status = _cairo_xlib_display_queue_resource (
2880 surface->display,
2881 XRenderFreePicture,
2882 surface->src_picture);
2883 if (status) {
2884 status = _cairo_surface_set_error (&surface->base, status);
2885 return;
2888 surface->src_picture = None;
2891 surface->drawable = drawable;
2893 surface->width = width;
2894 surface->height = height;
2898 * cairo_xlib_surface_get_display:
2899 * @surface: a #cairo_xlib_surface_t
2901 * Get the X Display for the underlying X Drawable.
2903 * Return value: the display.
2905 * Since: 1.2
2907 Display *
2908 cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
2910 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
2912 if (! _cairo_surface_is_xlib (abstract_surface)) {
2913 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2914 return NULL;
2917 return surface->dpy;
2921 * cairo_xlib_surface_get_drawable:
2922 * @surface: a #cairo_xlib_surface_t
2924 * Get the underlying X Drawable used for the surface.
2926 * Return value: the drawable.
2928 * Since: 1.2
2930 Drawable
2931 cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
2933 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
2935 if (! _cairo_surface_is_xlib (abstract_surface)) {
2936 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2937 return 0;
2940 return surface->drawable;
2944 * cairo_xlib_surface_get_screen:
2945 * @surface: a #cairo_xlib_surface_t
2947 * Get the X Screen for the underlying X Drawable.
2949 * Return value: the screen.
2951 * Since: 1.2
2953 Screen *
2954 cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
2956 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
2958 if (! _cairo_surface_is_xlib (abstract_surface)) {
2959 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2960 return NULL;
2963 return surface->screen;
2967 * cairo_xlib_surface_get_visual:
2968 * @surface: a #cairo_xlib_surface_t
2970 * Get the X Visual used for underlying X Drawable.
2972 * Return value: the visual.
2974 * Since: 1.2
2976 Visual *
2977 cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
2979 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
2981 if (! _cairo_surface_is_xlib (abstract_surface)) {
2982 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2983 return NULL;
2986 return surface->visual;
2990 * cairo_xlib_surface_get_depth:
2991 * @surface: a #cairo_xlib_surface_t
2993 * Get the number of bits used to represent each pixel value.
2995 * Return value: the depth of the surface in bits.
2997 * Since: 1.2
3000 cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
3002 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3004 if (! _cairo_surface_is_xlib (abstract_surface)) {
3005 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3006 return 0;
3009 return surface->depth;
3013 * cairo_xlib_surface_get_width:
3014 * @surface: a #cairo_xlib_surface_t
3016 * Get the width of the X Drawable underlying the surface in pixels.
3018 * Return value: the width of the surface in pixels.
3020 * Since: 1.2
3023 cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
3025 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3027 if (! _cairo_surface_is_xlib (abstract_surface)) {
3028 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3029 return -1;
3032 return surface->width;
3036 * cairo_xlib_surface_get_height:
3037 * @surface: a #cairo_xlib_surface_t
3039 * Get the height of the X Drawable underlying the surface in pixels.
3041 * Return value: the height of the surface in pixels.
3043 * Since: 1.2
3046 cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
3048 cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3050 if (! _cairo_surface_is_xlib (abstract_surface)) {
3051 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3052 return -1;
3055 return surface->height;
3058 enum {
3059 GLYPHSET_INDEX_ARGB32,
3060 GLYPHSET_INDEX_A8,
3061 GLYPHSET_INDEX_A1,
3062 NUM_GLYPHSETS
3065 typedef struct _cairo_xlib_font_glyphset_free_glyphs {
3066 GlyphSet glyphset;
3067 int glyph_count;
3068 unsigned long glyph_indices[128];
3069 } cairo_xlib_font_glyphset_free_glyphs_t;
3071 typedef struct _cairo_xlib_font_glyphset_info {
3072 GlyphSet glyphset;
3073 cairo_format_t format;
3074 XRenderPictFormat *xrender_format;
3075 cairo_xlib_font_glyphset_free_glyphs_t *pending_free_glyphs;
3076 } cairo_xlib_font_glyphset_info_t;
3078 typedef struct _cairo_xlib_surface_font_private {
3079 cairo_scaled_font_t *scaled_font;
3080 cairo_xlib_hook_t close_display_hook;
3081 cairo_xlib_display_t *display;
3082 cairo_xlib_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
3083 } cairo_xlib_surface_font_private_t;
3085 /* callback from CloseDisplay */
3086 static void
3087 _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t *display,
3088 void *data)
3090 cairo_xlib_surface_font_private_t *font_private;
3091 cairo_scaled_font_t *scaled_font;
3093 font_private = cairo_container_of (data,
3094 cairo_xlib_surface_font_private_t,
3095 close_display_hook);
3096 scaled_font = font_private->scaled_font;
3098 CAIRO_MUTEX_LOCK (scaled_font->mutex);
3099 font_private = scaled_font->surface_private;
3100 scaled_font->surface_private = NULL;
3102 _cairo_scaled_font_reset_cache (scaled_font);
3103 CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
3105 if (font_private != NULL) {
3106 Display *dpy;
3107 int i;
3109 dpy = display->display;
3110 for (i = 0; i < NUM_GLYPHSETS; i++) {
3111 cairo_xlib_font_glyphset_info_t *glyphset_info;
3113 glyphset_info = &font_private->glyphset_info[i];
3114 if (glyphset_info->glyphset)
3115 XRenderFreeGlyphSet (dpy, glyphset_info->glyphset);
3117 if (glyphset_info->pending_free_glyphs != NULL)
3118 free (glyphset_info->pending_free_glyphs);
3121 _cairo_xlib_display_destroy (font_private->display);
3122 free (font_private);
3126 static cairo_status_t
3127 _cairo_xlib_surface_font_init (Display *dpy,
3128 cairo_scaled_font_t *scaled_font)
3130 cairo_xlib_surface_font_private_t *font_private;
3131 int i;
3133 font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
3134 if (font_private == NULL)
3135 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3137 font_private->scaled_font = scaled_font;
3138 font_private->display = _cairo_xlib_display_get (dpy);
3139 if (font_private->display == NULL) {
3140 free (font_private);
3141 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3144 /* initialize and hook into the CloseDisplay callback */
3145 font_private->close_display_hook.func =
3146 _cairo_xlib_surface_remove_scaled_font;
3147 _cairo_xlib_add_close_display_hook (font_private->display,
3148 &font_private->close_display_hook);
3151 for (i = 0; i < NUM_GLYPHSETS; i++) {
3152 cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
3153 switch (i) {
3154 case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
3155 case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
3156 case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
3157 default: ASSERT_NOT_REACHED; break;
3159 glyphset_info->xrender_format = NULL;
3160 glyphset_info->glyphset = None;
3161 glyphset_info->pending_free_glyphs = NULL;
3164 scaled_font->surface_private = font_private;
3165 scaled_font->surface_backend = &cairo_xlib_surface_backend;
3167 return CAIRO_STATUS_SUCCESS;
3170 static void
3171 _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
3173 cairo_xlib_surface_font_private_t *font_private;
3175 font_private = scaled_font->surface_private;
3176 if (font_private != NULL) {
3177 cairo_xlib_display_t *display;
3178 int i;
3180 display = font_private->display;
3181 _cairo_xlib_remove_close_display_hook (display,
3182 &font_private->close_display_hook);
3184 for (i = 0; i < NUM_GLYPHSETS; i++) {
3185 cairo_xlib_font_glyphset_info_t *glyphset_info;
3187 glyphset_info = &font_private->glyphset_info[i];
3189 if (glyphset_info->pending_free_glyphs != NULL)
3190 free (glyphset_info->pending_free_glyphs);
3192 if (glyphset_info->glyphset) {
3193 cairo_status_t status;
3195 status = _cairo_xlib_display_queue_resource (display,
3196 XRenderFreeGlyphSet,
3197 glyphset_info->glyphset);
3198 (void) status; /* XXX cannot propagate failure */
3202 _cairo_xlib_display_destroy (display);
3203 free (font_private);
3207 static void
3208 _cairo_xlib_render_free_glyphs (Display *dpy,
3209 cairo_xlib_font_glyphset_free_glyphs_t *to_free)
3211 XRenderFreeGlyphs (dpy,
3212 to_free->glyphset,
3213 to_free->glyph_indices,
3214 to_free->glyph_count);
3217 static cairo_xlib_font_glyphset_info_t *
3218 _cairo_xlib_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
3220 return scaled_glyph->surface_private;
3223 static void
3224 _cairo_xlib_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
3225 cairo_xlib_font_glyphset_info_t *glyphset_info)
3227 scaled_glyph->surface_private = glyphset_info;
3230 static void
3231 _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
3232 cairo_scaled_font_t *scaled_font)
3234 cairo_xlib_surface_font_private_t *font_private;
3235 cairo_xlib_font_glyphset_info_t *glyphset_info;
3237 if (scaled_font->finished)
3238 return;
3240 font_private = scaled_font->surface_private;
3241 glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
3242 if (font_private != NULL && glyphset_info != NULL) {
3243 cairo_xlib_font_glyphset_free_glyphs_t *to_free;
3244 cairo_status_t status;
3246 to_free = glyphset_info->pending_free_glyphs;
3247 if (to_free != NULL &&
3248 to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
3250 status = _cairo_xlib_display_queue_work (font_private->display,
3251 (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs,
3252 to_free,
3253 free);
3254 /* XXX cannot propagate failure */
3255 if (status)
3256 free (to_free);
3258 to_free = glyphset_info->pending_free_glyphs = NULL;
3261 if (to_free == NULL) {
3262 to_free = malloc (sizeof (cairo_xlib_font_glyphset_free_glyphs_t));
3263 if (to_free == NULL) {
3264 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
3265 return; /* XXX cannot propagate failure */
3268 to_free->glyphset = glyphset_info->glyphset;
3269 to_free->glyph_count = 0;
3270 glyphset_info->pending_free_glyphs = to_free;
3273 to_free->glyph_indices[to_free->glyph_count++] =
3274 _cairo_scaled_glyph_index (scaled_glyph);
3278 static cairo_bool_t
3279 _native_byte_order_lsb (void)
3281 int x = 1;
3283 return *((char *) &x) == 1;
3286 static cairo_xlib_font_glyphset_info_t *
3287 _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
3288 cairo_format_t format)
3290 cairo_xlib_surface_font_private_t *font_private;
3291 cairo_xlib_font_glyphset_info_t *glyphset_info;
3292 int glyphset_index;
3294 switch (format) {
3295 default:
3296 case CAIRO_FORMAT_RGB24:
3297 case CAIRO_FORMAT_ARGB32: glyphset_index = GLYPHSET_INDEX_ARGB32; break;
3298 case CAIRO_FORMAT_A8: glyphset_index = GLYPHSET_INDEX_A8; break;
3299 case CAIRO_FORMAT_A1: glyphset_index = GLYPHSET_INDEX_A1; break;
3302 font_private = scaled_font->surface_private;
3303 glyphset_info = &font_private->glyphset_info[glyphset_index];
3304 if (glyphset_info->glyphset == None) {
3305 cairo_xlib_display_t *display = font_private->display;
3307 glyphset_info->xrender_format =
3308 _cairo_xlib_display_get_xrender_format (display,
3309 glyphset_info->format);
3310 glyphset_info->glyphset = XRenderCreateGlyphSet (display->display,
3311 glyphset_info->xrender_format);
3314 return glyphset_info;
3317 static cairo_bool_t
3318 _cairo_xlib_glyphset_info_has_pending_free_glyph (
3319 cairo_xlib_font_glyphset_info_t *glyphset_info,
3320 unsigned long glyph_index)
3322 if (glyphset_info->pending_free_glyphs != NULL) {
3323 cairo_xlib_font_glyphset_free_glyphs_t *to_free;
3324 int i;
3326 to_free = glyphset_info->pending_free_glyphs;
3327 for (i = 0; i < to_free->glyph_count; i++) {
3328 if (to_free->glyph_indices[i] == glyph_index) {
3329 to_free->glyph_count--;
3330 memmove (&to_free->glyph_indices[i],
3331 &to_free->glyph_indices[i+1],
3332 (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
3333 return TRUE;
3338 return FALSE;
3341 static cairo_xlib_font_glyphset_info_t *
3342 _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (
3343 cairo_scaled_font_t *scaled_font,
3344 unsigned long glyph_index,
3345 cairo_image_surface_t *surface)
3347 cairo_xlib_surface_font_private_t *font_private;
3348 int i;
3350 font_private = scaled_font->surface_private;
3351 if (font_private == NULL)
3352 return NULL;
3354 if (surface != NULL) {
3355 switch (surface->format) {
3356 default:
3357 case CAIRO_FORMAT_RGB24:
3358 case CAIRO_FORMAT_ARGB32: i = GLYPHSET_INDEX_ARGB32; break;
3359 case CAIRO_FORMAT_A8: i = GLYPHSET_INDEX_A8; break;
3360 case CAIRO_FORMAT_A1: i = GLYPHSET_INDEX_A1; break;
3362 if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
3363 &font_private->glyphset_info[i],
3364 glyph_index))
3366 return &font_private->glyphset_info[i];
3368 } else {
3369 for (i = 0; i < NUM_GLYPHSETS; i++) {
3370 if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
3371 &font_private->glyphset_info[i],
3372 glyph_index))
3374 return &font_private->glyphset_info[i];
3379 return NULL;
3382 static cairo_status_t
3383 _cairo_xlib_surface_add_glyph (Display *dpy,
3384 cairo_scaled_font_t *scaled_font,
3385 cairo_scaled_glyph_t **pscaled_glyph)
3387 XGlyphInfo glyph_info;
3388 unsigned long glyph_index;
3389 unsigned char *data;
3390 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3391 cairo_scaled_glyph_t *scaled_glyph = *pscaled_glyph;
3392 cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
3393 cairo_bool_t already_had_glyph_surface;
3394 cairo_xlib_font_glyphset_info_t *glyphset_info;
3396 glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
3398 /* check to see if we have a pending XRenderFreeGlyph for this glyph */
3399 glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
3400 if (glyphset_info != NULL) {
3401 _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
3402 return CAIRO_STATUS_SUCCESS;
3405 if (!glyph_surface) {
3406 status = _cairo_scaled_glyph_lookup (scaled_font,
3407 glyph_index,
3408 CAIRO_SCALED_GLYPH_INFO_METRICS |
3409 CAIRO_SCALED_GLYPH_INFO_SURFACE,
3410 pscaled_glyph);
3411 if (status)
3412 return status;
3414 scaled_glyph = *pscaled_glyph;
3415 glyph_surface = scaled_glyph->surface;
3416 already_had_glyph_surface = FALSE;
3417 } else {
3418 already_had_glyph_surface = TRUE;
3421 if (scaled_font->surface_private == NULL) {
3422 status = _cairo_xlib_surface_font_init (dpy, scaled_font);
3423 if (status)
3424 return status;
3427 glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_format (scaled_font,
3428 glyph_surface->format);
3430 /* XRenderAddGlyph does not handle a glyph surface larger than the extended maximum XRequest size. */
3432 int len = cairo_format_stride_for_width (glyphset_info->format, glyph_surface->width) * glyph_surface->height;
3433 int max_request_size = (XExtendedMaxRequestSize (dpy) ? XExtendedMaxRequestSize (dpy) : XMaxRequestSize (dpy)) * 4 -
3434 sz_xRenderAddGlyphsReq -
3435 sz_xGlyphInfo -
3437 if (len >= max_request_size)
3438 return CAIRO_INT_STATUS_UNSUPPORTED;
3441 /* If the glyph surface has zero height or width, we create
3442 * a clear 1x1 surface, to avoid various X server bugs.
3444 if (glyph_surface->width == 0 || glyph_surface->height == 0) {
3445 cairo_t *cr;
3446 cairo_surface_t *tmp_surface;
3448 tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
3449 status = tmp_surface->status;
3450 if (status)
3451 goto BAIL;
3453 cr = cairo_create (tmp_surface);
3454 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3455 cairo_paint (cr);
3456 status = cairo_status (cr);
3457 cairo_destroy (cr);
3459 tmp_surface->device_transform = glyph_surface->base.device_transform;
3460 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
3462 glyph_surface = (cairo_image_surface_t *) tmp_surface;
3464 if (status)
3465 goto BAIL;
3468 /* If the glyph format does not match the font format, then we
3469 * create a temporary surface for the glyph image with the font's
3470 * format.
3472 if (glyph_surface->format != glyphset_info->format) {
3473 cairo_t *cr;
3474 cairo_surface_t *tmp_surface;
3476 tmp_surface = cairo_image_surface_create (glyphset_info->format,
3477 glyph_surface->width,
3478 glyph_surface->height);
3479 status = tmp_surface->status;
3480 if (status)
3481 goto BAIL;
3483 tmp_surface->device_transform = glyph_surface->base.device_transform;
3484 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
3486 cr = cairo_create (tmp_surface);
3487 cairo_set_source_surface (cr, &glyph_surface->base, 0, 0);
3488 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3489 cairo_paint (cr);
3490 status = cairo_status (cr);
3491 cairo_destroy (cr);
3493 glyph_surface = (cairo_image_surface_t *) tmp_surface;
3495 if (status)
3496 goto BAIL;
3499 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
3500 glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
3501 glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
3502 glyph_info.width = glyph_surface->width;
3503 glyph_info.height = glyph_surface->height;
3504 glyph_info.xOff = scaled_glyph->x_advance;
3505 glyph_info.yOff = scaled_glyph->y_advance;
3507 data = glyph_surface->data;
3509 /* flip formats around */
3510 switch (scaled_glyph->surface->format) {
3511 case CAIRO_FORMAT_A1:
3512 /* local bitmaps are always stored with bit == byte */
3513 if (_native_byte_order_lsb() != (BitmapBitOrder (dpy) == LSBFirst)) {
3514 int c = glyph_surface->stride * glyph_surface->height;
3515 unsigned char *d;
3516 unsigned char *new, *n;
3518 new = malloc (c);
3519 if (!new) {
3520 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3521 goto BAIL;
3523 n = new;
3524 d = data;
3525 while (c--)
3527 char b = *d++;
3528 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
3529 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
3530 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
3531 *n++ = b;
3533 data = new;
3535 break;
3536 case CAIRO_FORMAT_A8:
3537 break;
3538 case CAIRO_FORMAT_ARGB32:
3539 if (_native_byte_order_lsb() != (ImageByteOrder (dpy) == LSBFirst)) {
3540 unsigned int c = glyph_surface->stride * glyph_surface->height;
3541 unsigned char *d;
3542 unsigned char *new, *n;
3544 new = malloc (c);
3545 if (new == NULL) {
3546 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3547 goto BAIL;
3549 n = new;
3550 d = data;
3551 while (c >= 4)
3553 n[3] = d[0];
3554 n[2] = d[1];
3555 n[1] = d[2];
3556 n[0] = d[3];
3557 d += 4;
3558 n += 4;
3559 c -= 4;
3561 data = new;
3563 break;
3564 case CAIRO_FORMAT_RGB24:
3565 default:
3566 ASSERT_NOT_REACHED;
3567 break;
3569 /* XXX assume X server wants pixman padding. Xft assumes this as well */
3571 XRenderAddGlyphs (dpy, glyphset_info->glyphset,
3572 &glyph_index, &glyph_info, 1,
3573 (char *) data,
3574 glyph_surface->stride * glyph_surface->height);
3576 if (data != glyph_surface->data)
3577 free (data);
3579 _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
3581 BAIL:
3582 if (glyph_surface != scaled_glyph->surface)
3583 cairo_surface_destroy (&glyph_surface->base);
3585 /* if the scaled glyph didn't already have a surface attached
3586 * to it, release the created surface now that we have it
3587 * uploaded to the X server. If the surface has already been
3588 * there (eg. because image backend requested it), leave it in
3589 * the cache
3591 if (!already_had_glyph_surface)
3592 _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
3594 return status;
3597 typedef void (*cairo_xrender_composite_text_func_t)
3598 (Display *dpy,
3599 int op,
3600 Picture src,
3601 Picture dst,
3602 _Xconst XRenderPictFormat *maskFormat,
3603 int xSrc,
3604 int ySrc,
3605 int xDst,
3606 int yDst,
3607 _Xconst XGlyphElt8 *elts,
3608 int nelt);
3610 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
3611 * an input glyph with double coordinates, and as "working" glyph with
3612 * integer from-current-point offsets. */
3613 typedef union {
3614 cairo_glyph_t d;
3615 unsigned long index;
3616 struct {
3617 unsigned long index;
3618 int x;
3619 int y;
3620 } i;
3621 } cairo_xlib_glyph_t;
3623 /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
3624 COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
3626 /* Start a new element for the first glyph,
3627 * or for any glyph that has unexpected position,
3628 * or if current element has too many glyphs
3629 * (Xrender limits each element to 252 glyphs, we limit them to 128)
3631 * These same conditions need to be mirrored between
3632 * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
3634 #define _start_new_glyph_elt(count, glyph) \
3635 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
3637 static cairo_status_t
3638 _emit_glyphs_chunk (cairo_xlib_surface_t *dst,
3639 cairo_xlib_glyph_t *glyphs,
3640 int num_glyphs,
3641 cairo_scaled_font_t *scaled_font,
3642 cairo_operator_t op,
3643 cairo_xlib_surface_t *src,
3644 cairo_surface_attributes_t *attributes,
3645 /* info for this chunk */
3646 int num_elts,
3647 int width,
3648 cairo_xlib_font_glyphset_info_t *glyphset_info)
3650 /* Which XRenderCompositeText function to use */
3651 cairo_xrender_composite_text_func_t composite_text_func;
3652 int size;
3654 /* Element buffer stuff */
3655 XGlyphElt8 *elts;
3656 XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
3658 /* Reuse the input glyph array for output char generation */
3659 char *char8 = (char *) glyphs;
3660 unsigned short *char16 = (unsigned short *) glyphs;
3661 unsigned int *char32 = (unsigned int *) glyphs;
3663 int i;
3664 int nelt; /* Element index */
3665 int n; /* Num output glyphs in current element */
3666 int j; /* Num output glyphs so far */
3668 switch (width) {
3669 case 1:
3670 /* don't cast the 8-variant, to catch possible mismatches */
3671 composite_text_func = XRenderCompositeText8;
3672 size = sizeof (char);
3673 break;
3674 case 2:
3675 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
3676 size = sizeof (unsigned short);
3677 break;
3678 default:
3679 case 4:
3680 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
3681 size = sizeof (unsigned int);
3684 /* Allocate element array */
3685 if (num_elts <= ARRAY_LENGTH (stack_elts)) {
3686 elts = stack_elts;
3687 } else {
3688 elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
3689 if (elts == NULL)
3690 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3693 /* Fill them in */
3694 nelt = 0;
3695 n = 0;
3696 j = 0;
3697 for (i = 0; i < num_glyphs; i++) {
3699 /* Start a new element for first output glyph,
3700 * or for any glyph that has unexpected position,
3701 * or if current element has too many glyphs.
3703 * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
3705 if (_start_new_glyph_elt (j, &glyphs[i])) {
3706 if (j) {
3707 elts[nelt].nchars = n;
3708 nelt++;
3709 n = 0;
3711 elts[nelt].chars = char8 + size * j;
3712 elts[nelt].glyphset = glyphset_info->glyphset;
3713 elts[nelt].xOff = glyphs[i].i.x;
3714 elts[nelt].yOff = glyphs[i].i.y;
3717 switch (width) {
3718 case 1: char8 [j] = (char) glyphs[i].index; break;
3719 case 2: char16[j] = (unsigned short) glyphs[i].index; break;
3720 default:
3721 case 4: char32[j] = (unsigned int) glyphs[i].index; break;
3724 n++;
3725 j++;
3728 if (n) {
3729 elts[nelt].nchars = n;
3730 nelt++;
3731 n = 0;
3734 /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
3735 * expected number of xGlyphElts. */
3736 assert (nelt == num_elts);
3738 composite_text_func (dst->dpy,
3739 _render_operator (op),
3740 src->src_picture,
3741 dst->dst_picture,
3742 glyphset_info->xrender_format,
3743 attributes->x_offset + elts[0].xOff,
3744 attributes->y_offset + elts[0].yOff,
3745 elts[0].xOff, elts[0].yOff,
3746 (XGlyphElt8 *) elts, nelt);
3748 if (elts != stack_elts)
3749 free (elts);
3751 return CAIRO_STATUS_SUCCESS;
3755 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
3756 * enough room for padding */
3757 #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
3759 static cairo_status_t
3760 _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
3761 cairo_xlib_glyph_t *glyphs,
3762 int num_glyphs,
3763 cairo_scaled_font_t *scaled_font,
3764 cairo_operator_t op,
3765 cairo_xlib_surface_t *src,
3766 cairo_surface_attributes_t *attributes,
3767 int *remaining_glyphs)
3769 int i;
3770 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3771 cairo_scaled_glyph_t *scaled_glyph;
3772 cairo_fixed_t x = 0, y = 0;
3773 cairo_xlib_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
3775 unsigned long max_index = 0;
3776 int width = 1;
3777 int num_elts = 0;
3778 int num_out_glyphs = 0;
3780 int max_request_size = XMaxRequestSize (dst->dpy) * 4
3781 - MAX (sz_xRenderCompositeGlyphs8Req,
3782 MAX(sz_xRenderCompositeGlyphs16Req,
3783 sz_xRenderCompositeGlyphs32Req));
3784 int request_size = 0;
3786 _cairo_xlib_surface_ensure_dst_picture (dst);
3787 _cairo_xlib_display_notify (dst->display);
3789 for (i = 0; i < num_glyphs; i++) {
3790 int this_x, this_y;
3791 int old_width;
3793 status = _cairo_scaled_glyph_lookup (scaled_font,
3794 glyphs[i].index,
3795 CAIRO_SCALED_GLYPH_INFO_METRICS,
3796 &scaled_glyph);
3797 if (status != CAIRO_STATUS_SUCCESS)
3798 return status;
3800 this_x = _cairo_lround (glyphs[i].d.x);
3801 this_y = _cairo_lround (glyphs[i].d.y);
3803 /* Glyph skipping:
3805 * We skip any glyphs that have troublesome coordinates. We want
3806 * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
3807 * a signed 16bit integer, otherwise it will overflow in the render
3808 * protocol.
3809 * To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
3810 * a signed 15bit integer. The trivial option would be to allow
3811 * coordinates -8192..8192, but that's kinda dull. It probably will
3812 * take a decade or so to get monitors 8192x4096 or something. A
3813 * negative value of -8192 on the other hand, is absolutely useless.
3814 * Note that we do want to allow some negative positions. The glyph
3815 * may start off the screen but part of it make it to the screen.
3816 * Anyway, we will allow positions in the range -4096..122887. That
3817 * will buy us a few more years before this stops working.
3819 * Update: upon seeing weird glyphs, we just return and let fallback
3820 * code do the job.
3822 if (((this_x+4096)|(this_y+4096))&~0x3fffu)
3823 break;
3825 /* Send unsent glyphs to the server */
3826 if (_cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
3827 status = _cairo_xlib_surface_add_glyph (dst->dpy,
3828 scaled_font,
3829 &scaled_glyph);
3830 if (status) {
3831 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
3832 /* Break so we flush glyphs so far and let fallback code
3833 * handle the rest */
3834 break;
3836 return status;
3840 this_glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
3841 if (!glyphset_info)
3842 glyphset_info = this_glyphset_info;
3844 /* The invariant here is that we can always flush the glyphs
3845 * accumulated before this one, using old_width, and they
3846 * would fit in the request.
3848 old_width = width;
3850 /* Update max glyph index */
3851 if (glyphs[i].index > max_index) {
3852 max_index = glyphs[i].index;
3853 if (max_index >= 65536)
3854 width = 4;
3855 else if (max_index >= 256)
3856 width = 2;
3857 if (width != old_width)
3858 request_size += (width - old_width) * num_out_glyphs;
3861 /* If we will pass the max request size by adding this glyph,
3862 * flush current glyphs. Note that we account for a
3863 * possible element being added below.
3865 * Also flush if changing glyphsets, as Xrender limits one mask
3866 * format per request, so we can either break up, or use a
3867 * wide-enough mask format. We do the former. One reason to
3868 * prefer the latter is the fact that Xserver ADDs all glyphs
3869 * to the mask first, and then composes that to final surface,
3870 * though it's not a big deal.
3872 if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
3873 (this_glyphset_info != glyphset_info)) {
3874 status = _emit_glyphs_chunk (dst, glyphs, i,
3875 scaled_font, op, src, attributes,
3876 num_elts, old_width, glyphset_info);
3877 if (status != CAIRO_STATUS_SUCCESS)
3878 return status;
3880 glyphs += i;
3881 num_glyphs -= i;
3882 i = 0;
3883 max_index = glyphs[i].index;
3884 width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
3885 request_size = 0;
3886 num_elts = 0;
3887 num_out_glyphs = 0;
3888 x = y = 0;
3889 glyphset_info = this_glyphset_info;
3892 /* Convert absolute glyph position to relative-to-current-point
3893 * position */
3894 glyphs[i].i.x = this_x - x;
3895 glyphs[i].i.y = this_y - y;
3897 /* Start a new element for the first glyph,
3898 * or for any glyph that has unexpected position,
3899 * or if current element has too many glyphs.
3901 * These same conditions are mirrored in _emit_glyphs_chunk().
3903 if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
3904 num_elts++;
3905 request_size += _cairo_sz_xGlyphElt;
3908 /* adjust current-position */
3909 x = this_x + scaled_glyph->x_advance;
3910 y = this_y + scaled_glyph->y_advance;
3912 num_out_glyphs++;
3913 request_size += width;
3916 if (num_elts)
3917 status = _emit_glyphs_chunk (dst, glyphs, i,
3918 scaled_font, op, src, attributes,
3919 num_elts, width, glyphset_info);
3921 *remaining_glyphs = num_glyphs - i;
3922 if (*remaining_glyphs && status == CAIRO_STATUS_SUCCESS)
3923 status = CAIRO_INT_STATUS_UNSUPPORTED;
3925 return status;
3928 static cairo_bool_t
3929 _cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst,
3930 cairo_scaled_font_t *scaled_font)
3932 cairo_xlib_surface_font_private_t *font_private;
3934 font_private = scaled_font->surface_private;
3935 if ((scaled_font->surface_backend != NULL &&
3936 scaled_font->surface_backend != &cairo_xlib_surface_backend) ||
3937 (font_private != NULL && font_private->display != dst->display))
3939 return FALSE;
3942 return TRUE;
3945 static cairo_int_status_t
3946 _cairo_xlib_surface_show_glyphs (void *abstract_dst,
3947 cairo_operator_t op,
3948 cairo_pattern_t *src_pattern,
3949 cairo_glyph_t *glyphs,
3950 int num_glyphs,
3951 cairo_scaled_font_t *scaled_font,
3952 int *remaining_glyphs)
3954 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
3955 cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst;
3957 composite_operation_t operation;
3958 cairo_surface_attributes_t attributes;
3959 cairo_xlib_surface_t *src = NULL;
3961 cairo_solid_pattern_t solid_pattern;
3963 if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
3964 return CAIRO_INT_STATUS_UNSUPPORTED;
3966 /* Just let unbounded operators go through the fallback code
3967 * instead of trying to do the fixups here */
3968 if (!_cairo_operator_bounded_by_mask (op))
3969 return CAIRO_INT_STATUS_UNSUPPORTED;
3971 /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
3972 * the solid source seems to be multiplied by the glyph mask, and
3973 * then the entire thing is copied to the destination surface,
3974 * including the fully transparent "background" of the rectangular
3975 * glyph surface. */
3976 if (op == CAIRO_OPERATOR_SOURCE &&
3977 !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
3978 return CAIRO_INT_STATUS_UNSUPPORTED;
3980 /* We can only use our code if we either have no clip or
3981 * have a real native clip region set. If we're using
3982 * fallback clip masking, we have to go through the full
3983 * fallback path.
3985 if (dst->base.clip &&
3986 (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
3987 dst->base.clip->surface != NULL))
3988 return CAIRO_INT_STATUS_UNSUPPORTED;
3990 operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
3991 if (operation == DO_UNSUPPORTED)
3992 return CAIRO_INT_STATUS_UNSUPPORTED;
3994 if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
3995 return CAIRO_INT_STATUS_UNSUPPORTED;
3997 /* After passing all those tests, we're now committed to rendering
3998 * these glyphs or to fail trying. We first upload any glyphs to
3999 * the X server that it doesn't have already, then we draw
4000 * them.
4003 /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
4004 * the mask (the glyphs). This code below was executed as a side effect
4005 * of going through the _clip_and_composite fallback code for old_show_glyphs,
4006 * so PictOpClear was never used with CompositeText before.
4008 if (op == CAIRO_OPERATOR_CLEAR) {
4009 _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
4010 CAIRO_CONTENT_COLOR);
4011 src_pattern = &solid_pattern.base;
4012 op = CAIRO_OPERATOR_DEST_OUT;
4015 if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
4016 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
4017 0, 0, 1, 1,
4018 (cairo_surface_t **) &src,
4019 &attributes);
4020 if (status)
4021 goto BAIL0;
4022 } else {
4023 cairo_rectangle_int_t glyph_extents;
4025 status = _cairo_scaled_font_glyph_device_extents (scaled_font,
4026 glyphs,
4027 num_glyphs,
4028 &glyph_extents);
4029 if (status)
4030 goto BAIL0;
4032 status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
4033 glyph_extents.x, glyph_extents.y,
4034 glyph_extents.width, glyph_extents.height,
4035 (cairo_surface_t **) &src,
4036 &attributes);
4037 if (status)
4038 goto BAIL0;
4041 operation = _recategorize_composite_operation (dst, op, src,
4042 &attributes, TRUE);
4043 if (operation == DO_UNSUPPORTED) {
4044 status = CAIRO_INT_STATUS_UNSUPPORTED;
4045 goto BAIL1;
4048 status = _cairo_xlib_surface_set_attributes (src, &attributes);
4049 if (status)
4050 goto BAIL1;
4052 _cairo_scaled_font_freeze_cache (scaled_font);
4053 if (_cairo_xlib_surface_owns_font (dst, scaled_font)) {
4054 status = _cairo_xlib_surface_emit_glyphs (dst,
4055 (cairo_xlib_glyph_t *) glyphs,
4056 num_glyphs,
4057 scaled_font,
4059 src,
4060 &attributes,
4061 remaining_glyphs);
4062 } else
4063 status = CAIRO_INT_STATUS_UNSUPPORTED;
4064 _cairo_scaled_font_thaw_cache (scaled_font);
4066 BAIL1:
4067 if (src)
4068 _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
4069 if (src_pattern == &solid_pattern.base)
4070 _cairo_pattern_fini (&solid_pattern.base);
4071 BAIL0:
4072 _cairo_xlib_display_notify (dst->display);
4074 return status;