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
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
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
,
57 static cairo_surface_t
*
58 _cairo_xlib_surface_create_internal (Display
*dpy
,
62 XRenderPictFormat
*xrender_format
,
68 _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t
*surface
);
71 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t
*surface
);
74 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t
*surface
);
77 _cairo_surface_is_xlib (cairo_surface_t
*surface
);
80 _native_byte_order_lsb (void);
82 static cairo_int_status_t
83 _cairo_xlib_surface_show_glyphs (void *abstract_dst
,
85 cairo_pattern_t
*src_pattern
,
86 cairo_glyph_t
*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 },
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
,
132 cairo_xlib_surface_t
*src
= abstract_src
;
133 Display
*dpy
= src
->dpy
;
135 cairo_xlib_surface_t
*surface
;
136 XRenderPictFormat
*xrender_format
;
138 if (width
> XLIB_COORD_MAX
|| height
> XLIB_COORD_MAX
)
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
))
149 xrender_format
= _cairo_xlib_display_get_xrender_format (
152 if (xrender_format
== 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
,
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
;
195 return CAIRO_CONTENT_ALPHA
;
197 return CAIRO_CONTENT_COLOR
;
200 static cairo_surface_t
*
201 _cairo_xlib_surface_create_similar (void *abstract_src
,
202 cairo_content_t content
,
206 cairo_xlib_surface_t
*src
= abstract_src
;
207 XRenderPictFormat
*xrender_format
= src
->xrender_format
;
208 cairo_xlib_surface_t
*surface
;
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
),
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
,
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
,
271 surface
->dst_picture
);
272 if (status2
== CAIRO_STATUS_SUCCESS
)
273 surface
->dst_picture
= None
;
274 else if (status
== CAIRO_STATUS_SUCCESS
)
278 if (surface
->src_picture
!= None
) {
279 status2
= _cairo_xlib_display_queue_resource (display
,
281 surface
->src_picture
);
282 if (status2
== CAIRO_STATUS_SUCCESS
)
283 surface
->src_picture
= None
;
284 else if (status
== CAIRO_STATUS_SUCCESS
)
288 status2
= _cairo_xlib_display_queue_resource (display
,
289 (cairo_xlib_notify_resource_func
) XFreePixmap
,
291 if (status2
== CAIRO_STATUS_SUCCESS
) {
292 surface
->owns_pixmap
= FALSE
;
293 surface
->drawable
= None
;
294 } else if (status
== CAIRO_STATUS_SUCCESS
)
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
,
309 surface
->have_clip_rects
);
311 if (status
== CAIRO_STATUS_SUCCESS
)
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
);
333 _noop_error_handler (Display
*display
,
336 return False
; /* return value is ignored */
340 _swap_ximage_2bytes (XImage
*ximage
)
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
--) {
352 line
+= ximage
->bytes_per_line
;
357 _swap_ximage_3bytes (XImage
*ximage
)
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
--) {
372 line
+= ximage
->bytes_per_line
;
377 _swap_ximage_4bytes (XImage
*ximage
)
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
--) {
389 line
+= ximage
->bytes_per_line
;
394 _swap_ximage_nibbles (XImage
*ximage
)
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);
406 line
+= ximage
->bytes_per_line
;
411 _swap_ximage_bits (XImage
*ximage
)
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
--) {
421 for (i
= line_bytes
; i
; i
--) {
423 b
= ((b
<< 1) & 0xaa) | ((b
>> 1) & 0x55);
424 b
= ((b
<< 2) & 0xcc) | ((b
>> 2) & 0x33);
425 b
= ((b
<< 4) & 0xf0) | ((b
>> 4) & 0x0f);
431 line
+= ximage
->bytes_per_line
;
436 _swap_ximage_to_native (XImage
*ximage
)
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
)
449 if (ximage
->byte_order
== native_byte_order
)
452 switch (ximage
->bits_per_pixel
) {
454 unit_bytes
= ximage
->bitmap_unit
/ 8;
457 _swap_ximage_nibbles (ximage
);
466 unit_bytes
= (ximage
->bits_per_pixel
+ 7) / 8;
469 /* This could be hit on some rare but possible cases. */
473 switch (unit_bytes
) {
477 _swap_ximage_2bytes (ximage
);
480 _swap_ximage_3bytes (ximage
);
483 _swap_ximage_4bytes (ximage
);
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'. */
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
505 static inline uint32_t
506 _resize_field (uint32_t field
, int width
, int new_width
)
511 if (width
>= new_width
) {
512 return field
>> (width
- new_width
);
514 uint32_t result
= field
<< (new_width
- width
);
516 while (width
< new_width
) {
517 result
|= result
>> width
;
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
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
)];
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
,
586 r
= visual_info
->colors
[pixel
].r
;
587 g
= visual_info
->colors
[pixel
].g
;
588 b
= visual_info
->colors
[pixel
].b
;
595 /* should range from -128 to 127 */
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
}
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
;
615 cairo_rectangle_int_t extents
;
616 pixman_format_code_t pixman_format
;
617 cairo_format_masks_t xlib_masks
;
621 extents
.width
= surface
->width
;
622 extents
.height
= surface
->height
;
625 if (! _cairo_rectangle_intersect (&extents
, interest_rect
)) {
627 return CAIRO_STATUS_SUCCESS
;
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
,
644 extents
.x
, extents
.y
,
645 extents
.width
, extents
.height
,
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.
654 surface
->use_pixmap
= CAIRO_ASSUME_PIXMAP
;
658 surface
->use_pixmap
--;
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
672 cairo_status_t status
= _cairo_xlib_surface_ensure_gc (surface
);
676 pixmap
= XCreatePixmap (surface
->dpy
,
678 extents
.width
, extents
.height
,
681 XCopyArea (surface
->dpy
, surface
->drawable
, pixmap
, surface
->gc
,
682 extents
.x
, extents
.y
,
683 extents
.width
, extents
.height
,
686 ximage
= XGetImage (surface
->dpy
,
689 extents
.width
, extents
.height
,
692 XFreePixmap (surface
->dpy
, pixmap
);
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
,
716 ximage
->bytes_per_line
);
717 status
= image
->base
.status
;
721 /* Let the surface take ownership of the data */
722 _cairo_image_surface_assume_ownership_of_data (image
);
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
;
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
||
751 format
= CAIRO_FORMAT_ARGB32
;
753 format
= CAIRO_FORMAT_RGB24
;
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
);
774 format
= CAIRO_FORMAT_RGB24
;
776 status
= _cairo_xlib_screen_get_visual_info (surface
->screen_info
,
783 image
= (cairo_image_surface_t
*) cairo_image_surface_create
784 (format
, ximage
->width
, ximage
->height
);
785 status
= image
->base
.status
;
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
);
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]);
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
) {
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
));
811 /* Undithering pseudocolor does not look better */
812 out_pixel
= _pseudocolor_to_rgb888 (visual_info
, in_pixel
);
821 XDestroyImage (ximage
);
825 cairo_surface_destroy (&image
->base
);
834 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t
*surface
)
836 if (!surface
->src_picture
)
838 XRenderPictureAttributes pa
;
841 pa
.subwindow_mode
= IncludeInferiors
;
842 mask
|= CPSubwindowMode
;
844 surface
->src_picture
= XRenderCreatePicture (surface
->dpy
,
846 surface
->xrender_format
,
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
,
858 surface
->num_clip_rects
);
860 XRenderPictureAttributes pa
;
862 XRenderChangePicture (surface
->dpy
, surface
->dst_picture
,
866 surface
->clip_dirty
&= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE
;
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
,
876 surface
->num_clip_rects
, YXSorted
);
878 XSetClipMask (surface
->dpy
, surface
->gc
, None
);
880 surface
->clip_dirty
&= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC
;
884 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t
*surface
)
886 if (!surface
->dst_picture
) {
887 surface
->dst_picture
= XRenderCreatePicture (surface
->dpy
,
889 surface
->xrender_format
,
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
)
901 if (surface
->gc
== NULL
) {
902 surface
->gc
= _cairo_xlib_screen_get_gc (surface
->screen_info
,
904 if (surface
->gc
== NULL
) {
905 gcv
.graphics_exposures
= False
;
906 surface
->gc
= XCreateGC (surface
->dpy
, surface
->drawable
,
907 GCGraphicsExposures
, &gcv
);
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
,
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
;
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
)
956 ximage
.bits_per_pixel
= image_masks
.bpp
;
957 ximage
.bytes_per_line
= image
->stride
;
958 ximage
.data
= (char *)image
->data
;
961 ret
= XInitImage (&ximage
);
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
;
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;
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
);
993 ret
= XInitImage (&ximage
);
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
;
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
);
1009 status
= _cairo_xlib_screen_get_visual_info (surface
->screen_info
,
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
);
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]);
1028 x
++, x_off
= (x_off
+1) % ARRAY_LENGTH (dither_pattern
[0]))
1030 int dither_adjustment
= dither_row
[x_off
];
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
];
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)
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
);
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
);
1058 out_pixel
= _pseudocolor_from_rgb888_dither (visual_info
, r
, g
, b
, dither_adjustment
);
1061 XPutPixel (&ximage
, x
, y
, out_pixel
);
1068 status
= _cairo_xlib_surface_ensure_gc (surface
);
1072 XPutImage(surface
->dpy
, surface
->drawable
, surface
->gc
,
1073 &ximage
, src_x
, src_y
, dst_x
, dst_y
,
1083 static cairo_status_t
1084 _cairo_xlib_surface_acquire_source_image (void *abstract_surface
,
1085 cairo_image_surface_t
**image_out
,
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
);
1099 *image_extra
= NULL
;
1101 return CAIRO_STATUS_SUCCESS
;
1105 _cairo_xlib_surface_release_source_image (void *abstract_surface
,
1106 cairo_image_surface_t
*image
,
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
,
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
);
1130 *image_extra
= NULL
;
1132 return CAIRO_STATUS_SUCCESS
;
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
,
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.
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
,
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
,
1206 return CAIRO_INT_STATUS_UNSUPPORTED
;
1208 if (clone
->base
.status
)
1209 return clone
->base
.status
;
1211 status
= _draw_image_surface (clone
, image_src
,
1216 cairo_surface_destroy (&clone
->base
);
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
))
1255 if (width
> XLIB_COORD_MAX
|| height
> XLIB_COORD_MAX
)
1258 image
= (cairo_image_surface_t
*)
1259 _cairo_image_surface_create_with_content (solid_pattern
->content
,
1261 status
= image
->base
.status
;
1265 pixmap
= XCreatePixmap (other
->dpy
,
1270 surface
= (cairo_xlib_surface_t
*)
1271 _cairo_xlib_surface_create_internal (other
->dpy
,
1273 other
->screen
, other
->visual
,
1274 other
->xrender_format
,
1277 status
= surface
->base
.status
;
1281 status
= _cairo_surface_paint (&image
->base
,
1282 CAIRO_OPERATOR_SOURCE
,
1283 &solid_pattern
->base
);
1287 status
= _draw_image_surface (surface
, image
,
1295 cairo_surface_destroy (&image
->base
);
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
;
1356 case CAIRO_FILTER_FAST
:
1357 render_filter
= FilterFast
;
1359 case CAIRO_FILTER_GOOD
:
1360 render_filter
= FilterGood
;
1362 case CAIRO_FILTER_BEST
:
1363 render_filter
= FilterBest
;
1365 case CAIRO_FILTER_NEAREST
:
1366 render_filter
= FilterNearest
;
1368 case CAIRO_FILTER_BILINEAR
:
1369 render_filter
= FilterBilinear
;
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. */
1378 render_filter
= FilterBest
;
1382 XRenderSetPictureFilter (surface
->dpy
, surface
->src_picture
,
1383 (char *) render_filter
, NULL
, 0);
1384 surface
->filter
= filter
;
1386 return CAIRO_STATUS_SUCCESS
;
1390 _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t
*surface
, int repeat
)
1392 XRenderPictureAttributes pa
;
1395 if (!surface
->src_picture
)
1398 if (surface
->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
);
1420 switch (attributes
->extend
) {
1421 case CAIRO_EXTEND_NONE
:
1422 _cairo_xlib_surface_set_repeat (surface
, RepeatNone
);
1424 case CAIRO_EXTEND_REPEAT
:
1425 _cairo_xlib_surface_set_repeat (surface
, RepeatNormal
);
1427 case CAIRO_EXTEND_REFLECT
:
1428 case CAIRO_EXTEND_PAD
:
1430 return CAIRO_INT_STATUS_UNSUPPORTED
;
1433 status
= _cairo_xlib_surface_set_filter (surface
, attributes
->filter
);
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
1445 _surfaces_compatible (cairo_xlib_surface_t
*dst
,
1446 cairo_xlib_surface_t
*src
)
1449 if (!_cairo_xlib_surface_same_screen (dst
, src
))
1452 /* same depth (for core) */
1453 if (src
->depth
!= dst
->depth
)
1456 /* if Render is supported, match picture formats */
1457 if (src
->xrender_format
!= dst
->xrender_format
)
1459 else if (src
->xrender_format
!= NULL
)
1462 /* Without Render, match visuals instead */
1463 if (src
->visual
== dst
->visual
)
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)
1480 /* In the no-render case, we never have alpha */
1485 /* Returns true if the given operator and source-alpha combination
1486 * requires alpha compositing to complete.
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
)))
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.
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
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
)
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.
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
1575 if (!_cairo_matrix_is_integer_translation (&src_pattern
->matrix
, NULL
, NULL
) &&
1576 src_pattern
->extend
== CAIRO_EXTEND_REPEAT
)
1577 return DO_UNSUPPORTED
;
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
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
));
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))
1623 ! needs_alpha_composite
&&
1624 _surfaces_compatible (dst
, src
))
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
;
1642 _render_operator (cairo_operator_t op
)
1645 case CAIRO_OPERATOR_CLEAR
:
1648 case CAIRO_OPERATOR_SOURCE
:
1650 case CAIRO_OPERATOR_OVER
:
1652 case CAIRO_OPERATOR_IN
:
1654 case CAIRO_OPERATOR_OUT
:
1656 case CAIRO_OPERATOR_ATOP
:
1659 case CAIRO_OPERATOR_DEST
:
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
:
1672 case CAIRO_OPERATOR_ADD
:
1674 case CAIRO_OPERATOR_SATURATE
:
1675 return PictOpSaturate
;
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
,
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
;
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
,
1716 (cairo_surface_t
**) &src
,
1717 (cairo_surface_t
**) &mask
,
1718 &src_attr
, &mask_attr
);
1722 /* check for fallback surfaces that we cannot handle ... */
1723 if (!_cairo_surface_is_xlib (&src
->base
)) {
1724 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1728 (! _cairo_surface_is_xlib (&mask
->base
) ||
1729 ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst
)))
1731 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
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
;
1745 status
= _cairo_xlib_surface_set_attributes (src
, &src_attr
);
1749 _cairo_xlib_surface_ensure_dst_picture (dst
);
1751 status
= _cairo_xlib_surface_set_attributes (mask
, &mask_attr
);
1755 XRenderComposite (dst
->dpy
,
1756 _render_operator (op
),
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
,
1767 XRenderComposite (dst
->dpy
,
1768 _render_operator (op
),
1772 src_x
+ src_attr
.x_offset
,
1773 src_y
+ src_attr
.y_offset
,
1782 status
= _cairo_xlib_surface_ensure_gc (dst
);
1786 is_integer_translation
= _cairo_matrix_is_integer_translation (&src_attr
.matrix
,
1788 /* This is a pre-condition for DO_XCOPYAREA. */
1789 assert (is_integer_translation
);
1791 XCopyArea (dst
->dpy
,
1795 src_x
+ src_attr
.x_offset
+ itx
,
1796 src_y
+ src_attr
.y_offset
+ ity
,
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
);
1813 is_integer_translation
= _cairo_matrix_is_integer_translation (&src_attr
.matrix
,
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
);
1827 case DO_UNSUPPORTED
:
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,
1840 dst_x
, dst_y
, width
, height
);
1844 _cairo_pattern_release_surface (mask_pattern
, &mask
->base
, &mask_attr
);
1846 _cairo_pattern_release_surface (src_pattern
, &src
->base
, &src_attr
);
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
,
1857 cairo_status_t status
;
1858 cairo_solid_pattern_t solid
;
1859 cairo_surface_t
*solid_surface
= NULL
;
1860 cairo_surface_attributes_t attrs
;
1863 _cairo_pattern_init_solid (&solid
, color
, CAIRO_CONTENT_COLOR
);
1865 status
= _cairo_xlib_surface_ensure_gc (surface
);
1869 status
= _cairo_pattern_acquire_surface (&solid
.base
, &surface
->base
,
1871 ARRAY_LENGTH (dither_pattern
[0]),
1872 ARRAY_LENGTH (dither_pattern
),
1878 if (! _cairo_surface_is_xlib (solid_surface
)) {
1879 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
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
);
1897 _cairo_pattern_release_surface (&solid
.base
, solid_surface
, &attrs
);
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
,
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
;
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
,
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
));
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
)
1956 return CAIRO_STATUS_SUCCESS
;
1959 /* Creates an A8 picture of size @width x @height, initialized with @color
1962 _create_a8_picture (cairo_xlib_surface_t
*surface
,
1963 XRenderColor
*color
,
1966 cairo_bool_t repeat
)
1968 XRenderPictureAttributes pa
;
1969 unsigned long mask
= 0;
1973 XRenderPictFormat
*xrender_format
;
1975 if (width
> XLIB_COORD_MAX
|| height
> XLIB_COORD_MAX
)
1979 _cairo_xlib_display_get_xrender_format (surface
->display
,
1981 if (xrender_format
== NULL
)
1984 pixmap
= XCreatePixmap (surface
->dpy
, surface
->drawable
,
1985 width
<= 0 ? 1 : width
,
1986 height
<= 0 ? 1 : height
,
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
);
2003 /* Creates a temporary mask for the trapezoids covering the area
2004 * [@dst_x, @dst_y, @width, @height] of the destination surface.
2007 _create_trapezoid_mask (cairo_xlib_surface_t
*dst
,
2008 cairo_trapezoid_t
*traps
,
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
;
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
);
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
);
2060 XRenderCompositeTrapezoids (dst
->dpy
, PictOpAdd
,
2061 solid_picture
, mask_picture
,
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
,
2076 cairo_antialias_t antialias
,
2082 unsigned int height
,
2083 cairo_trapezoid_t
*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
,
2111 operation
= _recategorize_composite_operation (dst
, op
, src
,
2113 if (operation
== DO_UNSUPPORTED
) {
2114 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
2118 switch (antialias
) {
2119 case CAIRO_ANTIALIAS_NONE
:
2121 _cairo_xlib_display_get_xrender_format (dst
->display
,
2124 case CAIRO_ANTIALIAS_GRAY
:
2125 case CAIRO_ANTIALIAS_SUBPIXEL
:
2126 case CAIRO_ANTIALIAS_DEFAULT
:
2129 _cairo_xlib_display_get_xrender_format (dst
->display
,
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
);
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
);
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
,
2163 if (!mask_picture
) {
2164 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2168 XRenderComposite (dst
->dpy
,
2169 _render_operator (op
),
2173 src_x
+ attributes
.x_offset
,
2174 src_y
+ attributes
.y_offset
,
2179 XRenderFreePicture (dst
->dpy
, mask_picture
);
2181 status
= _cairo_surface_composite_shape_fixup_unbounded (&dst
->base
,
2182 &attributes
, src
->width
, src
->height
,
2186 dst_x
, dst_y
, width
, height
);
2189 XTrapezoid xtraps_stack
[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid
)];
2190 XTrapezoid
*xtraps
= xtraps_stack
;
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
);
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
,
2218 render_src_x
+ attributes
.x_offset
,
2219 render_src_y
+ attributes
.y_offset
,
2222 if (xtraps
!= xtraps_stack
)
2227 _cairo_pattern_release_surface (pattern
, &src
->base
, &attributes
);
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
;
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
);
2270 _cairo_region_fini (&bound
);
2271 _cairo_region_fini (&bounded
);
2275 status
= _cairo_region_get_boxes (&bounded
, &n_boxes
, &boxes
);
2277 _cairo_region_fini (&bound
);
2278 _cairo_region_fini (&bounded
);
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
);
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 */
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
)
2324 surface
->clip_dirty
= CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL
;
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
;
2339 rectangle
->width
= surface
->width
;
2340 rectangle
->height
= surface
->height
;
2342 return CAIRO_STATUS_SUCCESS
;
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
;
2355 _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t
*scaled_font
);
2358 _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t
*scaled_glyph
,
2359 cairo_scaled_font_t
*scaled_font
);
2362 _cairo_xlib_surface_is_similar (void *surface_a
,
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
))
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 (
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
);
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
,
2422 NULL
, /* mark_dirty_rectangle */
2423 _cairo_xlib_surface_scaled_font_fini
,
2424 _cairo_xlib_surface_scaled_glyph_fini
,
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
2447 _cairo_surface_is_xlib (cairo_surface_t
*surface
)
2449 return surface
->backend
== &cairo_xlib_surface_backend
;
2452 /* callback from CloseDisplay */
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
);
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
);
2486 static cairo_surface_t
*
2487 _cairo_xlib_surface_create_internal (Display
*dpy
,
2491 XRenderPictFormat
*xrender_format
,
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
) {
2509 /* This is ugly, but we have to walk over all visuals
2510 * for the display to find the correct depth.
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
) {
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
) {
2558 xrender_format
= XRenderFindVisualFormat (dpy
, visual
);
2559 } else if (depth
== 1) {
2561 _cairo_xlib_display_get_xrender_format (display
,
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
));
2579 surface
->display
= display
;
2580 surface
->screen_info
= screen_info
;
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
;
2636 surface
->a_mask
= (1 << depth
) - 1;
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
;
2648 _cairo_xlib_screen_from_visual (Display
*dpy
, Visual
*visual
)
2656 for (s
= 0; s
< ScreenCount (dpy
); s
++) {
2657 screen
= ScreenOfDisplay (dpy
, s
);
2658 if (visual
== DefaultVisualOfScreen (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
])
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
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
2696 cairo_xlib_surface_create (Display
*dpy
,
2702 Screen
*screen
= _cairo_xlib_screen_from_visual (dpy
, visual
);
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
2725 cairo_xlib_surface_create_for_bitmap (Display
*dpy
,
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
2754 * Return value: the newly created surface
2757 cairo_xlib_surface_create_with_xrender_format (Display
*dpy
,
2760 XRenderPictFormat
*format
,
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.
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
);
2794 return xlib_surface
->xrender_format
;
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.
2815 cairo_xlib_surface_set_size (cairo_surface_t
*abstract_surface
,
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
);
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
2846 cairo_xlib_surface_set_drawable (cairo_surface_t
*abstract_surface
,
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
);
2860 /* XXX: and what about this case? */
2861 if (surface
->owns_pixmap
)
2864 if (surface
->drawable
!= drawable
) {
2865 if (surface
->dst_picture
!= None
) {
2866 status
= _cairo_xlib_display_queue_resource (
2869 surface
->dst_picture
);
2871 status
= _cairo_surface_set_error (&surface
->base
, status
);
2875 surface
->dst_picture
= None
;
2878 if (surface
->src_picture
!= None
) {
2879 status
= _cairo_xlib_display_queue_resource (
2882 surface
->src_picture
);
2884 status
= _cairo_surface_set_error (&surface
->base
, status
);
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.
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
);
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.
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
);
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.
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
);
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.
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
);
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.
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
);
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.
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
);
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.
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
);
3055 return surface
->height
;
3059 GLYPHSET_INDEX_ARGB32
,
3065 typedef struct _cairo_xlib_font_glyphset_free_glyphs
{
3068 unsigned long glyph_indices
[128];
3069 } cairo_xlib_font_glyphset_free_glyphs_t
;
3071 typedef struct _cairo_xlib_font_glyphset_info
{
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 */
3087 _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t
*display
,
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
) {
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
;
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
];
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
;
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
;
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
);
3208 _cairo_xlib_render_free_glyphs (Display
*dpy
,
3209 cairo_xlib_font_glyphset_free_glyphs_t
*to_free
)
3211 XRenderFreeGlyphs (dpy
,
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
;
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
;
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
)
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
,
3254 /* XXX cannot propagate failure */
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
);
3279 _native_byte_order_lsb (void)
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
;
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
;
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
;
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]));
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
;
3350 font_private
= scaled_font
->surface_private
;
3351 if (font_private
== NULL
)
3354 if (surface
!= NULL
) {
3355 switch (surface
->format
) {
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
],
3366 return &font_private
->glyphset_info
[i
];
3369 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
3370 if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
3371 &font_private
->glyphset_info
[i
],
3374 return &font_private
->glyphset_info
[i
];
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
,
3408 CAIRO_SCALED_GLYPH_INFO_METRICS
|
3409 CAIRO_SCALED_GLYPH_INFO_SURFACE
,
3414 scaled_glyph
= *pscaled_glyph
;
3415 glyph_surface
= scaled_glyph
->surface
;
3416 already_had_glyph_surface
= FALSE
;
3418 already_had_glyph_surface
= TRUE
;
3421 if (scaled_font
->surface_private
== NULL
) {
3422 status
= _cairo_xlib_surface_font_init (dpy
, scaled_font
);
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
-
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) {
3446 cairo_surface_t
*tmp_surface
;
3448 tmp_surface
= cairo_image_surface_create (glyphset_info
->format
, 1, 1);
3449 status
= tmp_surface
->status
;
3453 cr
= cairo_create (tmp_surface
);
3454 cairo_set_operator (cr
, CAIRO_OPERATOR_CLEAR
);
3456 status
= cairo_status (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
;
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
3472 if (glyph_surface
->format
!= glyphset_info
->format
) {
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
;
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
);
3490 status
= cairo_status (cr
);
3493 glyph_surface
= (cairo_image_surface_t
*) tmp_surface
;
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
;
3516 unsigned char *new, *n
;
3520 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
3528 b
= ((b
<< 1) & 0xaa) | ((b
>> 1) & 0x55);
3529 b
= ((b
<< 2) & 0xcc) | ((b
>> 2) & 0x33);
3530 b
= ((b
<< 4) & 0xf0) | ((b
>> 4) & 0x0f);
3536 case CAIRO_FORMAT_A8
:
3538 case CAIRO_FORMAT_ARGB32
:
3539 if (_native_byte_order_lsb() != (ImageByteOrder (dpy
) == LSBFirst
)) {
3540 unsigned int c
= glyph_surface
->stride
* glyph_surface
->height
;
3542 unsigned char *new, *n
;
3546 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
3564 case CAIRO_FORMAT_RGB24
:
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,
3574 glyph_surface
->stride
* glyph_surface
->height
);
3576 if (data
!= glyph_surface
->data
)
3579 _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph
, glyphset_info
);
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
3591 if (!already_had_glyph_surface
)
3592 _cairo_scaled_glyph_set_surface (scaled_glyph
, scaled_font
, NULL
);
3597 typedef void (*cairo_xrender_composite_text_func_t
)
3602 _Xconst XRenderPictFormat
*maskFormat
,
3607 _Xconst XGlyphElt8
*elts
,
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. */
3615 unsigned long index
;
3617 unsigned long index
;
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
,
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 */
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
;
3654 /* Element buffer stuff */
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
;
3664 int nelt
; /* Element index */
3665 int n
; /* Num output glyphs in current element */
3666 int j
; /* Num output glyphs so far */
3670 /* don't cast the 8-variant, to catch possible mismatches */
3671 composite_text_func
= XRenderCompositeText8
;
3672 size
= sizeof (char);
3675 composite_text_func
= (cairo_xrender_composite_text_func_t
) XRenderCompositeText16
;
3676 size
= sizeof (unsigned short);
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
)) {
3688 elts
= _cairo_malloc_ab (num_elts
, sizeof (XGlyphElt8
));
3690 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
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
])) {
3707 elts
[nelt
].nchars
= n
;
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
;
3718 case 1: char8
[j
] = (char) glyphs
[i
].index
; break;
3719 case 2: char16
[j
] = (unsigned short) glyphs
[i
].index
; break;
3721 case 4: char32
[j
] = (unsigned int) glyphs
[i
].index
; break;
3729 elts
[nelt
].nchars
= n
;
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
),
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
)
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
,
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
)
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;
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
++) {
3793 status
= _cairo_scaled_glyph_lookup (scaled_font
,
3795 CAIRO_SCALED_GLYPH_INFO_METRICS
,
3797 if (status
!= CAIRO_STATUS_SUCCESS
)
3800 this_x
= _cairo_lround (glyphs
[i
].d
.x
);
3801 this_y
= _cairo_lround (glyphs
[i
].d
.y
);
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
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
3822 if (((this_x
+4096)|(this_y
+4096))&~0x3fffu
)
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
,
3831 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
)
3832 /* Break so we flush glyphs so far and let fallback code
3833 * handle the rest */
3840 this_glyphset_info
= _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph
);
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.
3850 /* Update max glyph index */
3851 if (glyphs
[i
].index
> max_index
) {
3852 max_index
= glyphs
[i
].index
;
3853 if (max_index
>= 65536)
3855 else if (max_index
>= 256)
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
)
3883 max_index
= glyphs
[i
].index
;
3884 width
= max_index
< 256 ? 1 : max_index
< 65536 ? 2 : 4;
3889 glyphset_info
= this_glyphset_info
;
3892 /* Convert absolute glyph position to relative-to-current-point
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
])) {
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
;
3913 request_size
+= width
;
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
;
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
))
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
,
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
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
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
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
,
4018 (cairo_surface_t
**) &src
,
4023 cairo_rectangle_int_t glyph_extents
;
4025 status
= _cairo_scaled_font_glyph_device_extents (scaled_font
,
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
,
4041 operation
= _recategorize_composite_operation (dst
, op
, src
,
4043 if (operation
== DO_UNSUPPORTED
) {
4044 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
4048 status
= _cairo_xlib_surface_set_attributes (src
, &attributes
);
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
,
4063 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
4064 _cairo_scaled_font_thaw_cache (scaled_font
);
4068 _cairo_pattern_release_surface (src_pattern
, &src
->base
, &attributes
);
4069 if (src_pattern
== &solid_pattern
.base
)
4070 _cairo_pattern_fini (&solid_pattern
.base
);
4072 _cairo_xlib_display_notify (dst
->display
);