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.
6 * Copyright © 2011 Intel Corporation
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
37 * Carl D. Worth <cworth@cworth.org>
38 * Behdad Esfahbod <behdad@behdad.org>
39 * Chris Wilson <chris@chris-wilson.co.uk>
40 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
45 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
47 #include "cairo-xlib-private.h"
49 #include "cairo-compositor-private.h"
50 #include "cairo-damage-private.h"
51 #include "cairo-image-surface-private.h"
52 #include "cairo-list-inline.h"
53 #include "cairo-pattern-private.h"
54 #include "cairo-pixman-private.h"
55 #include "cairo-traps-private.h"
56 #include "cairo-tristrip-private.h"
58 static cairo_int_status_t
59 check_composite (const cairo_composite_rectangles_t
*extents
)
61 cairo_xlib_display_t
*display
= ((cairo_xlib_surface_t
*)extents
->surface
)->display
;
63 if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display
, extents
->op
))
64 return CAIRO_INT_STATUS_UNSUPPORTED
;
66 return CAIRO_STATUS_SUCCESS
;
69 static cairo_int_status_t
70 acquire (void *abstract_dst
)
72 cairo_xlib_surface_t
*dst
= abstract_dst
;
73 cairo_int_status_t status
;
75 status
= _cairo_xlib_display_acquire (dst
->base
.device
, &dst
->display
);
76 if (unlikely (status
))
79 dst
->dpy
= dst
->display
->display
;
80 return CAIRO_STATUS_SUCCESS
;
83 static cairo_int_status_t
84 release (void *abstract_dst
)
86 cairo_xlib_surface_t
*dst
= abstract_dst
;
88 cairo_device_release (&dst
->display
->base
);
91 return CAIRO_STATUS_SUCCESS
;
94 static cairo_int_status_t
95 set_clip_region (void *_surface
,
96 cairo_region_t
*region
)
98 cairo_xlib_surface_t
*surface
= _surface
;
100 _cairo_xlib_surface_ensure_picture (surface
);
102 if (region
!= NULL
) {
103 XRectangle stack_rects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
104 XRectangle
*rects
= stack_rects
;
107 n_rects
= cairo_region_num_rectangles (region
);
108 if (n_rects
> ARRAY_LENGTH (stack_rects
)) {
109 rects
= _cairo_malloc_ab (n_rects
, sizeof (XRectangle
));
110 if (unlikely (rects
== NULL
))
111 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
113 for (i
= 0; i
< n_rects
; i
++) {
114 cairo_rectangle_int_t rect
;
116 cairo_region_get_rectangle (region
, i
, &rect
);
120 rects
[i
].width
= rect
.width
;
121 rects
[i
].height
= rect
.height
;
123 XRenderSetPictureClipRectangles (surface
->dpy
,
127 if (rects
!= stack_rects
)
130 XRenderPictureAttributes pa
;
132 XRenderChangePicture (surface
->dpy
,
137 return CAIRO_STATUS_SUCCESS
;
140 static cairo_int_status_t
141 copy_image_boxes (void *_dst
,
142 cairo_image_surface_t
*image
,
143 cairo_boxes_t
*boxes
,
146 cairo_xlib_surface_t
*dst
= _dst
;
147 struct _cairo_boxes_chunk
*chunk
;
148 cairo_int_status_t status
;
153 assert (image
->depth
== dst
->depth
);
155 status
= acquire (dst
);
156 if (unlikely (status
))
159 status
= _cairo_xlib_surface_get_gc (dst
->display
, dst
, &gc
);
160 if (unlikely (status
)) {
165 src
= _cairo_xlib_shm_surface_get_pixmap (&image
->base
);
166 if (boxes
->num_boxes
== 1) {
167 int x1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.x
);
168 int y1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.y
);
169 int x2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.x
);
170 int y2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.y
);
172 _cairo_xlib_shm_surface_mark_active (&image
->base
);
173 XCopyArea (dst
->dpy
, src
, dst
->drawable
, gc
,
178 XRectangle stack_rects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
179 XRectangle
*rects
= stack_rects
;
181 if (boxes
->num_boxes
> ARRAY_LENGTH (stack_rects
)) {
182 rects
= _cairo_malloc_ab (boxes
->num_boxes
, sizeof (XRectangle
));
183 if (unlikely (rects
== NULL
))
184 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
188 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
189 for (i
= 0; i
< chunk
->count
; i
++) {
190 int x1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.x
);
191 int y1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.y
);
192 int x2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.x
);
193 int y2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.y
);
195 if (x2
> x1
&& y2
> y1
) {
198 rects
[j
].width
= x2
- x1
;
199 rects
[j
].height
= y2
- y1
;
205 XSetClipRectangles (dst
->dpy
, gc
, 0, 0, rects
, j
, Unsorted
);
206 _cairo_xlib_shm_surface_mark_active (&image
->base
);
207 XCopyArea (dst
->dpy
, src
, dst
->drawable
, gc
,
208 0, 0, image
->width
, image
->height
, -dx
, -dy
);
209 XSetClipMask (dst
->dpy
, gc
, None
);
211 if (rects
!= stack_rects
)
215 _cairo_xlib_surface_put_gc (dst
->display
, dst
, gc
);
217 return CAIRO_STATUS_SUCCESS
;
221 boxes_cover_surface (cairo_boxes_t
*boxes
,
222 cairo_xlib_surface_t
*surface
)
226 if (boxes
->num_boxes
!= 1)
229 b
= &boxes
->chunks
.base
[0];
231 if (_cairo_fixed_integer_part (b
->p1
.x
) > 0 ||
232 _cairo_fixed_integer_part (b
->p1
.y
) > 0)
235 if (_cairo_fixed_integer_part (b
->p2
.x
) < surface
->width
||
236 _cairo_fixed_integer_part (b
->p2
.y
) < surface
->height
)
242 static cairo_int_status_t
243 draw_image_boxes (void *_dst
,
244 cairo_image_surface_t
*image
,
245 cairo_boxes_t
*boxes
,
248 cairo_xlib_surface_t
*dst
= _dst
;
249 struct _cairo_boxes_chunk
*chunk
;
250 cairo_image_surface_t
*shm
= NULL
;
251 cairo_int_status_t status
;
254 if (image
->base
.device
== dst
->base
.device
) {
255 if (image
->depth
!= dst
->depth
)
256 return CAIRO_INT_STATUS_UNSUPPORTED
;
258 if (_cairo_xlib_shm_surface_get_pixmap (&image
->base
))
259 return copy_image_boxes (dst
, image
, boxes
, dx
, dy
);
261 goto draw_image_boxes
;
264 if (boxes_cover_surface (boxes
, dst
))
265 shm
= (cairo_image_surface_t
*) _cairo_xlib_surface_get_shm (dst
, TRUE
);
267 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
268 for (i
= 0; i
< chunk
->count
; i
++) {
269 cairo_box_t
*b
= &chunk
->base
[i
];
270 cairo_rectangle_int_t r
;
272 r
.x
= _cairo_fixed_integer_part (b
->p1
.x
);
273 r
.y
= _cairo_fixed_integer_part (b
->p1
.y
);
274 r
.width
= _cairo_fixed_integer_part (b
->p2
.x
) - r
.x
;
275 r
.height
= _cairo_fixed_integer_part (b
->p2
.y
) - r
.y
;
277 if (shm
->pixman_format
!= image
->pixman_format
||
278 ! pixman_blt ((uint32_t *)image
->data
, (uint32_t *)shm
->data
,
279 image
->stride
/ sizeof (uint32_t),
280 shm
->stride
/ sizeof (uint32_t),
281 PIXMAN_FORMAT_BPP (image
->pixman_format
),
282 PIXMAN_FORMAT_BPP (shm
->pixman_format
),
287 pixman_image_composite32 (PIXMAN_OP_SRC
,
288 image
->pixman_image
, NULL
, shm
->pixman_image
,
296 _cairo_damage_add_rectangle (shm
->base
.damage
, &r
);
299 dst
->base
.is_clear
= FALSE
;
302 return CAIRO_INT_STATUS_NOTHING_TO_DO
;
305 if (image
->depth
== dst
->depth
&&
306 ((cairo_xlib_display_t
*)dst
->display
)->shm
) {
308 cairo_rectangle_int_t r
;
310 _cairo_boxes_extents (boxes
, &extents
);
311 _cairo_box_round_to_rectangle (&extents
, &r
);
313 shm
= (cairo_image_surface_t
*)
314 _cairo_xlib_surface_create_shm (dst
, image
->pixman_format
,
317 int tx
= -r
.x
, ty
= -r
.y
;
319 assert (shm
->pixman_format
== image
->pixman_format
);
320 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
321 for (i
= 0; i
< chunk
->count
; i
++) {
322 cairo_box_t
*b
= &chunk
->base
[i
];
324 r
.x
= _cairo_fixed_integer_part (b
->p1
.x
);
325 r
.y
= _cairo_fixed_integer_part (b
->p1
.y
);
326 r
.width
= _cairo_fixed_integer_part (b
->p2
.x
) - r
.x
;
327 r
.height
= _cairo_fixed_integer_part (b
->p2
.y
) - r
.y
;
329 if (! pixman_blt ((uint32_t *)image
->data
, (uint32_t *)shm
->data
,
330 image
->stride
/ sizeof (uint32_t),
331 shm
->stride
/ sizeof (uint32_t),
332 PIXMAN_FORMAT_BPP (image
->pixman_format
),
333 PIXMAN_FORMAT_BPP (shm
->pixman_format
),
338 pixman_image_composite32 (PIXMAN_OP_SRC
,
339 image
->pixman_image
, NULL
, shm
->pixman_image
,
352 if (_cairo_xlib_shm_surface_get_pixmap (&image
->base
)) {
353 status
= copy_image_boxes (dst
, image
, boxes
, dx
, dy
);
354 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
361 status
= CAIRO_STATUS_SUCCESS
;
362 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
363 for (i
= 0; i
< chunk
->count
; i
++) {
364 cairo_box_t
*b
= &chunk
->base
[i
];
365 int x1
= _cairo_fixed_integer_part (b
->p1
.x
);
366 int y1
= _cairo_fixed_integer_part (b
->p1
.y
);
367 int x2
= _cairo_fixed_integer_part (b
->p2
.x
);
368 int y2
= _cairo_fixed_integer_part (b
->p2
.y
);
369 if (_cairo_xlib_surface_draw_image (dst
, image
,
373 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
380 cairo_surface_destroy (&shm
->base
);
384 static cairo_int_status_t
385 copy_boxes (void *_dst
,
386 cairo_surface_t
*_src
,
387 cairo_boxes_t
*boxes
,
388 const cairo_rectangle_int_t
*extents
,
391 cairo_xlib_surface_t
*dst
= _dst
;
392 cairo_xlib_surface_t
*src
= (cairo_xlib_surface_t
*)_src
;
393 struct _cairo_boxes_chunk
*chunk
;
394 cairo_int_status_t status
;
399 if (! _cairo_xlib_surface_same_screen (dst
, src
))
400 return CAIRO_INT_STATUS_UNSUPPORTED
;
402 if (dst
->depth
!= src
->depth
)
403 return CAIRO_INT_STATUS_UNSUPPORTED
;
405 status
= acquire (dst
);
406 if (unlikely (status
))
409 status
= _cairo_xlib_surface_get_gc (dst
->display
, dst
, &gc
);
410 if (unlikely (status
)) {
415 if (src
->fallback
&& src
->shm
->damage
->dirty
) {
417 d
= _cairo_xlib_shm_surface_get_pixmap (src
->shm
);
420 if (! src
->owns_pixmap
) {
423 gcv
.subwindow_mode
= IncludeInferiors
;
424 XChangeGC (dst
->display
->display
, gc
, GCSubwindowMode
, &gcv
);
429 if (boxes
->num_boxes
== 1) {
430 int x1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.x
);
431 int y1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.y
);
432 int x2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.x
);
433 int y2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.y
);
435 XCopyArea (dst
->dpy
, d
, dst
->drawable
, gc
,
440 /* We can only have a single control for subwindow_mode on the
441 * GC. If we have a Window destination, we need to set ClipByChildren,
442 * but if we have a Window source, we need IncludeInferiors. If we have
443 * both a Window destination and source, we must fallback. There is
444 * no convenient way to detect if a drawable is a Pixmap or Window,
445 * therefore we can only rely on those surfaces that we created
446 * ourselves to be Pixmaps, and treat everything else as a potential
449 if (src
== dst
|| (!src
->owns_pixmap
&& !dst
->owns_pixmap
)) {
450 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
451 for (i
= 0; i
< chunk
->count
; i
++) {
452 int x1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.x
);
453 int y1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.y
);
454 int x2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.x
);
455 int y2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.y
);
456 XCopyArea (dst
->dpy
, d
, dst
->drawable
, gc
,
463 XRectangle stack_rects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
464 XRectangle
*rects
= stack_rects
;
466 if (boxes
->num_boxes
> ARRAY_LENGTH (stack_rects
)) {
467 rects
= _cairo_malloc_ab (boxes
->num_boxes
, sizeof (XRectangle
));
468 if (unlikely (rects
== NULL
))
469 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
473 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
474 for (i
= 0; i
< chunk
->count
; i
++) {
475 int x1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.x
);
476 int y1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.y
);
477 int x2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.x
);
478 int y2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.y
);
482 rects
[j
].width
= x2
- x1
;
483 rects
[j
].height
= y2
- y1
;
487 assert (j
== boxes
->num_boxes
);
489 XSetClipRectangles (dst
->dpy
, gc
, 0, 0, rects
, j
, Unsorted
);
491 XCopyArea (dst
->dpy
, d
, dst
->drawable
, gc
,
492 extents
->x
+ dx
, extents
->y
+ dy
,
493 extents
->width
, extents
->height
,
494 extents
->x
, extents
->y
);
496 XSetClipMask (dst
->dpy
, gc
, None
);
498 if (rects
!= stack_rects
)
503 if (src
->fallback
&& src
->shm
->damage
->dirty
) {
504 _cairo_xlib_shm_surface_mark_active (src
->shm
);
505 } else if (! src
->owns_pixmap
) {
508 gcv
.subwindow_mode
= ClipByChildren
;
509 XChangeGC (dst
->display
->display
, gc
, GCSubwindowMode
, &gcv
);
512 _cairo_xlib_surface_put_gc (dst
->display
, dst
, gc
);
514 return CAIRO_STATUS_SUCCESS
;
518 _render_operator (cairo_operator_t op
)
521 case CAIRO_OPERATOR_CLEAR
:
524 case CAIRO_OPERATOR_SOURCE
:
526 case CAIRO_OPERATOR_OVER
:
528 case CAIRO_OPERATOR_IN
:
530 case CAIRO_OPERATOR_OUT
:
532 case CAIRO_OPERATOR_ATOP
:
535 case CAIRO_OPERATOR_DEST
:
537 case CAIRO_OPERATOR_DEST_OVER
:
538 return PictOpOverReverse
;
539 case CAIRO_OPERATOR_DEST_IN
:
540 return PictOpInReverse
;
541 case CAIRO_OPERATOR_DEST_OUT
:
542 return PictOpOutReverse
;
543 case CAIRO_OPERATOR_DEST_ATOP
:
544 return PictOpAtopReverse
;
546 case CAIRO_OPERATOR_XOR
:
548 case CAIRO_OPERATOR_ADD
:
550 case CAIRO_OPERATOR_SATURATE
:
551 return PictOpSaturate
;
553 case CAIRO_OPERATOR_MULTIPLY
:
554 return PictOpMultiply
;
555 case CAIRO_OPERATOR_SCREEN
:
557 case CAIRO_OPERATOR_OVERLAY
:
558 return PictOpOverlay
;
559 case CAIRO_OPERATOR_DARKEN
:
561 case CAIRO_OPERATOR_LIGHTEN
:
562 return PictOpLighten
;
563 case CAIRO_OPERATOR_COLOR_DODGE
:
564 return PictOpColorDodge
;
565 case CAIRO_OPERATOR_COLOR_BURN
:
566 return PictOpColorBurn
;
567 case CAIRO_OPERATOR_HARD_LIGHT
:
568 return PictOpHardLight
;
569 case CAIRO_OPERATOR_SOFT_LIGHT
:
570 return PictOpSoftLight
;
571 case CAIRO_OPERATOR_DIFFERENCE
:
572 return PictOpDifference
;
573 case CAIRO_OPERATOR_EXCLUSION
:
574 return PictOpExclusion
;
575 case CAIRO_OPERATOR_HSL_HUE
:
577 case CAIRO_OPERATOR_HSL_SATURATION
:
578 return PictOpHSLSaturation
;
579 case CAIRO_OPERATOR_HSL_COLOR
:
580 return PictOpHSLColor
;
581 case CAIRO_OPERATOR_HSL_LUMINOSITY
:
582 return PictOpHSLLuminosity
;
591 fill_reduces_to_source (cairo_operator_t op
,
592 const cairo_color_t
*color
,
593 cairo_xlib_surface_t
*dst
)
595 if (dst
->base
.is_clear
|| CAIRO_COLOR_IS_OPAQUE (color
)) {
596 if (op
== CAIRO_OPERATOR_OVER
)
598 if (op
== CAIRO_OPERATOR_ADD
)
599 return (dst
->base
.content
& CAIRO_CONTENT_COLOR
) == 0;
605 static cairo_int_status_t
606 fill_rectangles (void *abstract_surface
,
608 const cairo_color_t
*color
,
609 cairo_rectangle_int_t
*rects
,
612 cairo_xlib_surface_t
*dst
= abstract_surface
;
613 XRenderColor render_color
;
616 //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
618 if (fill_reduces_to_source (op
, color
, dst
))
619 op
= CAIRO_OPERATOR_SOURCE
;
621 if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst
->display
)) {
622 cairo_int_status_t status
;
624 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
625 if (op
== CAIRO_OPERATOR_SOURCE
)
626 status
= _cairo_xlib_core_fill_rectangles (dst
, color
, num_rects
, rects
);
630 render_color
.red
= color
->red_short
;
631 render_color
.green
= color
->green_short
;
632 render_color
.blue
= color
->blue_short
;
633 render_color
.alpha
= color
->alpha_short
;
635 _cairo_xlib_surface_ensure_picture (dst
);
636 if (num_rects
== 1) {
637 /* Take advantage of the protocol compaction that libXrender performs
638 * to amalgamate sequences of XRenderFillRectangle().
640 XRenderFillRectangle (dst
->dpy
,
641 _render_operator (op
),
645 rects
->width
, rects
->height
);
647 XRectangle stack_xrects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
648 XRectangle
*xrects
= stack_xrects
;
650 if (num_rects
> ARRAY_LENGTH (stack_xrects
)) {
651 xrects
= _cairo_malloc_ab (num_rects
, sizeof (XRectangle
));
652 if (unlikely (xrects
== NULL
))
653 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
656 for (i
= 0; i
< num_rects
; i
++) {
657 xrects
[i
].x
= rects
[i
].x
;
658 xrects
[i
].y
= rects
[i
].y
;
659 xrects
[i
].width
= rects
[i
].width
;
660 xrects
[i
].height
= rects
[i
].height
;
663 XRenderFillRectangles (dst
->dpy
,
664 _render_operator (op
),
666 &render_color
, xrects
, num_rects
);
668 if (xrects
!= stack_xrects
)
672 return CAIRO_STATUS_SUCCESS
;
675 static cairo_int_status_t
676 fill_boxes (void *abstract_surface
,
678 const cairo_color_t
*color
,
679 cairo_boxes_t
*boxes
)
681 cairo_xlib_surface_t
*dst
= abstract_surface
;
682 XRenderColor render_color
;
684 if (fill_reduces_to_source (op
, color
, dst
))
685 op
= CAIRO_OPERATOR_SOURCE
;
687 if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst
->display
)) {
688 cairo_int_status_t status
;
690 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
691 if (op
== CAIRO_OPERATOR_SOURCE
)
692 status
= _cairo_xlib_core_fill_boxes (dst
, color
, boxes
);
696 render_color
.red
= color
->red_short
;
697 render_color
.green
= color
->green_short
;
698 render_color
.blue
= color
->blue_short
;
699 render_color
.alpha
= color
->alpha_short
;
701 _cairo_xlib_surface_ensure_picture (dst
);
702 if (boxes
->num_boxes
== 1) {
703 int x1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.x
);
704 int y1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.y
);
705 int x2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.x
);
706 int y2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.y
);
708 /* Take advantage of the protocol compaction that libXrender performs
709 * to amalgamate sequences of XRenderFillRectangle().
711 XRenderFillRectangle (dst
->dpy
,
712 _render_operator (op
),
718 XRectangle stack_xrects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
719 XRectangle
*xrects
= stack_xrects
;
720 struct _cairo_boxes_chunk
*chunk
;
723 if (boxes
->num_boxes
> ARRAY_LENGTH (stack_xrects
)) {
724 xrects
= _cairo_malloc_ab (boxes
->num_boxes
, sizeof (XRectangle
));
725 if (unlikely (xrects
== NULL
))
726 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
730 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
731 for (i
= 0; i
< chunk
->count
; i
++) {
732 int x1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.x
);
733 int y1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.y
);
734 int x2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.x
);
735 int y2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.y
);
739 xrects
[j
].width
= x2
- x1
;
740 xrects
[j
].height
= y2
- y1
;
745 XRenderFillRectangles (dst
->dpy
,
746 _render_operator (op
),
748 &render_color
, xrects
, j
);
750 if (xrects
!= stack_xrects
)
754 return CAIRO_STATUS_SUCCESS
;
759 operation
= _categorize_composite_operation (dst
, op
, src_pattern
,
760 mask_pattern
!= NULL
);
761 if (operation
== DO_UNSUPPORTED
)
762 return UNSUPPORTED ("unsupported operation");
764 //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
766 operation
= _recategorize_composite_operation (dst
, op
, src
, &src_attr
,
767 mask_pattern
!= NULL
);
768 if (operation
== DO_UNSUPPORTED
) {
769 status
= UNSUPPORTED ("unsupported operation");
774 static cairo_int_status_t
775 composite (void *abstract_dst
,
777 cairo_surface_t
*abstract_src
,
778 cairo_surface_t
*abstract_mask
,
788 cairo_xlib_surface_t
*dst
= abstract_dst
;
789 cairo_xlib_source_t
*src
= (cairo_xlib_source_t
*)abstract_src
;
791 op
= _render_operator (op
);
793 _cairo_xlib_surface_ensure_picture (dst
);
795 cairo_xlib_source_t
*mask
= (cairo_xlib_source_t
*)abstract_mask
;
797 XRenderComposite (dst
->dpy
, op
,
798 src
->picture
, mask
->picture
, dst
->picture
,
804 XRenderComposite (dst
->dpy
, op
,
805 src
->picture
, 0, dst
->picture
,
812 return CAIRO_STATUS_SUCCESS
;
815 static cairo_int_status_t
816 lerp (void *abstract_dst
,
817 cairo_surface_t
*abstract_src
,
818 cairo_surface_t
*abstract_mask
,
828 cairo_xlib_surface_t
*dst
= abstract_dst
;
829 cairo_xlib_source_t
*src
= (cairo_xlib_source_t
*)abstract_src
;
830 cairo_xlib_source_t
*mask
= (cairo_xlib_source_t
*)abstract_mask
;
832 _cairo_xlib_surface_ensure_picture (dst
);
833 XRenderComposite (dst
->dpy
, PictOpOutReverse
,
834 mask
->picture
, None
, dst
->picture
,
839 XRenderComposite (dst
->dpy
, PictOpAdd
,
840 src
->picture
, mask
->picture
, dst
->picture
,
846 return CAIRO_STATUS_SUCCESS
;
849 static cairo_int_status_t
850 composite_boxes (void *abstract_dst
,
852 cairo_surface_t
*abstract_src
,
853 cairo_surface_t
*abstract_mask
,
860 cairo_boxes_t
*boxes
,
861 const cairo_rectangle_int_t
*extents
)
863 cairo_xlib_surface_t
*dst
= abstract_dst
;
864 Picture src
= ((cairo_xlib_source_t
*)abstract_src
)->picture
;
865 Picture mask
= abstract_mask
? ((cairo_xlib_source_t
*)abstract_mask
)->picture
: 0;
866 XRectangle stack_rects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
867 XRectangle
*rects
= stack_rects
;
868 struct _cairo_boxes_chunk
*chunk
;
871 op
= _render_operator (op
);
872 _cairo_xlib_surface_ensure_picture (dst
);
873 if (boxes
->num_boxes
== 1) {
874 int x1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.x
);
875 int y1
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p1
.y
);
876 int x2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.x
);
877 int y2
= _cairo_fixed_integer_part (boxes
->chunks
.base
[0].p2
.y
);
879 XRenderComposite (dst
->dpy
, op
,
880 src
, mask
, dst
->picture
,
881 x1
+ src_x
, y1
+ src_y
,
882 x1
+ mask_x
, y1
+ mask_y
,
883 x1
- dst_x
, y1
- dst_y
,
885 return CAIRO_STATUS_SUCCESS
;
888 if (boxes
->num_boxes
> ARRAY_LENGTH (stack_rects
)) {
889 rects
= _cairo_malloc_ab (boxes
->num_boxes
, sizeof (XRectangle
));
890 if (unlikely (rects
== NULL
))
891 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
895 for (chunk
= &boxes
->chunks
; chunk
; chunk
= chunk
->next
) {
896 for (i
= 0; i
< chunk
->count
; i
++) {
897 int x1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.x
);
898 int y1
= _cairo_fixed_integer_part (chunk
->base
[i
].p1
.y
);
899 int x2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.x
);
900 int y2
= _cairo_fixed_integer_part (chunk
->base
[i
].p2
.y
);
902 rects
[j
].x
= x1
- dst_x
;
903 rects
[j
].y
= y1
- dst_y
;
904 rects
[j
].width
= x2
- x1
;
905 rects
[j
].height
= y2
- y1
;
909 assert (j
== boxes
->num_boxes
);
911 XRenderSetPictureClipRectangles (dst
->dpy
,
915 if (rects
!= stack_rects
)
918 XRenderComposite (dst
->dpy
, op
,
919 src
, mask
, dst
->picture
,
920 extents
->x
+ src_x
, extents
->y
+ src_y
,
921 extents
->x
+ mask_x
, extents
->y
+ mask_y
,
922 extents
->x
- dst_x
, extents
->y
- dst_y
,
923 extents
->width
, extents
->height
);
925 set_clip_region (dst
, NULL
);
927 return CAIRO_STATUS_SUCCESS
;
933 _cairo_xlib_font_close (cairo_xlib_font_t
*priv
)
935 cairo_xlib_display_t
*display
= (cairo_xlib_display_t
*)priv
->base
.key
;
938 /* XXX All I really want is to do is zap my glyphs... */
939 _cairo_scaled_font_reset_cache (priv
->font
);
941 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
942 cairo_xlib_font_glyphset_t
*info
;
944 info
= &priv
->glyphset
[i
];
946 XRenderFreeGlyphSet (display
->display
, info
->glyphset
);
950 cairo_list_del (&priv
->link
);
951 cairo_list_del (&priv
->base
.link
);
956 _cairo_xlib_font_fini (cairo_scaled_font_private_t
*abstract_private
,
957 cairo_scaled_font_t
*font
)
959 cairo_xlib_font_t
*priv
= (cairo_xlib_font_t
*) abstract_private
;
960 cairo_status_t status
;
961 cairo_xlib_display_t
*display
;
964 cairo_list_del (&priv
->base
.link
);
965 cairo_list_del (&priv
->link
);
967 status
= _cairo_xlib_display_acquire (priv
->device
, &display
);
971 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
972 cairo_xlib_font_glyphset_t
*info
;
974 info
= &priv
->glyphset
[i
];
976 XRenderFreeGlyphSet (display
->display
, info
->glyphset
);
979 cairo_device_release (&display
->base
);
981 cairo_device_destroy (&display
->base
);
985 static cairo_xlib_font_t
*
986 _cairo_xlib_font_create (cairo_xlib_display_t
*display
,
987 cairo_scaled_font_t
*font
)
989 cairo_xlib_font_t
*priv
;
992 priv
= malloc (sizeof (cairo_xlib_font_t
));
993 if (unlikely (priv
== NULL
))
996 _cairo_scaled_font_attach_private (font
, &priv
->base
, display
,
997 _cairo_xlib_font_fini
);
999 priv
->device
= cairo_device_reference (&display
->base
);
1001 cairo_list_add (&priv
->link
, &display
->fonts
);
1003 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
1004 cairo_xlib_font_glyphset_t
*info
= &priv
->glyphset
[i
];
1006 case GLYPHSET_INDEX_ARGB32
: info
->format
= CAIRO_FORMAT_ARGB32
; break;
1007 case GLYPHSET_INDEX_A8
: info
->format
= CAIRO_FORMAT_A8
; break;
1008 case GLYPHSET_INDEX_A1
: info
->format
= CAIRO_FORMAT_A1
; break;
1009 default: ASSERT_NOT_REACHED
; break;
1011 info
->xrender_format
= NULL
;
1012 info
->glyphset
= None
;
1013 info
->to_free
.count
= 0;
1020 _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format
)
1022 if (format
== CAIRO_FORMAT_A8
)
1023 return GLYPHSET_INDEX_A8
;
1024 if (format
== CAIRO_FORMAT_A1
)
1025 return GLYPHSET_INDEX_A1
;
1027 assert (format
== CAIRO_FORMAT_ARGB32
);
1028 return GLYPHSET_INDEX_ARGB32
;
1031 static inline cairo_xlib_font_t
*
1032 _cairo_xlib_font_get (const cairo_xlib_display_t
*display
,
1033 cairo_scaled_font_t
*font
)
1035 return (cairo_xlib_font_t
*)_cairo_scaled_font_find_private (font
, display
);
1039 cairo_scaled_glyph_private_t base
;
1042 cairo_xlib_font_glyphset_t
*glyphset
;
1043 } cairo_xlib_glyph_private_t
;
1046 _cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t
*glyph_private
,
1047 cairo_scaled_glyph_t
*glyph
,
1048 cairo_scaled_font_t
*font
)
1050 cairo_xlib_glyph_private_t
*priv
= (cairo_xlib_glyph_private_t
*)glyph_private
;
1052 if (! font
->finished
) {
1053 cairo_xlib_font_t
*font_private
;
1054 struct _cairo_xlib_font_glyphset_free_glyphs
*to_free
;
1055 cairo_xlib_font_glyphset_t
*info
;
1057 font_private
= _cairo_xlib_font_get (glyph_private
->key
, font
);
1058 assert (font_private
);
1060 info
= priv
->glyphset
;
1061 to_free
= &info
->to_free
;
1062 if (to_free
->count
== ARRAY_LENGTH (to_free
->indices
)) {
1063 cairo_xlib_display_t
*display
;
1065 if (_cairo_xlib_display_acquire (font_private
->device
,
1066 &display
) == CAIRO_STATUS_SUCCESS
) {
1067 XRenderFreeGlyphs (display
->display
,
1071 cairo_device_release (&display
->base
);
1077 to_free
->indices
[to_free
->count
++] =
1078 _cairo_scaled_glyph_index (glyph
);
1081 cairo_list_del (&glyph_private
->link
);
1082 free (glyph_private
);
1085 static cairo_status_t
1086 _cairo_xlib_glyph_attach (cairo_xlib_display_t
*display
,
1087 cairo_scaled_glyph_t
*glyph
,
1088 cairo_xlib_font_glyphset_t
*info
)
1090 cairo_xlib_glyph_private_t
*priv
;
1092 priv
= malloc (sizeof (*priv
));
1093 if (unlikely (priv
== NULL
))
1094 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1096 _cairo_scaled_glyph_attach_private (glyph
, &priv
->base
, display
,
1097 _cairo_xlib_glyph_fini
);
1098 priv
->glyphset
= info
;
1100 glyph
->dev_private
= info
;
1101 glyph
->dev_private_key
= display
;
1102 return CAIRO_STATUS_SUCCESS
;
1105 static cairo_xlib_font_glyphset_t
*
1106 _cairo_xlib_font_get_glyphset_info_for_format (cairo_xlib_display_t
*display
,
1107 cairo_scaled_font_t
*font
,
1108 cairo_format_t format
)
1110 cairo_xlib_font_t
*priv
;
1111 cairo_xlib_font_glyphset_t
*info
;
1114 glyphset_index
= _cairo_xlib_get_glyphset_index_for_format (format
);
1116 priv
= _cairo_xlib_font_get (display
, font
);
1118 priv
= _cairo_xlib_font_create (display
, font
);
1123 info
= &priv
->glyphset
[glyphset_index
];
1124 if (info
->glyphset
== None
) {
1125 info
->xrender_format
=
1126 _cairo_xlib_display_get_xrender_format (display
, info
->format
);
1127 info
->glyphset
= XRenderCreateGlyphSet (display
->display
,
1128 info
->xrender_format
);
1135 has_pending_free_glyph (cairo_xlib_font_glyphset_t
*info
,
1136 unsigned long glyph_index
)
1138 struct _cairo_xlib_font_glyphset_free_glyphs
*to_free
;
1141 to_free
= &info
->to_free
;
1142 for (i
= 0; i
< to_free
->count
; i
++) {
1143 if (to_free
->indices
[i
] == glyph_index
) {
1145 memmove (&to_free
->indices
[i
],
1146 &to_free
->indices
[i
+1],
1147 (to_free
->count
- i
) * sizeof (to_free
->indices
[0]));
1155 static cairo_xlib_font_glyphset_t
*
1156 find_pending_free_glyph (cairo_xlib_display_t
*display
,
1157 cairo_scaled_font_t
*font
,
1158 unsigned long glyph_index
,
1159 cairo_image_surface_t
*surface
)
1161 cairo_xlib_font_t
*priv
;
1164 priv
= _cairo_xlib_font_get (display
, font
);
1168 if (surface
!= NULL
) {
1169 i
= _cairo_xlib_get_glyphset_index_for_format (surface
->format
);
1170 if (has_pending_free_glyph (&priv
->glyphset
[i
], glyph_index
))
1171 return &priv
->glyphset
[i
];
1173 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
1174 if (has_pending_free_glyph (&priv
->glyphset
[i
], glyph_index
))
1175 return &priv
->glyphset
[i
];
1182 static cairo_status_t
1183 _cairo_xlib_surface_add_glyph (cairo_xlib_display_t
*display
,
1184 cairo_scaled_font_t
*font
,
1185 cairo_scaled_glyph_t
**pscaled_glyph
)
1187 XGlyphInfo glyph_info
;
1188 unsigned long glyph_index
;
1189 unsigned char *data
;
1190 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1191 cairo_scaled_glyph_t
*glyph
= *pscaled_glyph
;
1192 cairo_image_surface_t
*glyph_surface
= glyph
->surface
;
1193 cairo_bool_t already_had_glyph_surface
;
1194 cairo_xlib_font_glyphset_t
*info
;
1196 glyph_index
= _cairo_scaled_glyph_index (glyph
);
1198 /* check to see if we have a pending XRenderFreeGlyph for this glyph */
1199 info
= find_pending_free_glyph (display
, font
, glyph_index
, glyph_surface
);
1201 return _cairo_xlib_glyph_attach (display
, glyph
, info
);
1203 if (glyph_surface
== NULL
) {
1204 status
= _cairo_scaled_glyph_lookup (font
,
1206 CAIRO_SCALED_GLYPH_INFO_METRICS
|
1207 CAIRO_SCALED_GLYPH_INFO_SURFACE
,
1209 if (unlikely (status
))
1212 glyph
= *pscaled_glyph
;
1213 glyph_surface
= glyph
->surface
;
1214 already_had_glyph_surface
= FALSE
;
1216 already_had_glyph_surface
= TRUE
;
1219 info
= _cairo_xlib_font_get_glyphset_info_for_format (display
, font
,
1220 glyph_surface
->format
);
1223 /* If the glyph surface has zero height or width, we create
1224 * a clear 1x1 surface, to avoid various X server bugs.
1226 if (glyph_surface
->width
== 0 || glyph_surface
->height
== 0) {
1227 cairo_surface_t
*tmp_surface
;
1229 tmp_surface
= cairo_image_surface_create (info
->format
, 1, 1);
1230 status
= tmp_surface
->status
;
1231 if (unlikely (status
))
1234 tmp_surface
->device_transform
= glyph_surface
->base
.device_transform
;
1235 tmp_surface
->device_transform_inverse
= glyph_surface
->base
.device_transform_inverse
;
1237 glyph_surface
= (cairo_image_surface_t
*) tmp_surface
;
1241 /* If the glyph format does not match the font format, then we
1242 * create a temporary surface for the glyph image with the font's
1245 if (glyph_surface
->format
!= info
->format
) {
1246 cairo_surface_pattern_t pattern
;
1247 cairo_surface_t
*tmp_surface
;
1249 tmp_surface
= cairo_image_surface_create (info
->format
,
1250 glyph_surface
->width
,
1251 glyph_surface
->height
);
1252 status
= tmp_surface
->status
;
1253 if (unlikely (status
))
1256 tmp_surface
->device_transform
= glyph_surface
->base
.device_transform
;
1257 tmp_surface
->device_transform_inverse
= glyph_surface
->base
.device_transform_inverse
;
1259 _cairo_pattern_init_for_surface (&pattern
, &glyph_surface
->base
);
1260 status
= _cairo_surface_paint (tmp_surface
,
1261 CAIRO_OPERATOR_SOURCE
, &pattern
.base
,
1263 _cairo_pattern_fini (&pattern
.base
);
1265 glyph_surface
= (cairo_image_surface_t
*) tmp_surface
;
1267 if (unlikely (status
))
1271 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
1272 glyph_info
.x
= _cairo_lround (glyph_surface
->base
.device_transform
.x0
);
1273 glyph_info
.y
= _cairo_lround (glyph_surface
->base
.device_transform
.y0
);
1274 glyph_info
.width
= glyph_surface
->width
;
1275 glyph_info
.height
= glyph_surface
->height
;
1276 glyph_info
.xOff
= glyph
->x_advance
;
1277 glyph_info
.yOff
= glyph
->y_advance
;
1279 data
= glyph_surface
->data
;
1281 /* flip formats around */
1282 switch (_cairo_xlib_get_glyphset_index_for_format (glyph
->surface
->format
)) {
1283 case GLYPHSET_INDEX_A1
:
1284 /* local bitmaps are always stored with bit == byte */
1285 if (_cairo_is_little_endian() != (BitmapBitOrder (display
->display
) == LSBFirst
)) {
1286 int c
= glyph_surface
->stride
* glyph_surface
->height
;
1288 unsigned char *new, *n
;
1295 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1302 b
= ((b
<< 1) & 0xaa) | ((b
>> 1) & 0x55);
1303 b
= ((b
<< 2) & 0xcc) | ((b
>> 2) & 0x33);
1304 b
= ((b
<< 4) & 0xf0) | ((b
>> 4) & 0x0f);
1310 case GLYPHSET_INDEX_A8
:
1312 case GLYPHSET_INDEX_ARGB32
:
1313 if (_cairo_is_little_endian() != (ImageByteOrder (display
->display
) == LSBFirst
)) {
1314 unsigned int c
= glyph_surface
->stride
* glyph_surface
->height
/ 4;
1321 new = malloc (4 * c
);
1322 if (unlikely (new == NULL
)) {
1323 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1327 d
= (uint32_t *) data
;
1329 *n
++ = bswap_32 (*d
);
1332 data
= (uint8_t *) new;
1339 /* XXX assume X server wants pixman padding. Xft assumes this as well */
1341 XRenderAddGlyphs (display
->display
, info
->glyphset
,
1342 &glyph_index
, &glyph_info
, 1,
1344 glyph_surface
->stride
* glyph_surface
->height
);
1346 if (data
!= glyph_surface
->data
)
1349 status
= _cairo_xlib_glyph_attach (display
, glyph
, info
);
1352 if (glyph_surface
!= glyph
->surface
)
1353 cairo_surface_destroy (&glyph_surface
->base
);
1355 /* if the scaled glyph didn't already have a surface attached
1356 * to it, release the created surface now that we have it
1357 * uploaded to the X server. If the surface has already been
1358 * there (eg. because image backend requested it), leave it in
1361 if (!already_had_glyph_surface
)
1362 _cairo_scaled_glyph_set_surface (glyph
, font
, NULL
);
1367 typedef void (*cairo_xrender_composite_text_func_t
)
1372 _Xconst XRenderPictFormat
*maskFormat
,
1377 _Xconst XGlyphElt8
*elts
,
1380 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
1381 * an input glyph with double coordinates, and as "working" glyph with
1382 * integer from-current-point offsets. */
1385 unsigned long index
;
1387 unsigned long index
;
1391 } cairo_xlib_glyph_t
;
1393 /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
1394 COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t
) == sizeof (cairo_glyph_t
));
1396 /* Start a new element for the first glyph,
1397 * or for any glyph that has unexpected position,
1398 * or if current element has too many glyphs
1399 * (Xrender limits each element to 252 glyphs, we limit them to 128)
1401 * These same conditions need to be mirrored between
1402 * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
1404 #define _start_new_glyph_elt(count, glyph) \
1405 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
1407 static cairo_status_t
1408 _emit_glyphs_chunk (cairo_xlib_display_t
*display
,
1409 cairo_xlib_surface_t
*dst
,
1410 int dst_x
, int dst_y
,
1411 cairo_xlib_glyph_t
*glyphs
,
1413 cairo_scaled_font_t
*font
,
1414 cairo_bool_t use_mask
,
1415 cairo_operator_t op
,
1416 cairo_xlib_source_t
*src
,
1417 int src_x
, int src_y
,
1418 /* info for this chunk */
1421 cairo_xlib_font_glyphset_t
*info
)
1423 /* Which XRenderCompositeText function to use */
1424 cairo_xrender_composite_text_func_t composite_text_func
;
1427 /* Element buffer stuff */
1429 XGlyphElt8 stack_elts
[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8
)];
1431 /* Reuse the input glyph array for output char generation */
1432 char *char8
= (char *) glyphs
;
1433 unsigned short *char16
= (unsigned short *) glyphs
;
1434 unsigned int *char32
= (unsigned int *) glyphs
;
1437 int nelt
; /* Element index */
1438 int n
; /* Num output glyphs in current element */
1439 int j
; /* Num output glyphs so far */
1443 /* don't cast the 8-variant, to catch possible mismatches */
1444 composite_text_func
= XRenderCompositeText8
;
1445 size
= sizeof (char);
1448 composite_text_func
= (cairo_xrender_composite_text_func_t
) XRenderCompositeText16
;
1449 size
= sizeof (unsigned short);
1453 composite_text_func
= (cairo_xrender_composite_text_func_t
) XRenderCompositeText32
;
1454 size
= sizeof (unsigned int);
1457 /* Allocate element array */
1458 if (num_elts
<= ARRAY_LENGTH (stack_elts
)) {
1461 elts
= _cairo_malloc_ab (num_elts
, sizeof (XGlyphElt8
));
1462 if (unlikely (elts
== NULL
))
1463 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1470 for (i
= 0; i
< num_glyphs
; i
++) {
1471 /* Start a new element for first output glyph,
1472 * or for any glyph that has unexpected position,
1473 * or if current element has too many glyphs.
1475 * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
1477 if (_start_new_glyph_elt (j
, &glyphs
[i
])) {
1479 elts
[nelt
].nchars
= n
;
1483 elts
[nelt
].chars
= char8
+ size
* j
;
1484 elts
[nelt
].glyphset
= info
->glyphset
;
1485 elts
[nelt
].xOff
= glyphs
[i
].i
.x
;
1486 elts
[nelt
].yOff
= glyphs
[i
].i
.y
;
1490 case 1: char8
[j
] = (char) glyphs
[i
].index
; break;
1491 case 2: char16
[j
] = (unsigned short) glyphs
[i
].index
; break;
1493 case 4: char32
[j
] = (unsigned int) glyphs
[i
].index
; break;
1501 elts
[nelt
].nchars
= n
;
1505 /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
1506 * expected number of xGlyphElts. */
1507 assert (nelt
== num_elts
);
1509 composite_text_func (display
->display
, op
,
1512 use_mask
? info
->xrender_format
: NULL
,
1513 src_x
+ elts
[0].xOff
+ dst_x
,
1514 src_y
+ elts
[0].yOff
+ dst_y
,
1515 elts
[0].xOff
, elts
[0].yOff
,
1516 (XGlyphElt8
*) elts
, nelt
);
1518 if (elts
!= stack_elts
)
1521 return CAIRO_STATUS_SUCCESS
;
1524 static cairo_int_status_t
1525 check_composite_glyphs (const cairo_composite_rectangles_t
*extents
,
1526 cairo_scaled_font_t
*font
,
1527 cairo_glyph_t
*glyphs
,
1530 cairo_xlib_surface_t
*dst
= (cairo_xlib_surface_t
*)extents
->surface
;
1531 cairo_xlib_display_t
*display
= dst
->display
;
1532 int max_request_size
, size
;
1534 TRACE ((stderr
, "%s\n", __FUNCTION__
));
1536 if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display
, extents
->op
))
1537 return CAIRO_INT_STATUS_UNSUPPORTED
;
1539 /* The glyph coordinates must be representable in an int16_t.
1540 * When possible, they will be expressed as an offset from the
1541 * previous glyph, otherwise they will be an offset from the
1542 * surface origin. If we can't guarantee this to be possible,
1545 if (extents
->bounded
.x
+ extents
->bounded
.width
> INT16_MAX
||
1546 extents
->bounded
.y
+ extents
->bounded
.height
> INT16_MAX
||
1547 extents
->bounded
.x
< INT16_MIN
||
1548 extents
->bounded
.y
< INT16_MIN
)
1550 return CAIRO_INT_STATUS_UNSUPPORTED
;
1553 /* Approximate the size of the largest glyph and fallback if we can not
1554 * upload it to the xserver.
1556 size
= ceil (font
->max_scale
);
1557 size
= 4 * size
* size
;
1558 max_request_size
= (XExtendedMaxRequestSize (display
->display
) ? XExtendedMaxRequestSize (display
->display
)
1559 : XMaxRequestSize (display
->display
)) * 4 -
1560 sz_xRenderAddGlyphsReq
-
1563 if (size
>= max_request_size
)
1564 return CAIRO_INT_STATUS_UNSUPPORTED
;
1566 return CAIRO_STATUS_SUCCESS
;
1569 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
1570 * enough room for padding */
1571 #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
1573 static cairo_int_status_t
1574 composite_glyphs (void *surface
,
1575 cairo_operator_t op
,
1576 cairo_surface_t
*_src
,
1581 cairo_composite_glyphs_info_t
*info
)
1583 cairo_xlib_surface_t
*dst
= surface
;
1584 cairo_xlib_glyph_t
*glyphs
= (cairo_xlib_glyph_t
*)info
->glyphs
;
1585 cairo_xlib_source_t
*src
= (cairo_xlib_source_t
*)_src
;
1586 cairo_xlib_display_t
*display
= dst
->display
;
1587 cairo_int_status_t status
= CAIRO_INT_STATUS_SUCCESS
;
1588 cairo_scaled_glyph_t
*glyph
;
1589 cairo_fixed_t x
= dst_x
, y
= dst_y
;
1590 cairo_xlib_font_glyphset_t
*glyphset
= NULL
, *this_glyphset_info
;
1592 unsigned long max_index
= 0;
1595 int num_out_glyphs
= 0;
1596 int num_glyphs
= info
->num_glyphs
;
1598 int max_request_size
= XMaxRequestSize (display
->display
) * 4
1599 - MAX (sz_xRenderCompositeGlyphs8Req
,
1600 MAX(sz_xRenderCompositeGlyphs16Req
,
1601 sz_xRenderCompositeGlyphs32Req
));
1602 int request_size
= 0;
1605 op
= _render_operator (op
),
1606 _cairo_xlib_surface_ensure_picture (dst
);
1607 for (i
= 0; i
< num_glyphs
; i
++) {
1611 status
= _cairo_scaled_glyph_lookup (info
->font
,
1613 CAIRO_SCALED_GLYPH_INFO_METRICS
,
1615 if (unlikely (status
))
1618 this_x
= _cairo_lround (glyphs
[i
].d
.x
);
1619 this_y
= _cairo_lround (glyphs
[i
].d
.y
);
1621 /* Send unsent glyphs to the server */
1622 if (glyph
->dev_private_key
!= display
) {
1623 status
= _cairo_xlib_surface_add_glyph (display
, info
->font
, &glyph
);
1624 if (unlikely (status
))
1628 this_glyphset_info
= glyph
->dev_private
;
1630 glyphset
= this_glyphset_info
;
1632 /* The invariant here is that we can always flush the glyphs
1633 * accumulated before this one, using old_width, and they
1634 * would fit in the request.
1638 /* Update max glyph index */
1639 if (glyphs
[i
].index
> max_index
) {
1640 max_index
= glyphs
[i
].index
;
1641 if (max_index
>= 65536)
1643 else if (max_index
>= 256)
1645 if (width
!= old_width
)
1646 request_size
+= (width
- old_width
) * num_out_glyphs
;
1649 /* If we will pass the max request size by adding this glyph,
1650 * flush current glyphs. Note that we account for a
1651 * possible element being added below.
1653 * Also flush if changing glyphsets, as Xrender limits one mask
1654 * format per request, so we can either break up, or use a
1655 * wide-enough mask format. We do the former. One reason to
1656 * prefer the latter is the fact that Xserver ADDs all glyphs
1657 * to the mask first, and then composes that to final surface,
1658 * though it's not a big deal.
1660 * If the glyph has a coordinate which cannot be represented
1661 * as a 16-bit offset from the previous glyph, flush the
1662 * current chunk. The current glyph will be the first one in
1663 * the next chunk, thus its coordinates will be an offset from
1664 * the destination origin. This offset is guaranteed to be
1665 * representable as 16-bit offset (otherwise we would have
1668 if (request_size
+ width
> max_request_size
- _cairo_sz_xGlyphElt
||
1669 this_x
- x
> INT16_MAX
|| this_x
- x
< INT16_MIN
||
1670 this_y
- y
> INT16_MAX
|| this_y
- y
< INT16_MIN
||
1671 (this_glyphset_info
!= glyphset
)) {
1672 status
= _emit_glyphs_chunk (display
, dst
, dst_x
, dst_y
,
1673 glyphs
, i
, info
->font
, info
->use_mask
,
1674 op
, src
, src_x
, src_y
,
1675 num_elts
, old_width
, glyphset
);
1676 if (unlikely (status
))
1682 max_index
= glyphs
[i
].index
;
1683 width
= max_index
< 256 ? 1 : max_index
< 65536 ? 2 : 4;
1688 glyphset
= this_glyphset_info
;
1691 /* Convert absolute glyph position to relative-to-current-point
1693 glyphs
[i
].i
.x
= this_x
- x
;
1694 glyphs
[i
].i
.y
= this_y
- y
;
1696 /* Start a new element for the first glyph,
1697 * or for any glyph that has unexpected position,
1698 * or if current element has too many glyphs.
1700 * These same conditions are mirrored in _emit_glyphs_chunk().
1702 if (_start_new_glyph_elt (num_out_glyphs
, &glyphs
[i
])) {
1704 request_size
+= _cairo_sz_xGlyphElt
;
1707 /* adjust current-position */
1708 x
= this_x
+ glyph
->x_advance
;
1709 y
= this_y
+ glyph
->y_advance
;
1712 request_size
+= width
;
1716 status
= _emit_glyphs_chunk (display
, dst
, dst_x
, dst_y
,
1717 glyphs
, i
, info
->font
, info
->use_mask
,
1718 op
, src
, src_x
, src_y
,
1719 num_elts
, width
, glyphset
);
1725 const cairo_compositor_t
*
1726 _cairo_xlib_mask_compositor_get (void)
1728 static cairo_mask_compositor_t compositor
;
1730 if (compositor
.base
.delegate
== NULL
) {
1731 _cairo_mask_compositor_init (&compositor
,
1732 _cairo_xlib_fallback_compositor_get ());
1734 compositor
.acquire
= acquire
;
1735 compositor
.release
= release
;
1736 compositor
.set_clip_region
= set_clip_region
;
1737 compositor
.pattern_to_surface
= _cairo_xlib_source_create_for_pattern
;
1738 compositor
.draw_image_boxes
= draw_image_boxes
;
1739 compositor
.fill_rectangles
= fill_rectangles
;
1740 compositor
.fill_boxes
= fill_boxes
;
1741 compositor
.copy_boxes
= copy_boxes
;
1742 compositor
.check_composite
= check_composite
;
1743 compositor
.composite
= composite
;
1744 //compositor.check_composite_boxes = check_composite_boxes;
1745 compositor
.composite_boxes
= composite_boxes
;
1746 compositor
.check_composite_glyphs
= check_composite_glyphs
;
1747 compositor
.composite_glyphs
= composite_glyphs
;
1750 return &compositor
.base
;
1753 #define CAIRO_FIXED_16_16_MIN -32768
1754 #define CAIRO_FIXED_16_16_MAX 32767
1757 line_exceeds_16_16 (const cairo_line_t
*line
)
1760 line
->p1
.x
< _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN
) ||
1761 line
->p1
.x
> _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX
) ||
1762 line
->p2
.x
< _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN
) ||
1763 line
->p2
.x
> _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX
) ||
1764 line
->p1
.y
< _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN
) ||
1765 line
->p1
.y
> _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX
) ||
1766 line
->p2
.y
< _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN
) ||
1767 line
->p2
.y
> _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX
);
1771 project_line_x_onto_16_16 (const cairo_line_t
*line
,
1773 cairo_fixed_t bottom
,
1776 cairo_point_double_t p1
, p2
;
1779 p1
.x
= _cairo_fixed_to_double (line
->p1
.x
);
1780 p1
.y
= _cairo_fixed_to_double (line
->p1
.y
);
1782 p2
.x
= _cairo_fixed_to_double (line
->p2
.x
);
1783 p2
.y
= _cairo_fixed_to_double (line
->p2
.y
);
1785 m
= (p2
.x
- p1
.x
) / (p2
.y
- p1
.y
);
1786 out
->p1
.x
= _cairo_fixed_16_16_from_double (p1
.x
+ m
* _cairo_fixed_to_double (top
- line
->p1
.y
));
1787 out
->p2
.x
= _cairo_fixed_16_16_from_double (p1
.x
+ m
* _cairo_fixed_to_double (bottom
- line
->p1
.y
));
1790 static cairo_int_status_T
1791 check_composite_trapezoids ()
1793 operation
= _categorize_composite_operation (dst
, op
, pattern
, TRUE
);
1794 if (operation
== DO_UNSUPPORTED
)
1795 return UNSUPPORTED ("unsupported operation");
1797 operation
= _recategorize_composite_operation (dst
, op
, src
,
1799 if (operation
== DO_UNSUPPORTED
) {
1800 status
= UNSUPPORTED ("unsupported operation");
1807 static cairo_int_status_t
1808 composite_traps (void *abstract_dst
,
1809 cairo_operator_t op
,
1810 cairo_surface_t
*abstract_src
,
1815 const cairo_rectangle_int_t
*extents
,
1816 cairo_antialias_t antialias
,
1817 cairo_traps_t
*traps
)
1819 cairo_xlib_surface_t
*dst
= abstract_dst
;
1820 cairo_xlib_display_t
*display
= dst
->display
;
1821 cairo_xlib_source_t
*src
= (cairo_xlib_source_t
*)abstract_src
;
1822 XRenderPictFormat
*pict_format
;
1823 XTrapezoid xtraps_stack
[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid
)];
1824 XTrapezoid
*xtraps
= xtraps_stack
;
1828 //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1830 if (dst
->base
.is_clear
&&
1831 (op
== CAIRO_OPERATOR_OVER
|| op
== CAIRO_OPERATOR_ADD
))
1833 op
= CAIRO_OPERATOR_SOURCE
;
1837 _cairo_xlib_display_get_xrender_format (display
,
1838 antialias
== CAIRO_ANTIALIAS_NONE
? CAIRO_FORMAT_A1
: CAIRO_FORMAT_A8
);
1840 if (traps
->num_traps
> ARRAY_LENGTH (xtraps_stack
)) {
1841 xtraps
= _cairo_malloc_ab (traps
->num_traps
, sizeof (XTrapezoid
));
1842 if (unlikely (xtraps
== NULL
))
1843 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1848 for (i
= 0; i
< traps
->num_traps
; i
++) {
1849 cairo_trapezoid_t
*t
= &traps
->traps
[i
];
1851 /* top/bottom will be clamped to surface bounds */
1852 xtraps
[i
].top
= _cairo_fixed_to_16_16(t
->top
) + dy
;
1853 xtraps
[i
].bottom
= _cairo_fixed_to_16_16(t
->bottom
) + dy
;
1855 /* However, all the other coordinates will have been left untouched so
1856 * as not to introduce numerical error. Recompute them if they
1857 * exceed the 16.16 limits.
1859 if (unlikely (line_exceeds_16_16 (&t
->left
))) {
1860 project_line_x_onto_16_16 (&t
->left
, t
->top
, t
->bottom
,
1862 xtraps
[i
].left
.p1
.x
+= dx
;
1863 xtraps
[i
].left
.p2
.x
+= dx
;
1864 xtraps
[i
].left
.p1
.y
= xtraps
[i
].top
;
1865 xtraps
[i
].left
.p2
.y
= xtraps
[i
].bottom
;
1867 xtraps
[i
].left
.p1
.x
= _cairo_fixed_to_16_16(t
->left
.p1
.x
) + dx
;
1868 xtraps
[i
].left
.p1
.y
= _cairo_fixed_to_16_16(t
->left
.p1
.y
) + dy
;
1869 xtraps
[i
].left
.p2
.x
= _cairo_fixed_to_16_16(t
->left
.p2
.x
) + dx
;
1870 xtraps
[i
].left
.p2
.y
= _cairo_fixed_to_16_16(t
->left
.p2
.y
) + dy
;
1873 if (unlikely (line_exceeds_16_16 (&t
->right
))) {
1874 project_line_x_onto_16_16 (&t
->right
, t
->top
, t
->bottom
,
1876 xtraps
[i
].right
.p1
.x
+= dx
;
1877 xtraps
[i
].right
.p2
.x
+= dx
;
1878 xtraps
[i
].right
.p1
.y
= xtraps
[i
].top
;
1879 xtraps
[i
].right
.p2
.y
= xtraps
[i
].bottom
;
1881 xtraps
[i
].right
.p1
.x
= _cairo_fixed_to_16_16(t
->right
.p1
.x
) + dx
;
1882 xtraps
[i
].right
.p1
.y
= _cairo_fixed_to_16_16(t
->right
.p1
.y
) + dy
;
1883 xtraps
[i
].right
.p2
.x
= _cairo_fixed_to_16_16(t
->right
.p2
.x
) + dx
;
1884 xtraps
[i
].right
.p2
.y
= _cairo_fixed_to_16_16(t
->right
.p2
.y
) + dy
;
1888 if (xtraps
[0].left
.p1
.y
< xtraps
[0].left
.p2
.y
) {
1889 src_x
+= _cairo_fixed_16_16_floor (xtraps
[0].left
.p1
.x
);
1890 src_y
+= _cairo_fixed_16_16_floor (xtraps
[0].left
.p1
.y
);
1892 src_x
+= _cairo_fixed_16_16_floor (xtraps
[0].left
.p2
.x
);
1893 src_y
+= _cairo_fixed_16_16_floor (xtraps
[0].left
.p2
.y
);
1898 _cairo_xlib_surface_ensure_picture (dst
);
1899 _cairo_xlib_surface_set_precision (dst
, antialias
);
1900 XRenderCompositeTrapezoids (dst
->dpy
,
1901 _render_operator (op
),
1902 src
->picture
, dst
->picture
,
1905 xtraps
, traps
->num_traps
);
1907 if (xtraps
!= xtraps_stack
)
1910 return CAIRO_STATUS_SUCCESS
;
1913 static cairo_int_status_t
1914 composite_tristrip (void *abstract_dst
,
1915 cairo_operator_t op
,
1916 cairo_surface_t
*abstract_src
,
1921 const cairo_rectangle_int_t
*extents
,
1922 cairo_antialias_t antialias
,
1923 cairo_tristrip_t
*strip
)
1925 cairo_xlib_surface_t
*dst
= abstract_dst
;
1926 cairo_xlib_display_t
*display
= dst
->display
;
1927 cairo_xlib_source_t
*src
= (cairo_xlib_source_t
*)abstract_src
;
1928 XRenderPictFormat
*pict_format
;
1929 XPointFixed points_stack
[CAIRO_STACK_ARRAY_LENGTH (XPointFixed
)];
1930 XPointFixed
*points
= points_stack
;
1934 //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1937 _cairo_xlib_display_get_xrender_format (display
,
1938 antialias
== CAIRO_ANTIALIAS_NONE
? CAIRO_FORMAT_A1
: CAIRO_FORMAT_A8
);
1940 if (strip
->num_points
> ARRAY_LENGTH (points_stack
)) {
1941 points
= _cairo_malloc_ab (strip
->num_points
, sizeof (XPointFixed
));
1942 if (unlikely (points
== NULL
))
1943 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1948 for (i
= 0; i
< strip
->num_points
; i
++) {
1949 cairo_point_t
*p
= &strip
->points
[i
];
1951 points
[i
].x
= _cairo_fixed_to_16_16(p
->x
) + dx
;
1952 points
[i
].y
= _cairo_fixed_to_16_16(p
->y
) + dy
;
1955 src_x
+= _cairo_fixed_16_16_floor (points
[0].x
) + dst_x
;
1956 src_y
+= _cairo_fixed_16_16_floor (points
[0].y
) + dst_y
;
1958 _cairo_xlib_surface_ensure_picture (dst
);
1959 _cairo_xlib_surface_set_precision (dst
, antialias
);
1960 XRenderCompositeTriStrip (dst
->dpy
,
1961 _render_operator (op
),
1962 src
->picture
, dst
->picture
,
1965 points
, strip
->num_points
);
1967 if (points
!= points_stack
)
1970 return CAIRO_STATUS_SUCCESS
;
1973 const cairo_compositor_t
*
1974 _cairo_xlib_traps_compositor_get (void)
1976 static cairo_traps_compositor_t compositor
;
1978 if (compositor
.base
.delegate
== NULL
) {
1979 _cairo_traps_compositor_init (&compositor
,
1980 _cairo_xlib_mask_compositor_get ());
1982 compositor
.acquire
= acquire
;
1983 compositor
.release
= release
;
1984 compositor
.set_clip_region
= set_clip_region
;
1985 compositor
.pattern_to_surface
= _cairo_xlib_source_create_for_pattern
;
1986 compositor
.draw_image_boxes
= draw_image_boxes
;
1987 compositor
.copy_boxes
= copy_boxes
;
1988 compositor
.fill_boxes
= fill_boxes
;
1989 compositor
.check_composite
= check_composite
;
1990 compositor
.composite
= composite
;
1991 compositor
.lerp
= lerp
;
1992 //compositor.check_composite_boxes = check_composite_boxes;
1993 compositor
.composite_boxes
= composite_boxes
;
1994 //compositor.check_composite_traps = check_composite_traps;
1995 compositor
.composite_traps
= composite_traps
;
1996 //compositor.check_composite_tristrip = check_composite_tristrip;
1997 compositor
.composite_tristrip
= composite_tristrip
;
1998 compositor
.check_composite_glyphs
= check_composite_glyphs
;
1999 compositor
.composite_glyphs
= composite_glyphs
;
2002 return &compositor
.base
;
2005 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */