1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
29 * Chris Wilson <chris@chris-wilson.co.uk>
34 #include "cairo-xcb-private.h"
36 #include "cairo-boxes-private.h"
37 #include "cairo-clip-inline.h"
38 #include "cairo-clip-private.h"
39 #include "cairo-composite-rectangles-private.h"
40 #include "cairo-image-surface-inline.h"
41 #include "cairo-image-surface-private.h"
42 #include "cairo-list-inline.h"
43 #include "cairo-region-private.h"
44 #include "cairo-surface-offset-private.h"
45 #include "cairo-surface-snapshot-inline.h"
46 #include "cairo-surface-subsurface-private.h"
47 #include "cairo-traps-private.h"
48 #include "cairo-recording-surface-inline.h"
49 #include "cairo-paginated-private.h"
50 #include "cairo-pattern-inline.h"
52 #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
55 _clip_and_composite_boxes (cairo_xcb_surface_t
*dst
,
57 const cairo_pattern_t
*src
,
59 cairo_composite_rectangles_t
*extents
);
61 static inline cairo_xcb_connection_t
*
62 _picture_to_connection (cairo_xcb_picture_t
*picture
)
64 return (cairo_xcb_connection_t
*) picture
->base
.device
;
68 _cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t
*surface
);
71 hars_petruska_f54_1_random (void)
73 #define rol(x,k) ((x << k) | (x >> (32-k)))
75 return x
= (x
^ rol (x
, 5) ^ rol (x
, 24)) + 0x37798849;
80 _cairo_xcb_picture_finish (void *abstract_surface
)
82 cairo_xcb_picture_t
*surface
= abstract_surface
;
83 cairo_xcb_connection_t
*connection
= _picture_to_connection (surface
);
84 cairo_status_t status
;
86 status
= _cairo_xcb_connection_acquire (connection
);
87 cairo_list_del (&surface
->link
);
88 if (unlikely (status
))
91 _cairo_xcb_connection_render_free_picture (connection
, surface
->picture
);
93 _cairo_xcb_connection_release (connection
);
95 return CAIRO_STATUS_SUCCESS
;
98 static const cairo_surface_backend_t _cairo_xcb_picture_backend
= {
99 CAIRO_SURFACE_TYPE_XCB
,
100 _cairo_xcb_picture_finish
,
103 static const struct xcb_render_transform_t identity_transform
= {
109 static cairo_xcb_picture_t
*
110 _cairo_xcb_picture_create (cairo_xcb_screen_t
*screen
,
111 pixman_format_code_t pixman_format
,
112 xcb_render_pictformat_t xrender_format
,
113 int width
, int height
)
115 cairo_xcb_picture_t
*surface
;
117 surface
= malloc (sizeof (cairo_xcb_picture_t
));
118 if (unlikely (surface
== NULL
))
119 return (cairo_xcb_picture_t
*)
120 _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
122 _cairo_surface_init (&surface
->base
,
123 &_cairo_xcb_picture_backend
,
124 &screen
->connection
->device
,
125 _cairo_content_from_pixman_format (pixman_format
));
127 cairo_list_add (&surface
->link
, &screen
->pictures
);
129 surface
->screen
= screen
;
130 surface
->picture
= _cairo_xcb_connection_get_xid (screen
->connection
);
131 surface
->pixman_format
= pixman_format
;
132 surface
->xrender_format
= xrender_format
;
134 surface
->x0
= surface
->y0
= 0;
135 surface
->x
= surface
->y
= 0;
136 surface
->width
= width
;
137 surface
->height
= height
;
139 surface
->transform
= identity_transform
;
140 surface
->extend
= CAIRO_EXTEND_NONE
;
141 surface
->filter
= CAIRO_FILTER_NEAREST
;
142 surface
->has_component_alpha
= FALSE
;
147 static inline cairo_bool_t
148 _operator_is_supported (uint32_t flags
, cairo_operator_t op
)
150 if (op
<= CAIRO_OPERATOR_SATURATE
)
153 /* Can we use PDF operators? */
154 #if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
155 if (op
<= CAIRO_OPERATOR_HSL_LUMINOSITY
)
156 return flags
& CAIRO_XCB_RENDER_HAS_PDF_OPERATORS
;
163 _render_operator (cairo_operator_t op
)
165 #define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y
176 C(DEST_OVER
, OVER_REVERSE
);
177 C(DEST_IN
, IN_REVERSE
);
178 C(DEST_OUT
, OUT_REVERSE
);
179 C(DEST_ATOP
, ATOP_REVERSE
);
183 C(SATURATE
, SATURATE
);
185 /* PDF operators were added in RENDER 0.11, check if the xcb headers have
186 * the defines, else fall through to the default case. */
187 #if CAIRO_XCB_RENDER_AT_LEAST(0, 11)
188 #define BLEND(x,y) C(x,y)
190 #define BLEND(x,y) case CAIRO_OPERATOR_##x:
192 BLEND(MULTIPLY
, MULTIPLY
);
193 BLEND(SCREEN
, SCREEN
);
194 BLEND(OVERLAY
, OVERLAY
);
195 BLEND(DARKEN
, DARKEN
);
196 BLEND(LIGHTEN
, LIGHTEN
);
197 BLEND(COLOR_DODGE
, COLOR_DODGE
);
198 BLEND(COLOR_BURN
, COLOR_BURN
);
199 BLEND(HARD_LIGHT
, HARD_LIGHT
);
200 BLEND(SOFT_LIGHT
, SOFT_LIGHT
);
201 BLEND(DIFFERENCE
, DIFFERENCE
);
202 BLEND(EXCLUSION
, EXCLUSION
);
203 BLEND(HSL_HUE
, HSL_HUE
);
204 BLEND(HSL_SATURATION
, HSL_SATURATION
);
205 BLEND(HSL_COLOR
, HSL_COLOR
);
206 BLEND(HSL_LUMINOSITY
, HSL_LUMINOSITY
);
210 return XCB_RENDER_PICT_OP_OVER
;
214 static cairo_status_t
215 _cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t
*surface
,
216 cairo_region_t
*region
)
218 xcb_rectangle_t stack_rects
[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t
)];
219 xcb_rectangle_t
*rects
= stack_rects
;
222 num_rects
= cairo_region_num_rectangles (region
);
224 if (num_rects
> ARRAY_LENGTH (stack_rects
)) {
225 rects
= _cairo_malloc_ab (num_rects
, sizeof (xcb_rectangle_t
));
226 if (unlikely (rects
== NULL
)) {
227 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
231 for (i
= 0; i
< num_rects
; i
++) {
232 cairo_rectangle_int_t rect
;
234 cairo_region_get_rectangle (region
, i
, &rect
);
238 rects
[i
].width
= rect
.width
;
239 rects
[i
].height
= rect
.height
;
242 _cairo_xcb_connection_render_set_picture_clip_rectangles (surface
->connection
,
247 if (rects
!= stack_rects
)
250 return CAIRO_STATUS_SUCCESS
;
254 _cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t
*surface
)
256 uint32_t values
[] = { XCB_NONE
};
257 _cairo_xcb_connection_render_change_picture (surface
->connection
,
259 XCB_RENDER_CP_CLIP_MASK
,
264 _cairo_xcb_surface_set_precision (cairo_xcb_surface_t
*surface
,
265 cairo_antialias_t antialias
)
267 cairo_xcb_connection_t
*connection
= surface
->connection
;
270 if (connection
->force_precision
!= -1)
271 precision
= connection
->force_precision
;
272 else switch (antialias
) {
274 case CAIRO_ANTIALIAS_DEFAULT
:
275 case CAIRO_ANTIALIAS_GRAY
:
276 case CAIRO_ANTIALIAS_NONE
:
277 case CAIRO_ANTIALIAS_FAST
:
278 case CAIRO_ANTIALIAS_GOOD
:
279 precision
= XCB_RENDER_POLY_MODE_IMPRECISE
;
281 case CAIRO_ANTIALIAS_SUBPIXEL
:
282 case CAIRO_ANTIALIAS_BEST
:
283 precision
= XCB_RENDER_POLY_MODE_PRECISE
;
287 if (surface
->precision
!= precision
) {
288 _cairo_xcb_connection_render_change_picture (connection
,
290 XCB_RENDER_CP_POLY_MODE
,
292 surface
->precision
= precision
;
298 _cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t
*surface
)
300 assert (surface
->fallback
== NULL
);
301 if (surface
->picture
== XCB_NONE
) {
305 if (surface
->precision
!= XCB_RENDER_POLY_MODE_PRECISE
) {
306 flags
|= XCB_RENDER_CP_POLY_MODE
;
307 values
[0] = surface
->precision
;
310 surface
->picture
= _cairo_xcb_connection_get_xid (surface
->connection
);
311 _cairo_xcb_connection_render_create_picture (surface
->connection
,
314 surface
->xrender_format
,
319 static cairo_xcb_picture_t
*
320 _picture_from_image (cairo_xcb_surface_t
*target
,
321 xcb_render_pictformat_t format
,
322 cairo_image_surface_t
*image
,
323 cairo_xcb_shm_info_t
*shm_info
)
327 cairo_xcb_picture_t
*picture
;
329 pixmap
= _cairo_xcb_connection_create_pixmap (target
->connection
,
332 image
->width
, image
->height
);
334 gc
= _cairo_xcb_screen_get_gc (target
->screen
, pixmap
, image
->depth
);
336 if (shm_info
!= NULL
) {
337 _cairo_xcb_connection_shm_put_image (target
->connection
,
339 image
->width
, image
->height
,
341 image
->width
, image
->height
,
349 /* Do we need to trim the image? */
350 len
= CAIRO_STRIDE_FOR_WIDTH_BPP (image
->width
, PIXMAN_FORMAT_BPP (image
->pixman_format
));
351 if (len
== image
->stride
) {
352 _cairo_xcb_connection_put_image (target
->connection
,
354 image
->width
, image
->height
,
360 _cairo_xcb_connection_put_subimage (target
->connection
,
363 image
->width
, image
->height
,
364 PIXMAN_FORMAT_BPP (image
->pixman_format
) / 8,
373 _cairo_xcb_screen_put_gc (target
->screen
, image
->depth
, gc
);
375 picture
= _cairo_xcb_picture_create (target
->screen
,
376 image
->pixman_format
, format
,
377 image
->width
, image
->height
);
378 if (likely (picture
->base
.status
== CAIRO_STATUS_SUCCESS
)) {
379 _cairo_xcb_connection_render_create_picture (target
->connection
,
380 picture
->picture
, pixmap
, format
,
384 _cairo_xcb_connection_free_pixmap (target
->connection
, pixmap
);
390 _pattern_is_supported (uint32_t flags
,
391 const cairo_pattern_t
*pattern
)
394 if (pattern
->type
== CAIRO_PATTERN_TYPE_SOLID
)
397 switch (pattern
->extend
) {
400 case CAIRO_EXTEND_NONE
:
401 case CAIRO_EXTEND_REPEAT
:
403 case CAIRO_EXTEND_PAD
:
404 case CAIRO_EXTEND_REFLECT
:
405 if ((flags
& CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT
) == 0)
409 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
410 switch (pattern
->filter
) {
411 case CAIRO_FILTER_FAST
:
412 case CAIRO_FILTER_NEAREST
:
413 return (flags
& CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM
) ||
414 _cairo_matrix_is_integer_translation (&pattern
->matrix
, NULL
, NULL
);
415 case CAIRO_FILTER_GOOD
:
416 return flags
& CAIRO_XCB_RENDER_HAS_FILTER_GOOD
;
417 case CAIRO_FILTER_BEST
:
418 return flags
& CAIRO_XCB_RENDER_HAS_FILTER_BEST
;
419 case CAIRO_FILTER_BILINEAR
:
420 case CAIRO_FILTER_GAUSSIAN
:
422 return flags
& CAIRO_XCB_RENDER_HAS_FILTERS
;
424 } else if (pattern
->type
== CAIRO_PATTERN_TYPE_MESH
) {
426 } else { /* gradient */
427 if ((flags
& CAIRO_XCB_RENDER_HAS_GRADIENTS
) == 0)
430 /* The RENDER specification says that the inner circle has to be
431 * completely contained inside the outer one. */
432 if (pattern
->type
== CAIRO_PATTERN_TYPE_RADIAL
&&
433 ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t
*) pattern
))
442 _cairo_xcb_picture_set_matrix (cairo_xcb_picture_t
*picture
,
443 const cairo_matrix_t
*matrix
,
444 cairo_filter_t filter
,
445 double xc
, double yc
)
447 xcb_render_transform_t transform
;
448 pixman_transform_t
*pixman_transform
;
449 cairo_int_status_t ignored
;
451 /* Casting between pixman_transform_t and xcb_render_transform_t is safe
452 * because they happen to be the exact same type.
454 pixman_transform
= (pixman_transform_t
*) &transform
;
456 picture
->x
= picture
->x0
;
457 picture
->y
= picture
->y0
;
458 ignored
= _cairo_matrix_to_pixman_matrix_offset (matrix
, filter
, xc
, yc
,
460 &picture
->x
, &picture
->y
);
463 if (memcmp (&picture
->transform
, &transform
, sizeof (xcb_render_transform_t
))) {
464 _cairo_xcb_connection_render_set_picture_transform (_picture_to_connection (picture
),
468 picture
->transform
= transform
;
473 _cairo_xcb_picture_set_filter (cairo_xcb_picture_t
*picture
,
474 cairo_filter_t filter
)
476 const char *render_filter
;
479 if (picture
->filter
== filter
)
483 case CAIRO_FILTER_FAST
:
484 render_filter
= "fast";
485 len
= strlen ("fast");
488 case CAIRO_FILTER_GOOD
:
489 render_filter
= "good";
490 len
= strlen ("good");
493 case CAIRO_FILTER_BEST
:
494 render_filter
= "best";
495 len
= strlen ("best");
498 case CAIRO_FILTER_NEAREST
:
499 render_filter
= "nearest";
500 len
= strlen ("nearest");
503 case CAIRO_FILTER_BILINEAR
:
504 render_filter
= "bilinear";
505 len
= strlen ("bilinear");
510 case CAIRO_FILTER_GAUSSIAN
:
511 render_filter
= "best";
512 len
= strlen ("best");
516 _cairo_xcb_connection_render_set_picture_filter (_picture_to_connection (picture
),
518 len
, (char *) render_filter
);
519 picture
->filter
= filter
;
523 _cairo_xcb_picture_set_extend (cairo_xcb_picture_t
*picture
,
524 cairo_extend_t extend
)
528 if (picture
->extend
== extend
)
534 case CAIRO_EXTEND_NONE
:
535 pa
[0] = XCB_RENDER_REPEAT_NONE
;
538 case CAIRO_EXTEND_REPEAT
:
539 pa
[0] = XCB_RENDER_REPEAT_NORMAL
;
542 case CAIRO_EXTEND_REFLECT
:
543 pa
[0] = XCB_RENDER_REPEAT_REFLECT
;
546 case CAIRO_EXTEND_PAD
:
547 pa
[0] = XCB_RENDER_REPEAT_PAD
;
551 _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture
),
553 XCB_RENDER_CP_REPEAT
, pa
);
554 picture
->extend
= extend
;
558 _cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t
*picture
,
563 if (picture
->has_component_alpha
== ca
)
568 _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture
),
570 XCB_RENDER_CP_COMPONENT_ALPHA
,
572 picture
->has_component_alpha
= ca
;
575 static cairo_xcb_picture_t
*
576 _solid_picture (cairo_xcb_surface_t
*target
,
577 const cairo_color_t
*color
)
579 xcb_render_color_t xcb_color
;
580 xcb_render_pictformat_t xrender_format
;
581 cairo_xcb_picture_t
*picture
;
583 xcb_color
.red
= color
->red_short
;
584 xcb_color
.green
= color
->green_short
;
585 xcb_color
.blue
= color
->blue_short
;
586 xcb_color
.alpha
= color
->alpha_short
;
588 xrender_format
= target
->screen
->connection
->standard_formats
[CAIRO_FORMAT_ARGB32
];
589 picture
= _cairo_xcb_picture_create (target
->screen
,
593 if (unlikely (picture
->base
.status
))
596 if (target
->connection
->flags
& CAIRO_XCB_RENDER_HAS_GRADIENTS
) {
597 _cairo_xcb_connection_render_create_solid_fill (target
->connection
,
602 uint32_t values
[] = { XCB_RENDER_REPEAT_NORMAL
};
604 pixmap
= _cairo_xcb_connection_create_pixmap (target
->connection
,
605 32, target
->drawable
, 1, 1);
606 _cairo_xcb_connection_render_create_picture (target
->connection
,
610 XCB_RENDER_CP_REPEAT
,
612 if (target
->connection
->flags
& CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
) {
613 xcb_rectangle_t rect
;
616 rect
.width
= rect
.height
= 1;
618 _cairo_xcb_connection_render_fill_rectangles (_picture_to_connection (picture
),
619 XCB_RENDER_PICT_OP_SRC
,
621 xcb_color
, 1, &rect
);
626 gc
= _cairo_xcb_screen_get_gc (target
->screen
, pixmap
, 32);
628 /* XXX byte ordering? */
629 pixel
= ((color
->alpha_short
>> 8) << 24) |
630 ((color
->red_short
>> 8) << 16) |
631 ((color
->green_short
>> 8) << 8) |
632 ((color
->blue_short
>> 8) << 0);
634 _cairo_xcb_connection_put_image (target
->connection
,
639 _cairo_xcb_screen_put_gc (target
->screen
, 32, gc
);
642 _cairo_xcb_connection_free_pixmap (target
->connection
, pixmap
);
648 static cairo_xcb_picture_t
*
649 _cairo_xcb_transparent_picture (cairo_xcb_surface_t
*target
)
651 cairo_xcb_picture_t
*picture
;
653 picture
= (cairo_xcb_picture_t
*) target
->screen
->stock_colors
[CAIRO_STOCK_TRANSPARENT
];
654 if (picture
== NULL
) {
655 picture
= _solid_picture (target
, CAIRO_COLOR_TRANSPARENT
);
656 target
->screen
->stock_colors
[CAIRO_STOCK_TRANSPARENT
] = &picture
->base
;
659 return (cairo_xcb_picture_t
*) cairo_surface_reference (&picture
->base
);
662 static cairo_xcb_picture_t
*
663 _cairo_xcb_black_picture (cairo_xcb_surface_t
*target
)
665 cairo_xcb_picture_t
*picture
;
667 picture
= (cairo_xcb_picture_t
*) target
->screen
->stock_colors
[CAIRO_STOCK_BLACK
];
668 if (picture
== NULL
) {
669 picture
= _solid_picture (target
, CAIRO_COLOR_BLACK
);
670 target
->screen
->stock_colors
[CAIRO_STOCK_BLACK
] = &picture
->base
;
673 return (cairo_xcb_picture_t
*) cairo_surface_reference (&picture
->base
);
676 static cairo_xcb_picture_t
*
677 _cairo_xcb_white_picture (cairo_xcb_surface_t
*target
)
679 cairo_xcb_picture_t
*picture
;
681 picture
= (cairo_xcb_picture_t
*) target
->screen
->stock_colors
[CAIRO_STOCK_WHITE
];
682 if (picture
== NULL
) {
683 picture
= _solid_picture (target
, CAIRO_COLOR_WHITE
);
684 target
->screen
->stock_colors
[CAIRO_STOCK_WHITE
] = &picture
->base
;
687 return (cairo_xcb_picture_t
*) cairo_surface_reference (&picture
->base
);
690 static cairo_xcb_picture_t
*
691 _cairo_xcb_solid_picture (cairo_xcb_surface_t
*target
,
692 const cairo_solid_pattern_t
*pattern
)
694 cairo_xcb_picture_t
*picture
;
695 cairo_xcb_screen_t
*screen
;
698 if (pattern
->color
.alpha_short
<= 0x00ff)
699 return _cairo_xcb_transparent_picture (target
);
701 if (pattern
->color
.alpha_short
>= 0xff00) {
702 if (pattern
->color
.red_short
<= 0x00ff &&
703 pattern
->color
.green_short
<= 0x00ff &&
704 pattern
->color
.blue_short
<= 0x00ff)
706 return _cairo_xcb_black_picture (target
);
709 if (pattern
->color
.red_short
>= 0xff00 &&
710 pattern
->color
.green_short
>= 0xff00 &&
711 pattern
->color
.blue_short
>= 0xff00)
713 return _cairo_xcb_white_picture (target
);
717 screen
= target
->screen
;
718 n_cached
= screen
->solid_cache_size
;
719 for (i
= 0; i
< n_cached
; i
++) {
720 if (_cairo_color_equal (&screen
->solid_cache
[i
].color
, &pattern
->color
)) {
721 return (cairo_xcb_picture_t
*) cairo_surface_reference (screen
->solid_cache
[i
].picture
);
725 picture
= _solid_picture (target
, &pattern
->color
);
726 if (unlikely (picture
->base
.status
))
729 if (screen
->solid_cache_size
< ARRAY_LENGTH (screen
->solid_cache
)) {
730 i
= screen
->solid_cache_size
++;
732 i
= hars_petruska_f54_1_random () % ARRAY_LENGTH (screen
->solid_cache
);
733 cairo_surface_destroy (screen
->solid_cache
[i
].picture
);
735 screen
->solid_cache
[i
].picture
= cairo_surface_reference (&picture
->base
);
736 screen
->solid_cache
[i
].color
= pattern
->color
;
741 static cairo_xcb_picture_t
*
742 _render_to_picture (cairo_xcb_surface_t
*target
,
743 const cairo_pattern_t
*pattern
,
744 const cairo_rectangle_int_t
*extents
)
746 cairo_image_surface_t
*image
;
747 cairo_xcb_shm_info_t
*shm_info
;
748 cairo_pattern_union_t copy
;
749 cairo_status_t status
;
750 cairo_xcb_picture_t
*picture
;
751 pixman_format_code_t pixman_format
;
752 xcb_render_pictformat_t xrender_format
;
754 /* XXX handle extend modes via tiling? */
755 /* XXX alpha-only masks? */
757 pixman_format
= PIXMAN_a8r8g8b8
;
758 xrender_format
= target
->screen
->connection
->standard_formats
[CAIRO_FORMAT_ARGB32
];
760 status
= _cairo_xcb_shm_image_create (target
->screen
->connection
,
762 extents
->width
, extents
->height
,
764 if (unlikely (status
))
765 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (status
);
767 _cairo_pattern_init_static_copy (©
.base
, pattern
);
768 cairo_matrix_translate (©
.base
.matrix
, extents
->x
, extents
->y
);
769 status
= _cairo_surface_paint (&image
->base
,
770 CAIRO_OPERATOR_SOURCE
,
773 if (unlikely (status
)) {
774 cairo_surface_destroy (&image
->base
);
775 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (status
);
778 picture
= _picture_from_image (target
, xrender_format
, image
, shm_info
);
779 cairo_surface_destroy (&image
->base
);
781 if (unlikely (picture
->base
.status
))
784 _cairo_xcb_picture_set_component_alpha (picture
, pattern
->has_component_alpha
);
785 picture
->x
= -extents
->x
;
786 picture
->y
= -extents
->y
;
791 static xcb_render_fixed_t
*
792 _gradient_to_xcb (const cairo_gradient_pattern_t
*gradient
,
793 unsigned int *n_stops
,
794 char *buf
, unsigned int buflen
)
796 xcb_render_fixed_t
*stops
;
797 xcb_render_color_t
*colors
;
800 assert (gradient
->n_stops
> 0);
801 *n_stops
= MAX (gradient
->n_stops
, 2);
803 if (*n_stops
* (sizeof (xcb_render_fixed_t
) + sizeof (xcb_render_color_t
)) < buflen
)
805 stops
= (xcb_render_fixed_t
*) buf
;
810 _cairo_malloc_ab (*n_stops
,
811 sizeof (xcb_render_fixed_t
) + sizeof (xcb_render_color_t
));
812 if (unlikely (stops
== NULL
))
816 colors
= (xcb_render_color_t
*) (stops
+ *n_stops
);
817 for (i
= 0; i
< gradient
->n_stops
; i
++) {
819 _cairo_fixed_16_16_from_double (gradient
->stops
[i
].offset
);
821 colors
[i
].red
= gradient
->stops
[i
].color
.red_short
;
822 colors
[i
].green
= gradient
->stops
[i
].color
.green_short
;
823 colors
[i
].blue
= gradient
->stops
[i
].color
.blue_short
;
824 colors
[i
].alpha
= gradient
->stops
[i
].color
.alpha_short
;
827 /* RENDER does not support gradients with less than 2 stops. If a
828 * gradient has only a single stop, duplicate it to make RENDER
830 if (gradient
->n_stops
== 1) {
831 stops
[1] = _cairo_fixed_16_16_from_double (gradient
->stops
[0].offset
);
833 colors
[1].red
= gradient
->stops
[0].color
.red_short
;
834 colors
[1].green
= gradient
->stops
[0].color
.green_short
;
835 colors
[1].blue
= gradient
->stops
[0].color
.blue_short
;
836 colors
[1].alpha
= gradient
->stops
[0].color
.alpha_short
;
842 static cairo_xcb_picture_t
*
843 _cairo_xcb_linear_picture (cairo_xcb_surface_t
*target
,
844 const cairo_linear_pattern_t
*pattern
,
845 const cairo_rectangle_int_t
*extents
)
847 char buf
[CAIRO_STACK_BUFFER_SIZE
];
848 xcb_render_fixed_t
*stops
;
849 xcb_render_color_t
*colors
;
850 xcb_render_pointfix_t p1
, p2
;
851 cairo_matrix_t matrix
;
852 cairo_circle_double_t extremes
[2];
853 cairo_xcb_picture_t
*picture
;
854 cairo_status_t status
;
855 unsigned int n_stops
;
857 _cairo_gradient_pattern_fit_to_range (&pattern
->base
, PIXMAN_MAX_INT
>> 1, &matrix
, extremes
);
859 picture
= (cairo_xcb_picture_t
*)
860 _cairo_xcb_screen_lookup_linear_picture (target
->screen
, pattern
);
864 stops
= _gradient_to_xcb (&pattern
->base
, &n_stops
, buf
, sizeof (buf
));
865 if (unlikely (stops
== NULL
))
866 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY
);
868 picture
= _cairo_xcb_picture_create (target
->screen
,
869 target
->screen
->connection
->standard_formats
[CAIRO_FORMAT_ARGB32
],
872 if (unlikely (picture
->base
.status
)) {
873 if (stops
!= (xcb_render_fixed_t
*) buf
)
877 picture
->filter
= CAIRO_FILTER_DEFAULT
;
879 colors
= (xcb_render_color_t
*) (stops
+ n_stops
);
881 p1
.x
= _cairo_fixed_16_16_from_double (extremes
[0].center
.x
);
882 p1
.y
= _cairo_fixed_16_16_from_double (extremes
[0].center
.y
);
883 p2
.x
= _cairo_fixed_16_16_from_double (extremes
[1].center
.x
);
884 p2
.y
= _cairo_fixed_16_16_from_double (extremes
[1].center
.y
);
886 _cairo_xcb_connection_render_create_linear_gradient (target
->connection
,
892 if (stops
!= (xcb_render_fixed_t
*) buf
)
895 status
= _cairo_xcb_screen_store_linear_picture (target
->screen
,
898 if (unlikely (status
)) {
899 cairo_surface_destroy (&picture
->base
);
900 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (status
);
904 _cairo_xcb_picture_set_matrix (picture
, &matrix
,
905 pattern
->base
.base
.filter
,
906 extents
->x
+ extents
->width
/2.,
907 extents
->y
+ extents
->height
/2.);
908 _cairo_xcb_picture_set_filter (picture
, pattern
->base
.base
.filter
);
909 _cairo_xcb_picture_set_extend (picture
, pattern
->base
.base
.extend
);
910 _cairo_xcb_picture_set_component_alpha (picture
,
911 pattern
->base
.base
.has_component_alpha
);
916 static cairo_xcb_picture_t
*
917 _cairo_xcb_radial_picture (cairo_xcb_surface_t
*target
,
918 const cairo_radial_pattern_t
*pattern
,
919 const cairo_rectangle_int_t
*extents
)
921 char buf
[CAIRO_STACK_BUFFER_SIZE
];
922 xcb_render_fixed_t
*stops
;
923 xcb_render_color_t
*colors
;
924 xcb_render_pointfix_t p1
, p2
;
925 xcb_render_fixed_t r1
, r2
;
926 cairo_matrix_t matrix
;
927 cairo_circle_double_t extremes
[2];
928 cairo_xcb_picture_t
*picture
;
929 cairo_status_t status
;
930 unsigned int n_stops
;
932 _cairo_gradient_pattern_fit_to_range (&pattern
->base
, PIXMAN_MAX_INT
>> 1, &matrix
, extremes
);
934 picture
= (cairo_xcb_picture_t
*)
935 _cairo_xcb_screen_lookup_radial_picture (target
->screen
, pattern
);
939 stops
= _gradient_to_xcb (&pattern
->base
, &n_stops
, buf
, sizeof (buf
));
940 if (unlikely (stops
== NULL
))
941 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY
);
943 picture
= _cairo_xcb_picture_create (target
->screen
,
944 target
->screen
->connection
->standard_formats
[CAIRO_FORMAT_ARGB32
],
947 if (unlikely (picture
->base
.status
)) {
948 if (stops
!= (xcb_render_fixed_t
*) buf
)
952 picture
->filter
= CAIRO_FILTER_DEFAULT
;
954 colors
= (xcb_render_color_t
*) (stops
+ n_stops
);
956 p1
.x
= _cairo_fixed_16_16_from_double (extremes
[0].center
.x
);
957 p1
.y
= _cairo_fixed_16_16_from_double (extremes
[0].center
.y
);
958 p2
.x
= _cairo_fixed_16_16_from_double (extremes
[1].center
.x
);
959 p2
.y
= _cairo_fixed_16_16_from_double (extremes
[1].center
.y
);
961 r1
= _cairo_fixed_16_16_from_double (extremes
[0].radius
);
962 r2
= _cairo_fixed_16_16_from_double (extremes
[1].radius
);
964 _cairo_xcb_connection_render_create_radial_gradient (target
->connection
,
970 if (stops
!= (xcb_render_fixed_t
*) buf
)
973 status
= _cairo_xcb_screen_store_radial_picture (target
->screen
,
976 if (unlikely (status
)) {
977 cairo_surface_destroy (&picture
->base
);
978 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (status
);
982 _cairo_xcb_picture_set_matrix (picture
, &matrix
,
983 pattern
->base
.base
.filter
,
984 extents
->x
+ extents
->width
/2.,
985 extents
->y
+ extents
->height
/2.);
986 _cairo_xcb_picture_set_filter (picture
, pattern
->base
.base
.filter
);
987 _cairo_xcb_picture_set_extend (picture
, pattern
->base
.base
.extend
);
988 _cairo_xcb_picture_set_component_alpha (picture
,
989 pattern
->base
.base
.has_component_alpha
);
994 static cairo_xcb_picture_t
*
995 _copy_to_picture (cairo_xcb_surface_t
*source
)
997 cairo_xcb_picture_t
*picture
;
998 uint32_t values
[] = { 0, 1 };
1000 if (source
->deferred_clear
) {
1001 cairo_status_t status
= _cairo_xcb_surface_clear (source
);
1002 if (unlikely (status
))
1003 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (status
);
1006 picture
= _cairo_xcb_picture_create (source
->screen
,
1007 source
->xrender_format
,
1008 source
->pixman_format
,
1011 if (unlikely (picture
->base
.status
))
1014 _cairo_xcb_connection_render_create_picture (source
->connection
,
1017 source
->xrender_format
,
1018 XCB_RENDER_CP_GRAPHICS_EXPOSURE
|
1019 XCB_RENDER_CP_SUBWINDOW_MODE
,
1026 _cairo_xcb_surface_setup_surface_picture(cairo_xcb_picture_t
*picture
,
1027 const cairo_surface_pattern_t
*pattern
,
1028 const cairo_rectangle_int_t
*extents
)
1030 cairo_filter_t filter
;
1032 filter
= pattern
->base
.filter
;
1033 if (filter
!= CAIRO_FILTER_NEAREST
&&
1034 _cairo_matrix_is_pixel_exact (&pattern
->base
.matrix
))
1036 filter
= CAIRO_FILTER_NEAREST
;
1038 _cairo_xcb_picture_set_filter (picture
, filter
);
1040 _cairo_xcb_picture_set_matrix (picture
,
1041 &pattern
->base
.matrix
, filter
,
1042 extents
->x
+ extents
->width
/2.,
1043 extents
->y
+ extents
->height
/2.);
1046 _cairo_xcb_picture_set_extend (picture
, pattern
->base
.extend
);
1047 _cairo_xcb_picture_set_component_alpha (picture
, pattern
->base
.has_component_alpha
);
1050 static cairo_xcb_picture_t
*
1051 record_to_picture (cairo_surface_t
*target
,
1052 const cairo_surface_pattern_t
*pattern
,
1053 const cairo_rectangle_int_t
*extents
)
1055 cairo_surface_pattern_t tmp_pattern
;
1056 cairo_xcb_picture_t
*picture
;
1057 cairo_status_t status
;
1058 cairo_matrix_t matrix
;
1059 cairo_surface_t
*tmp
;
1060 cairo_surface_t
*source
;
1061 cairo_rectangle_int_t limit
;
1062 cairo_extend_t extend
;
1064 /* XXX: The following was once more or less copied from cairo-xlibs-ource.c,
1065 * record_source() and recording_pattern_get_surface(), can we share a
1069 /* First get the 'real' recording surface and figure out the size for tmp */
1070 source
= _cairo_pattern_get_source (pattern
, &limit
);
1071 assert (_cairo_surface_is_recording (source
));
1073 if (! _cairo_matrix_is_identity (&pattern
->base
.matrix
)) {
1074 double x1
, y1
, x2
, y2
;
1076 matrix
= pattern
->base
.matrix
;
1077 status
= cairo_matrix_invert (&matrix
);
1078 assert (status
== CAIRO_STATUS_SUCCESS
);
1082 x2
= limit
.x
+ limit
.width
;
1083 y2
= limit
.y
+ limit
.height
;
1085 _cairo_matrix_transform_bounding_box (&matrix
,
1086 &x1
, &y1
, &x2
, &y2
, NULL
);
1088 limit
.x
= floor (x1
);
1089 limit
.y
= floor (y1
);
1090 limit
.width
= ceil (x2
) - limit
.x
;
1091 limit
.height
= ceil (y2
) - limit
.y
;
1093 extend
= pattern
->base
.extend
;
1094 if (_cairo_rectangle_contains_rectangle (&limit
, extents
))
1095 extend
= CAIRO_EXTEND_NONE
;
1096 if (extend
== CAIRO_EXTEND_NONE
&& ! _cairo_rectangle_intersect (&limit
, extents
))
1097 return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t
*) target
);
1099 /* Now draw the recording surface to an xcb surface */
1100 tmp
= _cairo_surface_create_scratch (target
,
1104 CAIRO_COLOR_TRANSPARENT
);
1105 if (tmp
->status
!= CAIRO_STATUS_SUCCESS
) {
1106 return (cairo_xcb_picture_t
*) tmp
;
1109 cairo_matrix_init_translate (&matrix
, limit
.x
, limit
.y
);
1110 cairo_matrix_multiply (&matrix
, &matrix
, &pattern
->base
.matrix
);
1112 status
= _cairo_recording_surface_replay_with_clip (source
,
1115 if (unlikely (status
)) {
1116 cairo_surface_destroy (tmp
);
1117 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (status
);
1120 /* Now that we have drawn this to an xcb surface, try again with that */
1121 _cairo_pattern_init_static_copy (&tmp_pattern
.base
, &pattern
->base
);
1122 tmp_pattern
.surface
= tmp
;
1123 cairo_matrix_init_translate (&tmp_pattern
.base
.matrix
, -limit
.x
, -limit
.y
);
1125 picture
= _copy_to_picture ((cairo_xcb_surface_t
*) tmp
);
1126 if (picture
->base
.status
== CAIRO_STATUS_SUCCESS
)
1127 _cairo_xcb_surface_setup_surface_picture (picture
, &tmp_pattern
, extents
);
1128 cairo_surface_destroy (tmp
);
1132 static cairo_xcb_picture_t
*
1133 _cairo_xcb_surface_picture (cairo_xcb_surface_t
*target
,
1134 const cairo_surface_pattern_t
*pattern
,
1135 const cairo_rectangle_int_t
*extents
)
1137 cairo_surface_t
*source
= pattern
->surface
;
1138 cairo_xcb_picture_t
*picture
;
1140 picture
= (cairo_xcb_picture_t
*)
1141 _cairo_surface_has_snapshot (source
, &_cairo_xcb_picture_backend
);
1142 if (picture
!= NULL
) {
1143 if (picture
->screen
== target
->screen
) {
1144 picture
= (cairo_xcb_picture_t
*) cairo_surface_reference (&picture
->base
);
1145 _cairo_xcb_surface_setup_surface_picture (picture
, pattern
, extents
);
1151 if (source
->type
== CAIRO_SURFACE_TYPE_XCB
)
1153 if (_cairo_surface_is_xcb(source
)) {
1154 cairo_xcb_surface_t
*xcb
= (cairo_xcb_surface_t
*) source
;
1155 if (xcb
->screen
== target
->screen
&& xcb
->fallback
== NULL
) {
1156 picture
= _copy_to_picture ((cairo_xcb_surface_t
*) source
);
1157 if (unlikely (picture
->base
.status
))
1160 } else if (source
->backend
->type
== CAIRO_SURFACE_TYPE_SUBSURFACE
) {
1161 cairo_surface_subsurface_t
*sub
= (cairo_surface_subsurface_t
*) source
;
1162 cairo_xcb_surface_t
*xcb
= (cairo_xcb_surface_t
*) sub
->target
;
1164 /* XXX repeat interval with source clipping? */
1165 if (FALSE
&& xcb
->screen
== target
->screen
&& xcb
->fallback
== NULL
) {
1166 xcb_rectangle_t rect
;
1168 picture
= _copy_to_picture (xcb
);
1169 if (unlikely (picture
->base
.status
))
1172 rect
.x
= sub
->extents
.x
;
1173 rect
.y
= sub
->extents
.y
;
1174 rect
.width
= sub
->extents
.width
;
1175 rect
.height
= sub
->extents
.height
;
1177 _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb
->connection
,
1181 picture
->x0
= rect
.x
;
1182 picture
->y0
= rect
.y
;
1183 picture
->width
= rect
.width
;
1184 picture
->height
= rect
.height
;
1186 } else if (_cairo_surface_is_snapshot (source
)) {
1187 cairo_surface_snapshot_t
*snap
= (cairo_surface_snapshot_t
*) source
;
1188 cairo_xcb_surface_t
*xcb
= (cairo_xcb_surface_t
*) snap
->target
;
1190 if (xcb
->screen
== target
->screen
&& xcb
->fallback
== NULL
) {
1191 picture
= _copy_to_picture (xcb
);
1192 if (unlikely (picture
->base
.status
))
1197 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1198 else if (source
->type
== CAIRO_SURFACE_TYPE_XLIB
)
1200 if (source
->backend
->type
== CAIRO_SURFACE_TYPE_XLIB
) {
1201 cairo_xcb_surface_t
*xcb
= ((cairo_xlib_xcb_surface_t
*) source
)->xcb
;
1202 if (xcb
->screen
== target
->screen
&& xcb
->fallback
== NULL
) {
1203 picture
= _copy_to_picture (xcb
);
1204 if (unlikely (picture
->base
.status
))
1207 } else if (source
->backend
->type
== CAIRO_SURFACE_TYPE_SUBSURFACE
) {
1208 cairo_surface_subsurface_t
*sub
= (cairo_surface_subsurface_t
*) source
;
1209 cairo_xcb_surface_t
*xcb
= ((cairo_xlib_xcb_surface_t
*) sub
->target
)->xcb
;
1211 if (FALSE
&& xcb
->screen
== target
->screen
&& xcb
->fallback
== NULL
) {
1212 xcb_rectangle_t rect
;
1214 picture
= _copy_to_picture (xcb
);
1215 if (unlikely (picture
->base
.status
))
1218 rect
.x
= sub
->extents
.x
;
1219 rect
.y
= sub
->extents
.y
;
1220 rect
.width
= sub
->extents
.width
;
1221 rect
.height
= sub
->extents
.height
;
1223 _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb
->connection
,
1227 picture
->x0
= rect
.x
;
1228 picture
->y0
= rect
.y
;
1229 picture
->width
= rect
.width
;
1230 picture
->height
= rect
.height
;
1232 } else if (_cairo_surface_is_snapshot (source
)) {
1233 cairo_surface_snapshot_t
*snap
= (cairo_surface_snapshot_t
*) source
;
1234 cairo_xcb_surface_t
*xcb
= ((cairo_xlib_xcb_surface_t
*) snap
->target
)->xcb
;
1236 if (xcb
->screen
== target
->screen
&& xcb
->fallback
== NULL
) {
1237 picture
= _copy_to_picture (xcb
);
1238 if (unlikely (picture
->base
.status
))
1244 #if CAIRO_HAS_GL_FUNCTIONS
1245 else if (source
->type
== CAIRO_SURFACE_TYPE_GL
)
1247 /* pixmap from texture */
1250 else if (source
->type
== CAIRO_SURFACE_TYPE_RECORDING
)
1252 /* We have to skip the call to attach_snapshot() because we possibly
1253 * only drew part of the recording surface.
1254 * TODO: When can we safely attach a snapshot?
1256 return record_to_picture(&target
->base
, pattern
, extents
);
1259 if (picture
== NULL
) {
1260 cairo_image_surface_t
*image
;
1262 cairo_status_t status
;
1264 status
= _cairo_surface_acquire_source_image (source
, &image
, &image_extra
);
1265 if (unlikely (status
))
1266 return (cairo_xcb_picture_t
*) _cairo_surface_create_in_error (status
);
1268 if (image
->format
!= CAIRO_FORMAT_INVALID
) {
1269 xcb_render_pictformat_t format
;
1271 format
= target
->screen
->connection
->standard_formats
[image
->format
];
1273 picture
= _picture_from_image (target
, format
, image
, NULL
);
1274 _cairo_surface_release_source_image (source
, image
, image_extra
);
1276 cairo_image_surface_t
*conv
;
1277 xcb_render_pictformat_t render_format
;
1279 /* XXX XRenderPutImage! */
1281 conv
= _cairo_image_surface_coerce (image
);
1282 _cairo_surface_release_source_image (source
, image
, image_extra
);
1283 if (unlikely (conv
->base
.status
))
1284 return (cairo_xcb_picture_t
*) conv
;
1286 render_format
= target
->screen
->connection
->standard_formats
[conv
->format
];
1287 picture
= _picture_from_image (target
, render_format
, conv
, NULL
);
1288 cairo_surface_destroy (&conv
->base
);
1291 if (unlikely (picture
->base
.status
))
1295 /* XXX: This causes too many problems and bugs, let's skip it for now. */
1297 _cairo_surface_attach_snapshot (source
,
1302 _cairo_xcb_surface_setup_surface_picture (picture
, pattern
, extents
);
1306 static cairo_xcb_picture_t
*
1307 _cairo_xcb_picture_for_pattern (cairo_xcb_surface_t
*target
,
1308 const cairo_pattern_t
*pattern
,
1309 const cairo_rectangle_int_t
*extents
)
1311 if (pattern
== NULL
)
1312 return _cairo_xcb_white_picture (target
);
1314 if (! _pattern_is_supported (target
->connection
->flags
, pattern
))
1315 return _render_to_picture (target
, pattern
, extents
);
1317 switch (pattern
->type
) {
1318 case CAIRO_PATTERN_TYPE_SOLID
:
1319 return _cairo_xcb_solid_picture (target
, (cairo_solid_pattern_t
*) pattern
);
1321 case CAIRO_PATTERN_TYPE_LINEAR
:
1322 return _cairo_xcb_linear_picture (target
,
1323 (cairo_linear_pattern_t
*) pattern
,
1326 case CAIRO_PATTERN_TYPE_RADIAL
:
1327 return _cairo_xcb_radial_picture (target
,
1328 (cairo_radial_pattern_t
*) pattern
,
1331 case CAIRO_PATTERN_TYPE_SURFACE
:
1332 return _cairo_xcb_surface_picture (target
,
1333 (cairo_surface_pattern_t
*) pattern
,
1337 case CAIRO_PATTERN_TYPE_MESH
:
1338 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
:
1339 return _render_to_picture (target
, pattern
, extents
);
1343 COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t
) <= sizeof (cairo_box_t
));
1345 static cairo_status_t
1346 _render_fill_boxes (void *abstract_dst
,
1347 cairo_operator_t op
,
1348 const cairo_color_t
*color
,
1349 cairo_boxes_t
*boxes
)
1351 cairo_xcb_surface_t
*dst
= abstract_dst
;
1352 xcb_rectangle_t stack_xrects
[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t
)];
1353 xcb_rectangle_t
*xrects
= stack_xrects
;
1354 xcb_render_color_t render_color
;
1355 int render_op
= _render_operator (op
);
1356 struct _cairo_boxes_chunk
*chunk
;
1359 render_color
.red
= color
->red_short
;
1360 render_color
.green
= color
->green_short
;
1361 render_color
.blue
= color
->blue_short
;
1362 render_color
.alpha
= color
->alpha_short
;
1365 for (chunk
= &boxes
->chunks
; chunk
!= NULL
; chunk
= chunk
->next
) {
1366 if (chunk
->count
> max_count
)
1367 max_count
= chunk
->count
;
1369 if (max_count
> ARRAY_LENGTH (stack_xrects
)) {
1370 xrects
= _cairo_malloc_ab (max_count
, sizeof (xcb_rectangle_t
));
1371 if (unlikely (xrects
== NULL
))
1372 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1375 for (chunk
= &boxes
->chunks
; chunk
!= NULL
; chunk
= chunk
->next
) {
1378 for (i
= j
= 0; i
< chunk
->count
; i
++) {
1379 int x1
= _cairo_fixed_integer_round_down (chunk
->base
[i
].p1
.x
);
1380 int y1
= _cairo_fixed_integer_round_down (chunk
->base
[i
].p1
.y
);
1381 int x2
= _cairo_fixed_integer_round_down (chunk
->base
[i
].p2
.x
);
1382 int y2
= _cairo_fixed_integer_round_down (chunk
->base
[i
].p2
.y
);
1384 if (x2
> x1
&& y2
> y1
) {
1387 xrects
[j
].width
= x2
- x1
;
1388 xrects
[j
].height
= y2
- y1
;
1394 _cairo_xcb_connection_render_fill_rectangles
1396 render_op
, dst
->picture
,
1397 render_color
, j
, xrects
);
1401 if (xrects
!= stack_xrects
)
1404 return CAIRO_STATUS_SUCCESS
;
1407 /* pixel aligned, non-overlapping boxes */
1408 static cairo_int_status_t
1409 _render_composite_boxes (cairo_xcb_surface_t
*dst
,
1410 cairo_operator_t op
,
1411 const cairo_pattern_t
*src_pattern
,
1412 const cairo_pattern_t
*mask_pattern
,
1413 const cairo_rectangle_int_t
*extents
,
1414 const cairo_boxes_t
*boxes
)
1416 cairo_xcb_picture_t
*src
, *mask
;
1417 const struct _cairo_boxes_chunk
*chunk
;
1418 xcb_rectangle_t stack_boxes
[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t
)];
1419 xcb_rectangle_t
*clip_boxes
;
1420 cairo_rectangle_int_t stack_extents
;
1421 cairo_status_t status
;
1425 render_op
= _render_operator (op
);
1427 if (src_pattern
== NULL
) {
1428 src_pattern
= mask_pattern
;
1429 mask_pattern
= NULL
;
1432 /* amalgamate into a single Composite call by setting a clip region */
1433 clip_boxes
= stack_boxes
;
1434 if (boxes
->num_boxes
> ARRAY_LENGTH (stack_boxes
)) {
1435 clip_boxes
= _cairo_malloc_ab (boxes
->num_boxes
, sizeof (xcb_rectangle_t
));
1436 if (unlikely (clip_boxes
== NULL
))
1437 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1440 src
= _cairo_xcb_picture_for_pattern (dst
, src_pattern
, extents
);
1441 status
= src
->base
.status
;
1442 if (unlikely (status
))
1446 for (chunk
= &boxes
->chunks
; chunk
!= NULL
; chunk
= chunk
->next
) {
1447 const cairo_box_t
*box
= chunk
->base
;
1450 for (i
= 0; i
< chunk
->count
; i
++) {
1451 int x
= _cairo_fixed_integer_round_down (box
[i
].p1
.x
);
1452 int y
= _cairo_fixed_integer_round_down (box
[i
].p1
.y
);
1453 int width
= _cairo_fixed_integer_round_down (box
[i
].p2
.x
) - x
;
1454 int height
= _cairo_fixed_integer_round_down (box
[i
].p2
.y
) - y
;
1456 if (width
&& height
) {
1457 clip_boxes
[num_boxes
].x
= x
;
1458 clip_boxes
[num_boxes
].y
= y
;
1459 clip_boxes
[num_boxes
].width
= width
;
1460 clip_boxes
[num_boxes
].height
= height
;
1467 if (num_boxes
> 1) {
1468 _cairo_xcb_connection_render_set_picture_clip_rectangles (dst
->connection
,
1474 stack_extents
.x
= clip_boxes
[0].x
;
1475 stack_extents
.y
= clip_boxes
[0].y
;
1476 stack_extents
.width
= clip_boxes
[0].width
;
1477 stack_extents
.height
= clip_boxes
[0].height
;
1478 extents
= &stack_extents
;
1481 if (mask_pattern
!= NULL
) {
1482 mask
= _cairo_xcb_picture_for_pattern (dst
, mask_pattern
, extents
);
1483 status
= mask
->base
.status
;
1484 if (unlikely (status
))
1487 _cairo_xcb_connection_render_composite (dst
->connection
,
1492 src
->x
+ extents
->x
, src
->y
+ extents
->y
,
1493 mask
->x
+ extents
->x
, mask
->y
+ extents
->y
,
1494 extents
->x
, extents
->y
,
1495 extents
->width
, extents
->height
);
1497 cairo_surface_destroy (&mask
->base
);
1499 _cairo_xcb_connection_render_composite (dst
->connection
,
1504 src
->x
+ extents
->x
, src
->y
+ extents
->y
,
1506 extents
->x
, extents
->y
,
1507 extents
->width
, extents
->height
);
1513 _cairo_xcb_surface_clear_clip_region (dst
);
1516 cairo_surface_destroy (&src
->base
);
1520 if (clip_boxes
!= stack_boxes
)
1527 #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
1528 #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
1531 _line_exceeds_16_16 (const cairo_line_t
*line
)
1534 line
->p1
.x
<= CAIRO_FIXED_16_16_MIN
||
1535 line
->p1
.x
>= CAIRO_FIXED_16_16_MAX
||
1537 line
->p2
.x
<= CAIRO_FIXED_16_16_MIN
||
1538 line
->p2
.x
>= CAIRO_FIXED_16_16_MAX
||
1540 line
->p1
.y
<= CAIRO_FIXED_16_16_MIN
||
1541 line
->p1
.y
>= CAIRO_FIXED_16_16_MAX
||
1543 line
->p2
.y
<= CAIRO_FIXED_16_16_MIN
||
1544 line
->p2
.y
>= CAIRO_FIXED_16_16_MAX
;
1548 _project_line_x_onto_16_16 (const cairo_line_t
*line
,
1550 cairo_fixed_t bottom
,
1551 xcb_render_linefix_t
*out
)
1553 cairo_point_double_t p1
, p2
;
1556 p1
.x
= _cairo_fixed_to_double (line
->p1
.x
);
1557 p1
.y
= _cairo_fixed_to_double (line
->p1
.y
);
1559 p2
.x
= _cairo_fixed_to_double (line
->p2
.x
);
1560 p2
.y
= _cairo_fixed_to_double (line
->p2
.y
);
1562 m
= (p2
.x
- p1
.x
) / (p2
.y
- p1
.y
);
1563 out
->p1
.x
= _cairo_fixed_16_16_from_double (p1
.x
+ m
* _cairo_fixed_to_double (top
- line
->p1
.y
));
1564 out
->p2
.x
= _cairo_fixed_16_16_from_double (p1
.x
+ m
* _cairo_fixed_to_double (bottom
- line
->p1
.y
));
1568 cairo_traps_t traps
;
1569 cairo_antialias_t antialias
;
1570 } composite_traps_info_t
;
1572 COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t
) <= sizeof (cairo_trapezoid_t
));
1574 static cairo_int_status_t
1575 _composite_traps (void *closure
,
1576 cairo_xcb_surface_t
*dst
,
1577 cairo_operator_t op
,
1578 const cairo_pattern_t
*pattern
,
1579 int dst_x
, int dst_y
,
1580 const cairo_rectangle_int_t
*extents
,
1583 composite_traps_info_t
*info
= closure
;
1584 const cairo_traps_t
*traps
= &info
->traps
;
1585 cairo_xcb_picture_t
*src
;
1586 cairo_format_t format
;
1587 xcb_render_pictformat_t xrender_format
;
1588 xcb_render_trapezoid_t
*xtraps
;
1589 int render_reference_x
, render_reference_y
;
1590 cairo_status_t status
;
1593 if (dst
->deferred_clear
) {
1594 status
= _cairo_xcb_surface_clear (dst
);
1595 if (unlikely (status
))
1599 src
= _cairo_xcb_picture_for_pattern (dst
, pattern
, extents
);
1600 if (unlikely (src
->base
.status
))
1601 return src
->base
.status
;
1603 if (info
->antialias
== CAIRO_ANTIALIAS_NONE
)
1604 format
= CAIRO_FORMAT_A1
;
1606 format
= CAIRO_FORMAT_A8
;
1607 xrender_format
= dst
->screen
->connection
->standard_formats
[format
];
1609 xtraps
= (xcb_render_trapezoid_t
*) traps
->traps
;
1610 for (i
= 0; i
< traps
->num_traps
; i
++) {
1611 cairo_trapezoid_t t
= traps
->traps
[i
];
1613 /* top/bottom will be clamped to surface bounds */
1614 xtraps
[i
].top
= _cairo_fixed_to_16_16 (t
.top
);
1615 xtraps
[i
].top
-= dst_y
<< 16;
1616 xtraps
[i
].bottom
= _cairo_fixed_to_16_16 (t
.bottom
);
1617 xtraps
[i
].bottom
-= dst_y
<< 16;
1619 /* However, all the other coordinates will have been left untouched so
1620 * as not to introduce numerical error. Recompute them if they
1621 * exceed the 16.16 limits.
1623 if (unlikely (_line_exceeds_16_16 (&t
.left
))) {
1624 _project_line_x_onto_16_16 (&t
.left
,
1628 xtraps
[i
].left
.p1
.y
= xtraps
[i
].top
;
1629 xtraps
[i
].left
.p2
.y
= xtraps
[i
].bottom
;
1631 xtraps
[i
].left
.p1
.x
= _cairo_fixed_to_16_16 (t
.left
.p1
.x
);
1632 xtraps
[i
].left
.p1
.y
= _cairo_fixed_to_16_16 (t
.left
.p1
.y
);
1633 xtraps
[i
].left
.p2
.x
= _cairo_fixed_to_16_16 (t
.left
.p2
.x
);
1634 xtraps
[i
].left
.p2
.y
= _cairo_fixed_to_16_16 (t
.left
.p2
.y
);
1636 xtraps
[i
].left
.p1
.x
-= dst_x
<< 16;
1637 xtraps
[i
].left
.p1
.y
-= dst_y
<< 16;
1638 xtraps
[i
].left
.p2
.x
-= dst_x
<< 16;
1639 xtraps
[i
].left
.p2
.y
-= dst_y
<< 16;
1641 if (unlikely (_line_exceeds_16_16 (&t
.right
))) {
1642 _project_line_x_onto_16_16 (&t
.right
,
1646 xtraps
[i
].right
.p1
.y
= xtraps
[i
].top
;
1647 xtraps
[i
].right
.p2
.y
= xtraps
[i
].bottom
;
1649 xtraps
[i
].right
.p1
.x
= _cairo_fixed_to_16_16 (t
.right
.p1
.x
);
1650 xtraps
[i
].right
.p1
.y
= _cairo_fixed_to_16_16 (t
.right
.p1
.y
);
1651 xtraps
[i
].right
.p2
.x
= _cairo_fixed_to_16_16 (t
.right
.p2
.x
);
1652 xtraps
[i
].right
.p2
.y
= _cairo_fixed_to_16_16 (t
.right
.p2
.y
);
1654 xtraps
[i
].right
.p1
.x
-= dst_x
<< 16;
1655 xtraps
[i
].right
.p1
.y
-= dst_y
<< 16;
1656 xtraps
[i
].right
.p2
.x
-= dst_x
<< 16;
1657 xtraps
[i
].right
.p2
.y
-= dst_y
<< 16;
1660 if (xtraps
[0].left
.p1
.y
< xtraps
[0].left
.p2
.y
) {
1661 render_reference_x
= xtraps
[0].left
.p1
.x
>> 16;
1662 render_reference_y
= xtraps
[0].left
.p1
.y
>> 16;
1664 render_reference_x
= xtraps
[0].left
.p2
.x
>> 16;
1665 render_reference_y
= xtraps
[0].left
.p2
.y
>> 16;
1667 render_reference_x
+= src
->x
+ dst_x
;
1668 render_reference_y
+= src
->y
+ dst_y
;
1670 _cairo_xcb_surface_set_precision (dst
, info
->antialias
);
1671 _cairo_xcb_connection_render_trapezoids (dst
->connection
,
1672 _render_operator (op
),
1678 traps
->num_traps
, xtraps
);
1680 cairo_surface_destroy (&src
->base
);
1682 return CAIRO_STATUS_SUCCESS
;
1685 /* low-level composite driver */
1687 static cairo_xcb_surface_t
*
1688 get_clip_surface (const cairo_clip_t
*clip
,
1689 cairo_xcb_surface_t
*target
,
1692 cairo_surface_t
*surface
;
1693 cairo_status_t status
;
1695 surface
= _cairo_surface_create_scratch (&target
->base
,
1696 CAIRO_CONTENT_ALPHA
,
1697 clip
->extents
.width
,
1698 clip
->extents
.height
,
1700 if (unlikely (surface
->status
))
1701 return (cairo_xcb_surface_t
*) surface
;
1703 assert (surface
->backend
== &_cairo_xcb_surface_backend
);
1704 status
= _cairo_clip_combine_with_surface (clip
, surface
,
1705 clip
->extents
.x
, clip
->extents
.y
);
1706 if (unlikely (status
)) {
1707 cairo_surface_destroy (surface
);
1708 surface
= _cairo_surface_create_in_error (status
);
1711 *tx
= clip
->extents
.x
;
1712 *ty
= clip
->extents
.y
;
1714 return (cairo_xcb_surface_t
*) surface
;
1717 typedef cairo_int_status_t
1718 (*xcb_draw_func_t
) (void *closure
,
1719 cairo_xcb_surface_t
*dst
,
1720 cairo_operator_t op
,
1721 const cairo_pattern_t
*src
,
1724 const cairo_rectangle_int_t
*extents
,
1725 cairo_clip_t
*clip
);
1727 static void do_unaligned_row(void (*blt
)(void *closure
,
1728 int16_t x
, int16_t y
,
1729 int16_t w
, int16_t h
,
1732 const cairo_box_t
*b
,
1733 int tx
, int y
, int h
,
1736 int x1
= _cairo_fixed_integer_part (b
->p1
.x
) - tx
;
1737 int x2
= _cairo_fixed_integer_part (b
->p2
.x
) - tx
;
1739 if (! _cairo_fixed_is_integer (b
->p1
.x
)) {
1740 blt(closure
, x1
, y
, 1, h
,
1741 coverage
* (256 - _cairo_fixed_fractional_part (b
->p1
.x
)));
1746 blt(closure
, x1
, y
, x2
-x1
, h
, (coverage
<< 8) - (coverage
>> 8));
1748 if (! _cairo_fixed_is_integer (b
->p2
.x
))
1749 blt(closure
, x2
, y
, 1, h
,
1750 coverage
* _cairo_fixed_fractional_part (b
->p2
.x
));
1752 blt(closure
, x1
, y
, 1, h
,
1753 coverage
* (b
->p2
.x
- b
->p1
.x
));
1756 static void do_unaligned_box(void (*blt
)(void *closure
,
1757 int16_t x
, int16_t y
,
1758 int16_t w
, int16_t h
,
1761 const cairo_box_t
*b
, int tx
, int ty
)
1763 int y1
= _cairo_fixed_integer_part (b
->p1
.y
) - ty
;
1764 int y2
= _cairo_fixed_integer_part (b
->p2
.y
) - ty
;
1766 if (! _cairo_fixed_is_integer (b
->p1
.y
)) {
1767 do_unaligned_row(blt
, closure
, b
, tx
, y1
, 1,
1768 256 - _cairo_fixed_fractional_part (b
->p1
.y
));
1773 do_unaligned_row(blt
, closure
, b
, tx
, y1
, y2
-y1
, 256);
1775 if (! _cairo_fixed_is_integer (b
->p2
.y
))
1776 do_unaligned_row(blt
, closure
, b
, tx
, y2
, 1,
1777 _cairo_fixed_fractional_part (b
->p2
.y
));
1779 do_unaligned_row(blt
, closure
, b
, tx
, y1
, 1,
1784 static void blt_in(void *closure
,
1785 int16_t x
, int16_t y
,
1786 int16_t w
, int16_t h
,
1789 cairo_xcb_surface_t
*mask
= closure
;
1790 xcb_render_color_t color
;
1791 xcb_rectangle_t rect
;
1793 if (coverage
== 0xffff)
1796 color
.red
= color
.green
= color
.blue
= 0;
1797 color
.alpha
= coverage
;
1804 _cairo_xcb_connection_render_fill_rectangles (mask
->connection
,
1805 XCB_RENDER_PICT_OP_IN
,
1810 static cairo_xcb_surface_t
*
1811 _create_composite_mask (cairo_clip_t
*clip
,
1812 xcb_draw_func_t draw_func
,
1813 xcb_draw_func_t mask_func
,
1815 cairo_xcb_surface_t
*dst
,
1816 const cairo_rectangle_int_t
*extents
)
1818 cairo_xcb_surface_t
*surface
;
1819 cairo_bool_t need_clip_combine
;
1820 cairo_int_status_t status
;
1822 surface
= (cairo_xcb_surface_t
*)
1823 _cairo_xcb_surface_create_similar (dst
, CAIRO_CONTENT_ALPHA
,
1824 extents
->width
, extents
->height
);
1825 if (unlikely (surface
->base
.status
))
1828 _cairo_xcb_surface_ensure_picture (surface
);
1830 surface
->deferred_clear_color
= *CAIRO_COLOR_TRANSPARENT
;
1831 surface
->deferred_clear
= TRUE
;
1832 surface
->base
.is_clear
= TRUE
;
1835 status
= mask_func (draw_closure
, surface
,
1836 CAIRO_OPERATOR_ADD
, NULL
,
1837 extents
->x
, extents
->y
,
1839 if (likely (status
!= CAIRO_INT_STATUS_UNSUPPORTED
))
1843 /* Is it worth setting the clip region here? */
1844 status
= draw_func (draw_closure
, surface
,
1845 CAIRO_OPERATOR_ADD
, NULL
,
1846 extents
->x
, extents
->y
,
1848 if (unlikely (status
)) {
1849 cairo_surface_destroy (&surface
->base
);
1850 return (cairo_xcb_surface_t
*) _cairo_surface_create_in_error (status
);
1853 if (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
) {
1856 for (i
= 0; i
< clip
->num_boxes
; i
++) {
1857 cairo_box_t
*b
= &clip
->boxes
[i
];
1859 if (! _cairo_fixed_is_integer (b
->p1
.x
) ||
1860 ! _cairo_fixed_is_integer (b
->p1
.y
) ||
1861 ! _cairo_fixed_is_integer (b
->p2
.x
) ||
1862 ! _cairo_fixed_is_integer (b
->p2
.y
))
1864 do_unaligned_box(blt_in
, surface
, b
, extents
->x
, extents
->y
);
1868 need_clip_combine
= clip
->path
!= NULL
;
1870 need_clip_combine
= ! _cairo_clip_is_region (clip
);
1872 if (need_clip_combine
) {
1873 status
= _cairo_clip_combine_with_surface (clip
, &surface
->base
,
1874 extents
->x
, extents
->y
);
1875 if (unlikely (status
)) {
1876 cairo_surface_destroy (&surface
->base
);
1877 return (cairo_xcb_surface_t
*) _cairo_surface_create_in_error (status
);
1884 /* Handles compositing with a clip surface when the operator allows
1885 * us to combine the clip with the mask
1887 static cairo_status_t
1888 _clip_and_composite_with_mask (cairo_clip_t
*clip
,
1889 cairo_operator_t op
,
1890 const cairo_pattern_t
*pattern
,
1891 xcb_draw_func_t draw_func
,
1892 xcb_draw_func_t mask_func
,
1894 cairo_xcb_surface_t
*dst
,
1895 const cairo_rectangle_int_t
*extents
)
1897 cairo_xcb_surface_t
*mask
;
1898 cairo_xcb_picture_t
*src
;
1900 mask
= _create_composite_mask (clip
,
1901 draw_func
, mask_func
, draw_closure
,
1903 if (unlikely (mask
->base
.status
))
1904 return mask
->base
.status
;
1906 if (pattern
!= NULL
|| dst
->base
.content
!= CAIRO_CONTENT_ALPHA
) {
1907 src
= _cairo_xcb_picture_for_pattern (dst
, pattern
, extents
);
1908 if (unlikely (src
->base
.status
)) {
1909 cairo_surface_destroy (&mask
->base
);
1910 return src
->base
.status
;
1913 _cairo_xcb_connection_render_composite (dst
->connection
,
1914 _render_operator (op
),
1918 extents
->x
+ src
->x
, extents
->y
+ src
->y
,
1920 extents
->x
, extents
->y
,
1921 extents
->width
, extents
->height
);
1923 cairo_surface_destroy (&src
->base
);
1925 _cairo_xcb_connection_render_composite (dst
->connection
,
1926 _render_operator (op
),
1932 extents
->x
, extents
->y
,
1933 extents
->width
, extents
->height
);
1935 cairo_surface_destroy (&mask
->base
);
1937 return CAIRO_STATUS_SUCCESS
;
1940 /* Handles compositing with a clip surface when we have to do the operation
1941 * in two pieces and combine them together.
1943 static cairo_status_t
1944 _clip_and_composite_combine (cairo_clip_t
*clip
,
1945 cairo_operator_t op
,
1946 const cairo_pattern_t
*pattern
,
1947 xcb_draw_func_t draw_func
,
1949 cairo_xcb_surface_t
*dst
,
1950 const cairo_rectangle_int_t
*extents
)
1952 cairo_xcb_surface_t
*tmp
;
1953 cairo_xcb_surface_t
*clip_surface
;
1954 int clip_x
= 0, clip_y
= 0;
1955 xcb_render_picture_t clip_picture
;
1956 cairo_status_t status
;
1958 tmp
= (cairo_xcb_surface_t
*)
1959 _cairo_xcb_surface_create_similar (dst
, dst
->base
.content
,
1960 extents
->width
, extents
->height
);
1961 if (unlikely (tmp
->base
.status
))
1962 return tmp
->base
.status
;
1964 /* create_similar() could have done a fallback to an image surface */
1965 assert (tmp
->base
.backend
== &_cairo_xcb_surface_backend
);
1967 _cairo_xcb_surface_ensure_picture (tmp
);
1969 if (pattern
== NULL
) {
1970 status
= (*draw_func
) (draw_closure
, tmp
,
1971 CAIRO_OPERATOR_ADD
, NULL
,
1972 extents
->x
, extents
->y
,
1975 /* Initialize the temporary surface from the destination surface */
1976 if (! dst
->base
.is_clear
||
1977 (dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
) == 0)
1979 /* XCopyArea may actually be quicker here.
1980 * A good driver should translate if appropriate.
1982 _cairo_xcb_connection_render_composite (dst
->connection
,
1983 XCB_RENDER_PICT_OP_SRC
,
1987 extents
->x
, extents
->y
,
1990 extents
->width
, extents
->height
);
1994 xcb_render_color_t clear
;
1995 xcb_rectangle_t xrect
;
1997 clear
.red
= clear
.green
= clear
.blue
= clear
.alpha
= 0;
1999 xrect
.x
= xrect
.y
= 0;
2000 xrect
.width
= extents
->width
;
2001 xrect
.height
= extents
->height
;
2003 _cairo_xcb_connection_render_fill_rectangles (dst
->connection
,
2004 XCB_RENDER_PICT_OP_CLEAR
,
2009 status
= (*draw_func
) (draw_closure
, tmp
, op
, pattern
,
2010 extents
->x
, extents
->y
,
2013 if (unlikely (status
))
2014 goto CLEANUP_SURFACE
;
2016 clip_surface
= get_clip_surface (clip
, dst
, &clip_x
, &clip_y
);
2017 status
= clip_surface
->base
.status
;
2018 if (unlikely (status
))
2019 goto CLEANUP_SURFACE
;
2021 assert (clip_surface
->base
.backend
== &_cairo_xcb_surface_backend
);
2022 clip_picture
= clip_surface
->picture
;
2023 assert (clip_picture
!= XCB_NONE
);
2025 if (dst
->base
.is_clear
) {
2026 _cairo_xcb_connection_render_composite (dst
->connection
,
2027 XCB_RENDER_PICT_OP_SRC
,
2028 tmp
->picture
, clip_picture
, dst
->picture
,
2031 extents
->x
, extents
->y
,
2032 extents
->width
, extents
->height
);
2034 /* Punch the clip out of the destination */
2035 _cairo_xcb_connection_render_composite (dst
->connection
,
2036 XCB_RENDER_PICT_OP_OUT_REVERSE
,
2037 clip_picture
, XCB_NONE
, dst
->picture
,
2038 extents
->x
- clip_x
,
2039 extents
->y
- clip_y
,
2041 extents
->x
, extents
->y
,
2042 extents
->width
, extents
->height
);
2044 /* Now add the two results together */
2045 _cairo_xcb_connection_render_composite (dst
->connection
,
2046 XCB_RENDER_PICT_OP_ADD
,
2047 tmp
->picture
, clip_picture
, dst
->picture
,
2049 extents
->x
- clip_x
,
2050 extents
->y
- clip_y
,
2051 extents
->x
, extents
->y
,
2052 extents
->width
, extents
->height
);
2054 cairo_surface_destroy (&clip_surface
->base
);
2057 cairo_surface_destroy (&tmp
->base
);
2062 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
2063 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
2065 static cairo_status_t
2066 _clip_and_composite_source (cairo_clip_t
*clip
,
2067 const cairo_pattern_t
*pattern
,
2068 xcb_draw_func_t draw_func
,
2069 xcb_draw_func_t mask_func
,
2071 cairo_xcb_surface_t
*dst
,
2072 const cairo_rectangle_int_t
*extents
)
2074 cairo_xcb_surface_t
*mask
;
2075 cairo_xcb_picture_t
*src
;
2077 /* Create a surface that is mask IN clip */
2078 mask
= _create_composite_mask (clip
,
2079 draw_func
, mask_func
, draw_closure
,
2081 if (unlikely (mask
->base
.status
))
2082 return mask
->base
.status
;
2084 src
= _cairo_xcb_picture_for_pattern (dst
, pattern
, extents
);
2085 if (unlikely (src
->base
.status
)) {
2086 cairo_surface_destroy (&mask
->base
);
2087 return src
->base
.status
;
2090 if (dst
->base
.is_clear
) {
2091 _cairo_xcb_connection_render_composite (dst
->connection
,
2092 XCB_RENDER_PICT_OP_SRC
,
2096 extents
->x
+ src
->x
, extents
->y
+ src
->y
,
2098 extents
->x
, extents
->y
,
2099 extents
->width
, extents
->height
);
2101 /* Compute dest' = dest OUT (mask IN clip) */
2102 _cairo_xcb_connection_render_composite (dst
->connection
,
2103 XCB_RENDER_PICT_OP_OUT_REVERSE
,
2108 extents
->x
, extents
->y
,
2109 extents
->width
, extents
->height
);
2111 /* Now compute (src IN (mask IN clip)) ADD dest' */
2112 _cairo_xcb_connection_render_composite (dst
->connection
,
2113 XCB_RENDER_PICT_OP_ADD
,
2117 extents
->x
+ src
->x
, extents
->y
+ src
->y
,
2119 extents
->x
, extents
->y
,
2120 extents
->width
, extents
->height
);
2123 cairo_surface_destroy (&src
->base
);
2124 cairo_surface_destroy (&mask
->base
);
2126 return CAIRO_STATUS_SUCCESS
;
2130 can_reduce_alpha_op (cairo_operator_t op
)
2134 case CAIRO_OPERATOR_OVER
:
2135 case CAIRO_OPERATOR_SOURCE
:
2136 case CAIRO_OPERATOR_ADD
:
2144 reduce_alpha_op (cairo_surface_t
*dst
,
2145 cairo_operator_t op
,
2146 const cairo_pattern_t
*pattern
)
2148 return dst
->is_clear
&&
2149 dst
->content
== CAIRO_CONTENT_ALPHA
&&
2150 _cairo_pattern_is_opaque_solid (pattern
) &&
2151 can_reduce_alpha_op (op
);
2154 static cairo_status_t
2155 _cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t
*dst
,
2156 const cairo_composite_rectangles_t
*rects
)
2158 xcb_rectangle_t xrects
[4];
2161 if (rects
->bounded
.width
== rects
->unbounded
.width
&&
2162 rects
->bounded
.height
== rects
->unbounded
.height
)
2164 return CAIRO_STATUS_SUCCESS
;
2168 if (rects
->bounded
.width
== 0 || rects
->bounded
.height
== 0) {
2169 xrects
[n
].x
= rects
->unbounded
.x
;
2170 xrects
[n
].width
= rects
->unbounded
.width
;
2171 xrects
[n
].y
= rects
->unbounded
.y
;
2172 xrects
[n
].height
= rects
->unbounded
.height
;
2176 if (rects
->bounded
.y
!= rects
->unbounded
.y
) {
2177 xrects
[n
].x
= rects
->unbounded
.x
;
2178 xrects
[n
].width
= rects
->unbounded
.width
;
2179 xrects
[n
].y
= rects
->unbounded
.y
;
2180 xrects
[n
].height
= rects
->bounded
.y
- rects
->unbounded
.y
;
2184 if (rects
->bounded
.x
!= rects
->unbounded
.x
) {
2185 xrects
[n
].x
= rects
->unbounded
.x
;
2186 xrects
[n
].width
= rects
->bounded
.x
- rects
->unbounded
.x
;
2187 xrects
[n
].y
= rects
->bounded
.y
;
2188 xrects
[n
].height
= rects
->bounded
.height
;
2192 if (rects
->bounded
.x
+ rects
->bounded
.width
!= rects
->unbounded
.x
+ rects
->unbounded
.width
) {
2193 xrects
[n
].x
= rects
->bounded
.x
+ rects
->bounded
.width
;
2194 xrects
[n
].width
= rects
->unbounded
.x
+ rects
->unbounded
.width
- xrects
[n
].x
;
2195 xrects
[n
].y
= rects
->bounded
.y
;
2196 xrects
[n
].height
= rects
->bounded
.height
;
2200 if (rects
->bounded
.y
+ rects
->bounded
.height
!= rects
->unbounded
.y
+ rects
->unbounded
.height
) {
2201 xrects
[n
].x
= rects
->unbounded
.x
;
2202 xrects
[n
].width
= rects
->unbounded
.width
;
2203 xrects
[n
].y
= rects
->bounded
.y
+ rects
->bounded
.height
;
2204 xrects
[n
].height
= rects
->unbounded
.y
+ rects
->unbounded
.height
- xrects
[n
].y
;
2209 if (dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
) {
2210 xcb_render_color_t color
;
2217 _cairo_xcb_connection_render_fill_rectangles (dst
->connection
,
2218 XCB_RENDER_PICT_OP_CLEAR
,
2223 cairo_xcb_picture_t
*src
;
2225 src
= _cairo_xcb_transparent_picture (dst
);
2226 if (unlikely (src
->base
.status
))
2227 return src
->base
.status
;
2229 for (i
= 0; i
< n
; i
++) {
2230 _cairo_xcb_connection_render_composite (dst
->connection
,
2231 XCB_RENDER_PICT_OP_CLEAR
,
2232 src
->picture
, XCB_NONE
, dst
->picture
,
2235 xrects
[i
].x
, xrects
[i
].y
,
2236 xrects
[i
].width
, xrects
[i
].height
);
2238 cairo_surface_destroy (&src
->base
);
2241 return CAIRO_STATUS_SUCCESS
;
2244 static cairo_status_t
2245 _cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t
*dst
,
2246 const cairo_composite_rectangles_t
*rects
,
2249 cairo_xcb_surface_t
*mask
;
2250 int mask_x
= 0, mask_y
= 0;
2252 mask
= get_clip_surface (clip
, dst
, &mask_x
, &mask_y
);
2253 if (unlikely (mask
->base
.status
))
2254 return mask
->base
.status
;
2257 if (rects
->bounded
.y
!= rects
->unbounded
.y
) {
2258 int x
= rects
->unbounded
.x
;
2259 int y
= rects
->unbounded
.y
;
2260 int width
= rects
->unbounded
.width
;
2261 int height
= rects
->bounded
.y
- y
;
2263 _cairo_xcb_connection_render_composite (dst
->connection
,
2264 XCB_RENDER_PICT_OP_OUT_REVERSE
,
2265 mask
->picture
, XCB_NONE
, dst
->picture
,
2266 x
- mask_x
, y
- mask_y
,
2273 if (rects
->bounded
.x
!= rects
->unbounded
.x
) {
2274 int x
= rects
->unbounded
.x
;
2275 int y
= rects
->bounded
.y
;
2276 int width
= rects
->bounded
.x
- x
;
2277 int height
= rects
->bounded
.height
;
2279 _cairo_xcb_connection_render_composite (dst
->connection
,
2280 XCB_RENDER_PICT_OP_OUT_REVERSE
,
2281 mask
->picture
, XCB_NONE
, dst
->picture
,
2282 x
- mask_x
, y
- mask_y
,
2289 if (rects
->bounded
.x
+ rects
->bounded
.width
!= rects
->unbounded
.x
+ rects
->unbounded
.width
) {
2290 int x
= rects
->bounded
.x
+ rects
->bounded
.width
;
2291 int y
= rects
->bounded
.y
;
2292 int width
= rects
->unbounded
.x
+ rects
->unbounded
.width
- x
;
2293 int height
= rects
->bounded
.height
;
2295 _cairo_xcb_connection_render_composite (dst
->connection
,
2296 XCB_RENDER_PICT_OP_OUT_REVERSE
,
2297 mask
->picture
, XCB_NONE
, dst
->picture
,
2298 x
- mask_x
, y
- mask_y
,
2305 if (rects
->bounded
.y
+ rects
->bounded
.height
!= rects
->unbounded
.y
+ rects
->unbounded
.height
) {
2306 int x
= rects
->unbounded
.x
;
2307 int y
= rects
->bounded
.y
+ rects
->bounded
.height
;
2308 int width
= rects
->unbounded
.width
;
2309 int height
= rects
->unbounded
.y
+ rects
->unbounded
.height
- y
;
2311 _cairo_xcb_connection_render_composite (dst
->connection
,
2312 XCB_RENDER_PICT_OP_OUT_REVERSE
,
2313 mask
->picture
, XCB_NONE
, dst
->picture
,
2314 x
- mask_x
, y
- mask_y
,
2320 cairo_surface_destroy (&mask
->base
);
2322 return CAIRO_STATUS_SUCCESS
;
2325 static cairo_status_t
2326 _cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t
*dst
,
2327 const cairo_composite_rectangles_t
*extents
,
2329 cairo_boxes_t
*boxes
)
2331 cairo_boxes_t clear
;
2333 cairo_status_t status
;
2334 struct _cairo_boxes_chunk
*chunk
;
2337 if (boxes
->num_boxes
<= 1 && clip
== NULL
)
2338 return _cairo_xcb_surface_fixup_unbounded (dst
, extents
);
2340 _cairo_boxes_init (&clear
);
2342 box
.p1
.x
= _cairo_fixed_from_int (extents
->unbounded
.x
+ extents
->unbounded
.width
);
2343 box
.p1
.y
= _cairo_fixed_from_int (extents
->unbounded
.y
);
2344 box
.p2
.x
= _cairo_fixed_from_int (extents
->unbounded
.x
);
2345 box
.p2
.y
= _cairo_fixed_from_int (extents
->unbounded
.y
+ extents
->unbounded
.height
);
2350 _cairo_boxes_init (&tmp
);
2352 status
= _cairo_boxes_add (&tmp
, CAIRO_ANTIALIAS_DEFAULT
, &box
);
2353 assert (status
== CAIRO_STATUS_SUCCESS
);
2355 tmp
.chunks
.next
= &boxes
->chunks
;
2356 tmp
.num_boxes
+= boxes
->num_boxes
;
2358 status
= _cairo_bentley_ottmann_tessellate_boxes (&tmp
,
2359 CAIRO_FILL_RULE_WINDING
,
2362 tmp
.chunks
.next
= NULL
;
2364 _cairo_boxes_init_with_clip (&clear
, clip
);
2366 status
= _cairo_boxes_add (&clear
, CAIRO_ANTIALIAS_DEFAULT
, &box
);
2367 assert (status
== CAIRO_STATUS_SUCCESS
);
2369 for (chunk
= &boxes
->chunks
; chunk
!= NULL
; chunk
= chunk
->next
) {
2370 for (i
= 0; i
< chunk
->count
; i
++) {
2371 status
= _cairo_boxes_add (&clear
,
2372 CAIRO_ANTIALIAS_DEFAULT
,
2374 if (unlikely (status
)) {
2375 _cairo_boxes_fini (&clear
);
2381 status
= _cairo_bentley_ottmann_tessellate_boxes (&clear
,
2382 CAIRO_FILL_RULE_WINDING
,
2386 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
2387 if (dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
)
2388 status
= _render_fill_boxes (dst
,
2389 CAIRO_OPERATOR_CLEAR
,
2390 CAIRO_COLOR_TRANSPARENT
,
2393 status
= _cairo_xcb_surface_core_fill_boxes (dst
,
2394 CAIRO_COLOR_TRANSPARENT
,
2398 _cairo_boxes_fini (&clear
);
2404 _cairo_xcb_surface_clear (cairo_xcb_surface_t
*dst
)
2407 xcb_rectangle_t rect
;
2408 cairo_status_t status
;
2410 status
= _cairo_xcb_connection_acquire (dst
->connection
);
2411 if (unlikely (status
))
2414 rect
.x
= rect
.y
= 0;
2415 rect
.width
= dst
->width
;
2416 rect
.height
= dst
->height
;
2418 if (dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
) {
2419 xcb_render_color_t color
;
2422 color
.red
= dst
->deferred_clear_color
.red_short
;
2423 color
.green
= dst
->deferred_clear_color
.green_short
;
2424 color
.blue
= dst
->deferred_clear_color
.blue_short
;
2425 color
.alpha
= dst
->deferred_clear_color
.alpha_short
;
2427 if (color
.alpha
== 0)
2428 op
= XCB_RENDER_PICT_OP_CLEAR
;
2430 op
= XCB_RENDER_PICT_OP_SRC
;
2432 _cairo_xcb_surface_ensure_picture (dst
);
2433 _cairo_xcb_connection_render_fill_rectangles (dst
->connection
,
2434 op
, dst
->picture
, color
,
2437 gc
= _cairo_xcb_screen_get_gc (dst
->screen
, dst
->drawable
, dst
->depth
);
2440 _cairo_xcb_connection_poly_fill_rectangle (dst
->connection
,
2444 _cairo_xcb_screen_put_gc (dst
->screen
, dst
->depth
, gc
);
2447 _cairo_xcb_connection_release (dst
->connection
);
2449 dst
->deferred_clear
= FALSE
;
2450 return CAIRO_STATUS_SUCCESS
;
2454 NEED_CLIP_REGION
= 0x1,
2455 NEED_CLIP_SURFACE
= 0x2,
2456 FORCE_CLIP_REGION
= 0x4,
2460 need_bounded_clip (cairo_composite_rectangles_t
*extents
)
2462 unsigned int flags
= NEED_CLIP_REGION
;
2463 if (! _cairo_clip_is_region (extents
->clip
))
2464 flags
|= NEED_CLIP_SURFACE
;
2469 need_unbounded_clip (cairo_composite_rectangles_t
*extents
)
2471 unsigned int flags
= 0;
2472 if (! extents
->is_bounded
) {
2473 flags
|= NEED_CLIP_REGION
;
2474 if (! _cairo_clip_is_region (extents
->clip
))
2475 flags
|= NEED_CLIP_SURFACE
;
2477 if (extents
->clip
->path
!= NULL
)
2478 flags
|= NEED_CLIP_SURFACE
;
2482 static cairo_status_t
2483 _clip_and_composite (cairo_xcb_surface_t
*dst
,
2484 cairo_operator_t op
,
2485 const cairo_pattern_t
*src
,
2486 xcb_draw_func_t draw_func
,
2487 xcb_draw_func_t mask_func
,
2489 cairo_composite_rectangles_t
*extents
,
2490 unsigned int need_clip
)
2492 cairo_region_t
*clip_region
= NULL
;
2493 cairo_status_t status
;
2495 status
= _cairo_xcb_connection_acquire (dst
->connection
);
2496 if (unlikely (status
))
2499 if (dst
->deferred_clear
) {
2500 status
= _cairo_xcb_surface_clear (dst
);
2501 if (unlikely (status
)) {
2502 _cairo_xcb_connection_release (dst
->connection
);
2507 _cairo_xcb_surface_ensure_picture (dst
);
2509 if (need_clip
& NEED_CLIP_REGION
) {
2510 clip_region
= _cairo_clip_get_region (extents
->clip
);
2511 if ((need_clip
& FORCE_CLIP_REGION
) == 0 && clip_region
!= NULL
&&
2512 cairo_region_contains_rectangle (clip_region
,
2513 &extents
->unbounded
) == CAIRO_REGION_OVERLAP_IN
)
2515 if (clip_region
!= NULL
) {
2516 status
= _cairo_xcb_surface_set_clip_region (dst
, clip_region
);
2517 if (unlikely (status
)) {
2518 _cairo_xcb_connection_release (dst
->connection
);
2524 if (reduce_alpha_op (&dst
->base
, op
, src
)) {
2525 op
= CAIRO_OPERATOR_ADD
;
2529 if (extents
->bounded
.width
!= 0 && extents
->bounded
.height
!= 0) {
2530 if (op
== CAIRO_OPERATOR_SOURCE
) {
2531 status
= _clip_and_composite_source (extents
->clip
, src
,
2532 draw_func
, mask_func
, draw_closure
,
2533 dst
, &extents
->bounded
);
2535 if (op
== CAIRO_OPERATOR_CLEAR
) {
2536 op
= CAIRO_OPERATOR_DEST_OUT
;
2540 if (need_clip
& NEED_CLIP_SURFACE
) {
2541 if (extents
->is_bounded
) {
2542 status
= _clip_and_composite_with_mask (extents
->clip
, op
, src
,
2546 dst
, &extents
->bounded
);
2548 status
= _clip_and_composite_combine (extents
->clip
, op
, src
,
2549 draw_func
, draw_closure
,
2550 dst
, &extents
->bounded
);
2553 status
= draw_func (draw_closure
,
2562 if (status
== CAIRO_STATUS_SUCCESS
&& ! extents
->is_bounded
) {
2563 if (need_clip
& NEED_CLIP_SURFACE
)
2564 status
= _cairo_xcb_surface_fixup_unbounded_with_mask (dst
, extents
, extents
->clip
);
2566 status
= _cairo_xcb_surface_fixup_unbounded (dst
, extents
);
2570 _cairo_xcb_surface_clear_clip_region (dst
);
2572 _cairo_xcb_connection_release (dst
->connection
);
2577 static cairo_status_t
2578 _core_boxes (cairo_xcb_surface_t
*dst
,
2579 cairo_operator_t op
,
2580 const cairo_pattern_t
*src
,
2581 cairo_boxes_t
*boxes
,
2582 const cairo_composite_rectangles_t
*extents
)
2584 if (! boxes
->is_pixel_aligned
)
2585 return CAIRO_INT_STATUS_UNSUPPORTED
;
2587 if (! _cairo_clip_is_region (extents
->clip
))
2588 return CAIRO_INT_STATUS_UNSUPPORTED
;
2590 if (op
== CAIRO_OPERATOR_CLEAR
)
2591 return _cairo_xcb_surface_core_fill_boxes (dst
, CAIRO_COLOR_TRANSPARENT
, boxes
);
2593 if (op
== CAIRO_OPERATOR_OVER
) {
2594 if (dst
->base
.is_clear
|| _cairo_pattern_is_opaque (src
, &extents
->bounded
))
2595 op
= CAIRO_OPERATOR_SOURCE
;
2597 if (op
!= CAIRO_OPERATOR_SOURCE
)
2598 return CAIRO_INT_STATUS_UNSUPPORTED
;
2600 if (src
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
2601 return _cairo_xcb_surface_core_fill_boxes (dst
,
2602 &((cairo_solid_pattern_t
*) src
)->color
,
2606 return _cairo_xcb_surface_core_copy_boxes (dst
, src
, &extents
->bounded
, boxes
);
2609 static cairo_status_t
2610 _composite_boxes (cairo_xcb_surface_t
*dst
,
2611 cairo_operator_t op
,
2612 const cairo_pattern_t
*src
,
2613 cairo_boxes_t
*boxes
,
2614 const cairo_composite_rectangles_t
*extents
)
2616 cairo_clip_t
*clip
= extents
->clip
;
2617 cairo_bool_t need_clip_mask
= ! _cairo_clip_is_region (clip
);
2618 cairo_status_t status
;
2620 /* If the boxes are not pixel-aligned, we will need to compute a real mask */
2621 if (! boxes
->is_pixel_aligned
)
2622 return CAIRO_INT_STATUS_UNSUPPORTED
;
2624 if (need_clip_mask
&&
2625 (! extents
->is_bounded
|| op
== CAIRO_OPERATOR_SOURCE
))
2627 return CAIRO_INT_STATUS_UNSUPPORTED
;
2630 status
= _cairo_xcb_connection_acquire (dst
->connection
);
2631 if (unlikely (status
))
2634 _cairo_xcb_surface_ensure_picture (dst
);
2635 if (dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
&& ! need_clip_mask
&&
2636 (op
== CAIRO_OPERATOR_CLEAR
|| src
->type
== CAIRO_PATTERN_TYPE_SOLID
))
2638 const cairo_color_t
*color
;
2640 if (op
== CAIRO_OPERATOR_CLEAR
)
2641 color
= CAIRO_COLOR_TRANSPARENT
;
2643 color
= &((cairo_solid_pattern_t
*) src
)->color
;
2645 status
= _render_fill_boxes (dst
, op
, color
, boxes
);
2649 cairo_surface_pattern_t mask
;
2651 if (need_clip_mask
) {
2652 cairo_xcb_surface_t
*clip_surface
;
2653 int clip_x
= 0, clip_y
= 0;
2655 clip_surface
= get_clip_surface (extents
->clip
, dst
,
2657 if (unlikely (clip_surface
->base
.status
))
2658 return clip_surface
->base
.status
;
2660 _cairo_pattern_init_for_surface (&mask
, &clip_surface
->base
);
2661 mask
.base
.filter
= CAIRO_FILTER_NEAREST
;
2662 cairo_matrix_init_translate (&mask
.base
.matrix
,
2665 cairo_surface_destroy (&clip_surface
->base
);
2667 if (op
== CAIRO_OPERATOR_CLEAR
) {
2669 op
= CAIRO_OPERATOR_DEST_OUT
;
2673 status
= _render_composite_boxes (dst
, op
, src
,
2674 need_clip_mask
? &mask
.base
: NULL
,
2675 &extents
->bounded
, boxes
);
2678 _cairo_pattern_fini (&mask
.base
);
2681 if (status
== CAIRO_STATUS_SUCCESS
&& ! extents
->is_bounded
) {
2683 _cairo_xcb_surface_fixup_unbounded_boxes (dst
, extents
,
2687 _cairo_xcb_connection_release (dst
->connection
);
2693 cairo_boxes_for_each_box (cairo_boxes_t
*boxes
,
2694 cairo_bool_t (*func
) (cairo_box_t
*box
,
2698 struct _cairo_boxes_chunk
*chunk
;
2701 for (chunk
= &boxes
->chunks
; chunk
!= NULL
; chunk
= chunk
->next
) {
2702 for (i
= 0; i
< chunk
->count
; i
++)
2703 if (! func (&chunk
->base
[i
], data
))
2710 struct _image_contains_box
{
2715 static cairo_bool_t
image_contains_box (cairo_box_t
*box
, void *closure
)
2717 struct _image_contains_box
*data
= closure
;
2719 /* The box is pixel-aligned so the truncation is safe. */
2721 _cairo_fixed_integer_part (box
->p1
.x
) + data
->tx
>= 0 &&
2722 _cairo_fixed_integer_part (box
->p1
.y
) + data
->ty
>= 0 &&
2723 _cairo_fixed_integer_part (box
->p2
.x
) + data
->tx
<= data
->width
&&
2724 _cairo_fixed_integer_part (box
->p2
.y
) + data
->ty
<= data
->height
;
2727 struct _image_upload_box
{
2728 cairo_xcb_surface_t
*surface
;
2729 cairo_image_surface_t
*image
;
2734 static cairo_bool_t
image_upload_box (cairo_box_t
*box
, void *closure
)
2736 const struct _image_upload_box
*iub
= closure
;
2737 /* The box is pixel-aligned so the truncation is safe. */
2738 int x
= _cairo_fixed_integer_part (box
->p1
.x
);
2739 int y
= _cairo_fixed_integer_part (box
->p1
.y
);
2740 int width
= _cairo_fixed_integer_part (box
->p2
.x
- box
->p1
.x
);
2741 int height
= _cairo_fixed_integer_part (box
->p2
.y
- box
->p1
.y
);
2742 int bpp
= PIXMAN_FORMAT_BPP (iub
->image
->pixman_format
);
2743 int len
= CAIRO_STRIDE_FOR_WIDTH_BPP (width
, bpp
);
2744 if (len
== iub
->image
->stride
) {
2745 _cairo_xcb_connection_put_image (iub
->surface
->connection
,
2746 iub
->surface
->drawable
,
2753 (y
+ iub
->ty
) * iub
->image
->stride
+
2754 (x
+ iub
->tx
) * bpp
/8);
2756 _cairo_xcb_connection_put_subimage (iub
->surface
->connection
,
2757 iub
->surface
->drawable
,
2772 static cairo_status_t
2773 _upload_image_inplace (cairo_xcb_surface_t
*surface
,
2774 const cairo_pattern_t
*source
,
2775 cairo_boxes_t
*boxes
)
2777 const cairo_surface_pattern_t
*pattern
;
2778 struct _image_contains_box icb
;
2779 struct _image_upload_box iub
;
2780 cairo_image_surface_t
*image
;
2781 cairo_status_t status
;
2784 if (! boxes
->is_pixel_aligned
)
2785 return CAIRO_INT_STATUS_UNSUPPORTED
;
2787 if (source
->type
!= CAIRO_PATTERN_TYPE_SURFACE
)
2788 return CAIRO_INT_STATUS_UNSUPPORTED
;
2790 pattern
= (const cairo_surface_pattern_t
*) source
;
2791 if (! _cairo_surface_is_image (pattern
->surface
))
2792 return CAIRO_INT_STATUS_UNSUPPORTED
;
2794 /* Have we already upload this image to a pixmap? */
2796 cairo_xcb_picture_t
*snapshot
;
2798 snapshot
= (cairo_xcb_picture_t
*)
2799 _cairo_surface_has_snapshot (pattern
->surface
, &_cairo_xcb_picture_backend
);
2800 if (snapshot
!= NULL
) {
2801 if (snapshot
->screen
== surface
->screen
)
2802 return CAIRO_INT_STATUS_UNSUPPORTED
;
2806 image
= (cairo_image_surface_t
*) pattern
->surface
;
2807 if (image
->format
== CAIRO_FORMAT_INVALID
)
2808 return CAIRO_INT_STATUS_UNSUPPORTED
;
2810 if (image
->depth
!= surface
->depth
)
2811 return CAIRO_INT_STATUS_UNSUPPORTED
;
2813 if (! _cairo_matrix_is_integer_translation (&source
->matrix
, &tx
, &ty
))
2814 return CAIRO_INT_STATUS_UNSUPPORTED
;
2816 /* Check that the data is entirely within the image */
2817 icb
.width
= image
->width
;
2818 icb
.height
= image
->height
;
2821 if (! cairo_boxes_for_each_box (boxes
, image_contains_box
, &icb
))
2822 return CAIRO_INT_STATUS_UNSUPPORTED
;
2824 if (surface
->deferred_clear
) {
2825 status
= _cairo_xcb_surface_clear (surface
);
2826 if (unlikely (status
))
2830 status
= _cairo_xcb_connection_acquire (surface
->connection
);
2831 if (unlikely (status
))
2834 iub
.surface
= surface
;
2836 iub
.gc
= _cairo_xcb_screen_get_gc (surface
->screen
,
2841 cairo_boxes_for_each_box (boxes
, image_upload_box
, &iub
);
2843 _cairo_xcb_screen_put_gc (surface
->screen
, image
->depth
, iub
.gc
);
2844 _cairo_xcb_connection_release (surface
->connection
);
2846 return CAIRO_STATUS_SUCCESS
;
2849 static cairo_int_status_t
2850 trim_extents_to_traps (cairo_composite_rectangles_t
*extents
,
2851 cairo_traps_t
*traps
)
2855 /* X trims the affected area to the extents of the trapezoids, so
2856 * we need to compensate when fixing up the unbounded area.
2858 _cairo_traps_extents (traps
, &box
);
2859 return _cairo_composite_rectangles_intersect_mask_extents (extents
, &box
);
2863 _mono_edge_is_vertical (const cairo_line_t
*line
)
2865 return _cairo_fixed_integer_round_down (line
->p1
.x
) == _cairo_fixed_integer_round_down (line
->p2
.x
);
2869 _traps_are_pixel_aligned (cairo_traps_t
*traps
,
2870 cairo_antialias_t antialias
)
2874 if (antialias
== CAIRO_ANTIALIAS_NONE
) {
2875 for (i
= 0; i
< traps
->num_traps
; i
++) {
2876 if (! _mono_edge_is_vertical (&traps
->traps
[i
].left
) ||
2877 ! _mono_edge_is_vertical (&traps
->traps
[i
].right
))
2879 traps
->maybe_region
= FALSE
;
2884 for (i
= 0; i
< traps
->num_traps
; i
++) {
2885 if (traps
->traps
[i
].left
.p1
.x
!= traps
->traps
[i
].left
.p2
.x
||
2886 traps
->traps
[i
].right
.p1
.x
!= traps
->traps
[i
].right
.p2
.x
||
2887 ! _cairo_fixed_is_integer (traps
->traps
[i
].top
) ||
2888 ! _cairo_fixed_is_integer (traps
->traps
[i
].bottom
) ||
2889 ! _cairo_fixed_is_integer (traps
->traps
[i
].left
.p1
.x
) ||
2890 ! _cairo_fixed_is_integer (traps
->traps
[i
].right
.p1
.x
))
2892 traps
->maybe_region
= FALSE
;
2902 _boxes_for_traps (cairo_boxes_t
*boxes
,
2903 cairo_traps_t
*traps
,
2904 cairo_antialias_t antialias
)
2908 _cairo_boxes_init (boxes
);
2910 boxes
->chunks
.base
= (cairo_box_t
*) traps
->traps
;
2911 boxes
->chunks
.size
= traps
->num_traps
;
2913 if (antialias
!= CAIRO_ANTIALIAS_NONE
) {
2914 for (i
= j
= 0; i
< traps
->num_traps
; i
++) {
2915 /* Note the traps and boxes alias so we need to take the local copies first. */
2916 cairo_fixed_t x1
= traps
->traps
[i
].left
.p1
.x
;
2917 cairo_fixed_t x2
= traps
->traps
[i
].right
.p1
.x
;
2918 cairo_fixed_t y1
= traps
->traps
[i
].top
;
2919 cairo_fixed_t y2
= traps
->traps
[i
].bottom
;
2921 if (x1
== x2
|| y1
== y2
)
2924 boxes
->chunks
.base
[j
].p1
.x
= x1
;
2925 boxes
->chunks
.base
[j
].p1
.y
= y1
;
2926 boxes
->chunks
.base
[j
].p2
.x
= x2
;
2927 boxes
->chunks
.base
[j
].p2
.y
= y2
;
2930 if (boxes
->is_pixel_aligned
) {
2931 boxes
->is_pixel_aligned
=
2932 _cairo_fixed_is_integer (x1
) && _cairo_fixed_is_integer (y1
) &&
2933 _cairo_fixed_is_integer (x2
) && _cairo_fixed_is_integer (y2
);
2937 boxes
->is_pixel_aligned
= TRUE
;
2939 for (i
= j
= 0; i
< traps
->num_traps
; i
++) {
2940 /* Note the traps and boxes alias so we need to take the local copies first. */
2941 cairo_fixed_t x1
= traps
->traps
[i
].left
.p1
.x
;
2942 cairo_fixed_t x2
= traps
->traps
[i
].right
.p1
.x
;
2943 cairo_fixed_t y1
= traps
->traps
[i
].top
;
2944 cairo_fixed_t y2
= traps
->traps
[i
].bottom
;
2946 /* round down here to match Pixman's behavior when using traps. */
2947 boxes
->chunks
.base
[j
].p1
.x
= _cairo_fixed_round_down (x1
);
2948 boxes
->chunks
.base
[j
].p1
.y
= _cairo_fixed_round_down (y1
);
2949 boxes
->chunks
.base
[j
].p2
.x
= _cairo_fixed_round_down (x2
);
2950 boxes
->chunks
.base
[j
].p2
.y
= _cairo_fixed_round_down (y2
);
2952 j
+= (boxes
->chunks
.base
[j
].p1
.x
!= boxes
->chunks
.base
[j
].p2
.x
&&
2953 boxes
->chunks
.base
[j
].p1
.y
!= boxes
->chunks
.base
[j
].p2
.y
);
2957 boxes
->num_boxes
= j
;
2958 boxes
->chunks
.count
= j
;
2961 static cairo_status_t
2962 _composite_polygon (cairo_xcb_surface_t
*dst
,
2963 cairo_operator_t op
,
2964 const cairo_pattern_t
*source
,
2965 cairo_polygon_t
*polygon
,
2966 cairo_antialias_t antialias
,
2967 cairo_fill_rule_t fill_rule
,
2968 cairo_composite_rectangles_t
*extents
)
2970 composite_traps_info_t traps
;
2971 cairo_bool_t clip_surface
= ! _cairo_clip_is_region (extents
->clip
);
2972 cairo_region_t
*clip_region
= _cairo_clip_get_region (extents
->clip
);
2973 cairo_status_t status
;
2975 if (polygon
->num_edges
== 0) {
2976 status
= CAIRO_STATUS_SUCCESS
;
2978 if (! extents
->is_bounded
) {
2979 if (cairo_region_contains_rectangle (clip_region
, &extents
->unbounded
) == CAIRO_REGION_OVERLAP_IN
)
2982 if (clip_surface
== FALSE
) {
2983 if (clip_region
!= NULL
) {
2984 status
= _cairo_xcb_surface_set_clip_region (dst
, clip_region
);
2985 if (unlikely (status
))
2989 status
= _cairo_xcb_surface_fixup_unbounded (dst
, extents
);
2991 if (clip_region
!= NULL
)
2992 _cairo_xcb_surface_clear_clip_region (dst
);
2994 status
= _cairo_xcb_surface_fixup_unbounded_with_mask (dst
,
3003 if (extents
->clip
->path
!= NULL
&& extents
->is_bounded
) {
3004 cairo_polygon_t clipper
;
3005 cairo_fill_rule_t clipper_fill_rule
;
3006 cairo_antialias_t clipper_antialias
;
3008 status
= _cairo_clip_get_polygon (extents
->clip
,
3011 &clipper_antialias
);
3012 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3013 if (clipper_antialias
== antialias
) {
3014 status
= _cairo_polygon_intersect (polygon
, fill_rule
,
3015 &clipper
, clipper_fill_rule
);
3016 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3017 cairo_clip_t
* clip
= _cairo_clip_copy_region (extents
->clip
);
3018 _cairo_clip_destroy (extents
->clip
);
3019 extents
->clip
= clip
;
3021 fill_rule
= CAIRO_FILL_RULE_WINDING
;
3023 _cairo_polygon_fini (&clipper
);
3028 _cairo_traps_init (&traps
.traps
);
3030 status
= _cairo_bentley_ottmann_tessellate_polygon (&traps
.traps
, polygon
, fill_rule
);
3031 if (unlikely (status
))
3034 if (traps
.traps
.has_intersections
) {
3035 if (traps
.traps
.is_rectangular
)
3036 status
= _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps
.traps
, CAIRO_FILL_RULE_WINDING
);
3037 else if (traps
.traps
.is_rectilinear
)
3038 status
= _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps
.traps
, CAIRO_FILL_RULE_WINDING
);
3040 status
= _cairo_bentley_ottmann_tessellate_traps (&traps
.traps
, CAIRO_FILL_RULE_WINDING
);
3041 if (unlikely (status
))
3045 /* Use a fast path if the trapezoids consist of a simple region,
3046 * but we can only do this if we do not have a clip surface, or can
3047 * substitute the mask with the clip.
3049 if (traps
.traps
.maybe_region
&&
3050 _traps_are_pixel_aligned (&traps
.traps
, antialias
) &&
3052 (extents
->is_bounded
&& op
!= CAIRO_OPERATOR_SOURCE
)))
3054 cairo_boxes_t boxes
;
3056 _boxes_for_traps (&boxes
, &traps
.traps
, antialias
);
3057 status
= _clip_and_composite_boxes (dst
, op
, source
, &boxes
, extents
);
3061 /* Otherwise render the trapezoids to a mask and composite in the usual
3064 traps
.antialias
= antialias
;
3065 status
= trim_extents_to_traps (extents
, &traps
.traps
);
3066 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3067 unsigned int flags
= 0;
3069 /* For unbounded operations, the X11 server will estimate the
3070 * affected rectangle and apply the operation to that. However,
3071 * there are cases where this is an overestimate (e.g. the
3072 * clip-fill-{eo,nz}-unbounded test).
3074 * The clip will trim that overestimate to our expectations.
3076 if (! extents
->is_bounded
)
3077 flags
|= FORCE_CLIP_REGION
;
3079 status
= _clip_and_composite (dst
, op
, source
, _composite_traps
,
3080 NULL
, &traps
, extents
,
3081 need_unbounded_clip (extents
) | flags
);
3086 _cairo_traps_fini (&traps
.traps
);
3091 static cairo_status_t
3092 _clip_and_composite_boxes (cairo_xcb_surface_t
*dst
,
3093 cairo_operator_t op
,
3094 const cairo_pattern_t
*src
,
3095 cairo_boxes_t
*boxes
,
3096 cairo_composite_rectangles_t
*extents
)
3098 composite_traps_info_t info
;
3099 cairo_int_status_t status
;
3101 if (boxes
->num_boxes
== 0 && extents
->is_bounded
)
3102 return CAIRO_STATUS_SUCCESS
;
3104 if (boxes
->is_pixel_aligned
&& _cairo_clip_is_region (extents
->clip
) &&
3105 (op
== CAIRO_OPERATOR_SOURCE
||
3106 (dst
->base
.is_clear
&& (op
== CAIRO_OPERATOR_OVER
|| op
== CAIRO_OPERATOR_ADD
))))
3108 if (boxes
->num_boxes
== 1 &&
3109 extents
->bounded
.width
== dst
->width
&&
3110 extents
->bounded
.height
== dst
->height
)
3112 op
= CAIRO_OPERATOR_SOURCE
;
3113 dst
->deferred_clear
= FALSE
;
3116 status
= _upload_image_inplace (dst
, src
, boxes
);
3117 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
3121 /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
3122 if (dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
&&
3123 extents
->clip
->path
!= NULL
&& extents
->is_bounded
) {
3124 cairo_polygon_t polygon
;
3125 cairo_fill_rule_t fill_rule
;
3126 cairo_antialias_t antialias
;
3129 clip
= _cairo_clip_copy (extents
->clip
);
3130 clip
= _cairo_clip_intersect_boxes (clip
, boxes
);
3131 if (_cairo_clip_is_all_clipped (clip
))
3132 return CAIRO_INT_STATUS_NOTHING_TO_DO
;
3134 status
= _cairo_clip_get_polygon (clip
, &polygon
,
3135 &fill_rule
, &antialias
);
3136 _cairo_clip_path_destroy (clip
->path
);
3138 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
)) {
3139 cairo_clip_t
*saved_clip
= extents
->clip
;
3140 extents
->clip
= clip
;
3141 status
= _composite_polygon (dst
, op
, src
,
3146 if (extents
->clip
!= clip
)
3148 extents
->clip
= saved_clip
;
3149 _cairo_polygon_fini (&polygon
);
3152 _cairo_clip_destroy (clip
);
3154 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
3158 if (dst
->deferred_clear
) {
3159 status
= _cairo_xcb_surface_clear (dst
);
3160 if (unlikely (status
))
3164 if (boxes
->is_pixel_aligned
&&
3165 _cairo_clip_is_region (extents
->clip
) &&
3166 op
== CAIRO_OPERATOR_SOURCE
) {
3167 status
= _upload_image_inplace (dst
, src
, boxes
);
3168 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
3172 if ((dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE
) == 0)
3173 return _core_boxes (dst
, op
, src
, boxes
, extents
);
3175 /* Use a fast path if the boxes are pixel aligned */
3176 status
= _composite_boxes (dst
, op
, src
, boxes
, extents
);
3177 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
3180 if ((dst
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
) == 0)
3181 return CAIRO_INT_STATUS_UNSUPPORTED
;
3183 /* Otherwise render via a mask and composite in the usual fashion. */
3184 status
= _cairo_traps_init_boxes (&info
.traps
, boxes
);
3185 if (unlikely (status
))
3188 info
.antialias
= CAIRO_ANTIALIAS_DEFAULT
;
3189 status
= trim_extents_to_traps (extents
, &info
.traps
);
3190 if (status
== CAIRO_INT_STATUS_SUCCESS
) {
3191 status
= _clip_and_composite (dst
, op
, src
,
3192 _composite_traps
, NULL
, &info
,
3193 extents
, need_unbounded_clip (extents
));
3196 _cairo_traps_fini (&info
.traps
);
3200 static cairo_int_status_t
3201 _composite_mask (void *closure
,
3202 cairo_xcb_surface_t
*dst
,
3203 cairo_operator_t op
,
3204 const cairo_pattern_t
*src_pattern
,
3207 const cairo_rectangle_int_t
*extents
,
3210 const cairo_pattern_t
*mask_pattern
= closure
;
3211 cairo_xcb_picture_t
*src
, *mask
= NULL
;
3212 cairo_status_t status
;
3214 if (dst
->base
.is_clear
) {
3215 if (op
== CAIRO_OPERATOR_OVER
|| op
== CAIRO_OPERATOR_ADD
)
3216 op
= CAIRO_OPERATOR_SOURCE
;
3219 if (op
== CAIRO_OPERATOR_SOURCE
&& clip
== NULL
)
3220 dst
->deferred_clear
= FALSE
;
3222 if (dst
->deferred_clear
) {
3223 status
= _cairo_xcb_surface_clear (dst
);
3224 if (unlikely (status
))
3228 if (src_pattern
!= NULL
) {
3229 src
= _cairo_xcb_picture_for_pattern (dst
, src_pattern
, extents
);
3230 if (unlikely (src
->base
.status
))
3231 return src
->base
.status
;
3233 mask
= _cairo_xcb_picture_for_pattern (dst
, mask_pattern
, extents
);
3234 if (unlikely (mask
->base
.status
)) {
3235 cairo_surface_destroy (&src
->base
);
3236 return mask
->base
.status
;
3239 _cairo_xcb_connection_render_composite (dst
->connection
,
3240 _render_operator (op
),
3244 extents
->x
+ src
->x
, extents
->y
+ src
->y
,
3245 extents
->x
+ mask
->x
, extents
->y
+ mask
->y
,
3246 extents
->x
- dst_x
, extents
->y
- dst_y
,
3247 extents
->width
, extents
->height
);
3248 cairo_surface_destroy (&mask
->base
);
3249 cairo_surface_destroy (&src
->base
);
3251 src
= _cairo_xcb_picture_for_pattern (dst
, mask_pattern
, extents
);
3252 if (unlikely (src
->base
.status
))
3253 return src
->base
.status
;
3255 _cairo_xcb_connection_render_composite (dst
->connection
,
3256 _render_operator (op
),
3260 extents
->x
+ src
->x
, extents
->y
+ src
->y
,
3262 extents
->x
- dst_x
, extents
->y
- dst_y
,
3263 extents
->width
, extents
->height
);
3264 cairo_surface_destroy (&src
->base
);
3267 return CAIRO_STATUS_SUCCESS
;
3270 struct composite_box_info
{
3271 cairo_xcb_surface_t
*dst
;
3272 cairo_xcb_picture_t
*src
;
3276 static void composite_box(void *closure
,
3277 int16_t x
, int16_t y
,
3278 int16_t w
, int16_t h
,
3281 struct composite_box_info
*info
= closure
;
3283 if (coverage
< 0xff00) {
3284 cairo_xcb_picture_t
*mask
;
3285 cairo_color_t color
;
3287 color
.red_short
= color
.green_short
= color
.blue_short
= 0;
3288 color
.alpha_short
= coverage
;
3290 mask
= _solid_picture (info
->dst
, &color
);
3291 if (likely (mask
->base
.status
== CAIRO_STATUS_SUCCESS
)) {
3292 _cairo_xcb_connection_render_composite (info
->dst
->connection
,
3297 x
+ info
->src
->x
, y
+ info
->src
->y
,
3302 cairo_surface_destroy (&mask
->base
);
3304 _cairo_xcb_connection_render_composite (info
->dst
->connection
,
3309 x
+ info
->src
->x
, y
+ info
->src
->y
,
3316 static cairo_int_status_t
3317 _composite_mask_clip_boxes (void *closure
,
3318 cairo_xcb_surface_t
*dst
,
3319 cairo_operator_t op
,
3320 const cairo_pattern_t
*src_pattern
,
3323 const cairo_rectangle_int_t
*extents
,
3326 struct composite_box_info info
;
3327 cairo_status_t status
;
3330 assert (src_pattern
== NULL
);
3331 assert (op
== CAIRO_OPERATOR_ADD
);
3332 assert (dst
->base
.is_clear
);
3334 if (clip
->num_boxes
> 1) {
3335 status
= _cairo_xcb_surface_clear (dst
);
3336 if (unlikely (status
))
3340 info
.op
= XCB_RENDER_PICT_OP_SRC
;
3342 info
.src
= _cairo_xcb_picture_for_pattern (dst
, closure
, extents
);
3343 if (unlikely (info
.src
->base
.status
))
3344 return info
.src
->base
.status
;
3346 info
.src
->x
+= dst_x
;
3347 info
.src
->y
+= dst_y
;
3349 for (i
= 0; i
< clip
->num_boxes
; i
++)
3350 do_unaligned_box(composite_box
, &info
, &clip
->boxes
[i
], dst_x
, dst_y
);
3351 cairo_surface_destroy (&info
.src
->base
);
3353 return CAIRO_STATUS_SUCCESS
;
3356 static cairo_int_status_t
3357 _composite_mask_clip (void *closure
,
3358 cairo_xcb_surface_t
*dst
,
3359 cairo_operator_t op
,
3360 const cairo_pattern_t
*src_pattern
,
3363 const cairo_rectangle_int_t
*extents
,
3366 const cairo_pattern_t
*mask_pattern
= closure
;
3367 cairo_polygon_t polygon
;
3368 cairo_fill_rule_t fill_rule
;
3369 composite_traps_info_t info
;
3370 cairo_status_t status
;
3372 assert (src_pattern
== NULL
);
3373 assert (op
== CAIRO_OPERATOR_ADD
);
3374 assert (dst
->base
.is_clear
);
3376 status
= _cairo_clip_get_polygon (clip
, &polygon
,
3377 &fill_rule
, &info
.antialias
);
3378 if (unlikely (status
))
3381 _cairo_traps_init (&info
.traps
);
3382 status
= _cairo_bentley_ottmann_tessellate_polygon (&info
.traps
,
3385 _cairo_polygon_fini (&polygon
);
3386 if (unlikely (status
))
3389 if (info
.traps
.has_intersections
) {
3390 if (info
.traps
.is_rectangular
)
3391 status
= _cairo_bentley_ottmann_tessellate_rectangular_traps (&info
.traps
, CAIRO_FILL_RULE_WINDING
);
3392 else if (info
.traps
.is_rectilinear
)
3393 status
= _cairo_bentley_ottmann_tessellate_rectilinear_traps (&info
.traps
, CAIRO_FILL_RULE_WINDING
);
3395 status
= _cairo_bentley_ottmann_tessellate_traps (&info
.traps
, CAIRO_FILL_RULE_WINDING
);
3396 if (unlikely (status
)) {
3397 _cairo_traps_fini (&info
.traps
);
3402 dst
->deferred_clear
= FALSE
; /* assert(trap extents == extents); */
3404 status
= _composite_traps (&info
,
3405 dst
, CAIRO_OPERATOR_SOURCE
, mask_pattern
,
3408 _cairo_traps_fini (&info
.traps
);
3413 struct composite_opacity_info
{
3415 cairo_xcb_surface_t
*dst
;
3416 cairo_xcb_picture_t
*src
;
3420 static void composite_opacity(void *closure
,
3421 int16_t x
, int16_t y
,
3422 int16_t w
, int16_t h
,
3425 struct composite_opacity_info
*info
= closure
;
3426 cairo_xcb_picture_t
*mask
;
3427 cairo_color_t color
;
3429 color
.red_short
= color
.green_short
= color
.blue_short
= 0;
3430 color
.alpha_short
= info
->opacity
* coverage
;
3432 mask
= _solid_picture (info
->dst
, &color
);
3433 if (likely (mask
->base
.status
== CAIRO_STATUS_SUCCESS
)) {
3435 _cairo_xcb_connection_render_composite (info
->dst
->connection
,
3440 x
+ info
->src
->x
, y
+ info
->src
->y
,
3445 _cairo_xcb_connection_render_composite (info
->dst
->connection
,
3457 cairo_surface_destroy (&mask
->base
);
3460 static cairo_int_status_t
3461 _composite_opacity_boxes (void *closure
,
3462 cairo_xcb_surface_t
*dst
,
3463 cairo_operator_t op
,
3464 const cairo_pattern_t
*src_pattern
,
3467 const cairo_rectangle_int_t
*extents
,
3470 const cairo_solid_pattern_t
*mask_pattern
= closure
;
3471 struct composite_opacity_info info
;
3472 cairo_status_t status
;
3475 if (dst
->base
.is_clear
) {
3476 if (op
== CAIRO_OPERATOR_OVER
|| op
== CAIRO_OPERATOR_ADD
)
3477 op
= CAIRO_OPERATOR_SOURCE
;
3480 if (op
== CAIRO_OPERATOR_SOURCE
&&
3482 (clip
->extents
.width
>= extents
->width
&&
3483 clip
->extents
.height
>= extents
->height
)))
3484 dst
->deferred_clear
= FALSE
;
3486 if (dst
->deferred_clear
) {
3487 status
= _cairo_xcb_surface_clear (dst
);
3488 if (unlikely (status
))
3492 info
.op
= _render_operator (op
);
3495 if (src_pattern
!= NULL
) {
3496 info
.src
= _cairo_xcb_picture_for_pattern (dst
, src_pattern
, extents
);
3497 if (unlikely (info
.src
->base
.status
))
3498 return info
.src
->base
.status
;
3502 info
.opacity
= mask_pattern
->color
.alpha
;
3504 /* XXX for lots of boxes create a clip region for the fully opaque areas */
3506 for (i
= 0; i
< clip
->num_boxes
; i
++)
3507 do_unaligned_box(composite_opacity
, &info
,
3508 &clip
->boxes
[i
], dst_x
, dst_y
);
3510 composite_opacity(&info
,
3517 cairo_surface_destroy (&info
.src
->base
);
3519 return CAIRO_STATUS_SUCCESS
;
3522 /* high level rasteriser -> compositor */
3525 _cairo_xcb_render_compositor_paint (const cairo_compositor_t
*compositor
,
3526 cairo_composite_rectangles_t
*composite
)
3528 cairo_xcb_surface_t
*surface
= (cairo_xcb_surface_t
*) composite
->surface
;
3529 cairo_operator_t op
= composite
->op
;
3530 cairo_pattern_t
*source
= &composite
->source_pattern
.base
;
3531 cairo_boxes_t boxes
;
3532 cairo_status_t status
;
3534 if (unlikely (! _operator_is_supported (surface
->connection
->flags
, op
)))
3535 return CAIRO_INT_STATUS_UNSUPPORTED
;
3537 if ((surface
->connection
->flags
& (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
|
3538 CAIRO_XCB_RENDER_HAS_COMPOSITE
)) == 0)
3540 return CAIRO_INT_STATUS_UNSUPPORTED
;
3543 if (composite
->clip
== NULL
&&
3544 source
->type
== CAIRO_PATTERN_TYPE_SOLID
&&
3545 (op
== CAIRO_OPERATOR_SOURCE
||
3546 op
== CAIRO_OPERATOR_CLEAR
||
3547 (surface
->base
.is_clear
&&
3548 (op
== CAIRO_OPERATOR_ADD
|| op
== CAIRO_OPERATOR_OVER
))))
3550 surface
->deferred_clear
= TRUE
;
3551 surface
->deferred_clear_color
= composite
->source_pattern
.solid
.color
;
3552 return CAIRO_STATUS_SUCCESS
;
3555 _cairo_clip_steal_boxes(composite
->clip
, &boxes
);
3556 status
= _clip_and_composite_boxes (surface
, op
, source
, &boxes
, composite
);
3557 _cairo_clip_unsteal_boxes (composite
->clip
, &boxes
);
3563 _cairo_xcb_render_compositor_mask (const cairo_compositor_t
*compositor
,
3564 cairo_composite_rectangles_t
*composite
)
3566 cairo_xcb_surface_t
*surface
= (cairo_xcb_surface_t
*) composite
->surface
;
3567 cairo_operator_t op
= composite
->op
;
3568 cairo_pattern_t
*source
= &composite
->source_pattern
.base
;
3569 cairo_pattern_t
*mask
= &composite
->mask_pattern
.base
;
3570 cairo_status_t status
;
3572 if (unlikely (! _operator_is_supported (surface
->connection
->flags
, op
)))
3573 return CAIRO_INT_STATUS_UNSUPPORTED
;
3575 if ((surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE
) == 0)
3576 return CAIRO_INT_STATUS_UNSUPPORTED
;
3578 if (mask
->type
== CAIRO_PATTERN_TYPE_SOLID
&&
3579 composite
->clip
->path
== NULL
&&
3580 ! _cairo_clip_is_region (composite
->clip
)) {
3581 status
= _clip_and_composite (surface
, op
, source
,
3582 _composite_opacity_boxes
,
3583 _composite_opacity_boxes
,
3585 composite
, need_unbounded_clip (composite
));
3587 xcb_draw_func_t mask_func
= NULL
;
3588 if (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
)
3589 mask_func
= composite
->clip
->path
? _composite_mask_clip
: _composite_mask_clip_boxes
;
3590 status
= _clip_and_composite (surface
, op
, source
,
3591 _composite_mask
, mask_func
,
3593 composite
, need_bounded_clip (composite
));
3599 static cairo_int_status_t
3600 _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t
*dst
,
3601 cairo_operator_t op
,
3602 const cairo_pattern_t
*source
,
3603 const cairo_path_fixed_t
*path
,
3604 const cairo_stroke_style_t
*stroke_style
,
3605 const cairo_matrix_t
*ctm
,
3606 const cairo_matrix_t
*ctm_inverse
,
3608 cairo_antialias_t antialias
,
3609 cairo_composite_rectangles_t
*extents
)
3611 cairo_polygon_t polygon
;
3612 cairo_status_t status
;
3614 _cairo_polygon_init_with_clip (&polygon
, extents
->clip
);
3615 status
= _cairo_path_fixed_stroke_to_polygon (path
,
3620 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3621 status
= _composite_polygon (dst
, op
, source
,
3622 &polygon
, antialias
,
3623 CAIRO_FILL_RULE_WINDING
,
3626 _cairo_polygon_fini (&polygon
);
3631 static cairo_status_t
3632 _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t
*dst
,
3633 cairo_operator_t op
,
3634 const cairo_pattern_t
*source
,
3635 const cairo_path_fixed_t
*path
,
3636 const cairo_stroke_style_t
*stroke_style
,
3637 const cairo_matrix_t
*ctm
,
3638 const cairo_matrix_t
*ctm_inverse
,
3640 cairo_antialias_t antialias
,
3641 cairo_composite_rectangles_t
*extents
)
3643 cairo_surface_t
*image
;
3644 cairo_status_t status
;
3648 x
= extents
->bounded
.x
;
3649 y
= extents
->bounded
.y
;
3650 image
= _cairo_xcb_surface_create_similar_image (dst
, CAIRO_FORMAT_A8
,
3651 extents
->bounded
.width
,
3652 extents
->bounded
.height
);
3653 if (unlikely (image
->status
))
3654 return image
->status
;
3656 clip
= _cairo_clip_copy_region (extents
->clip
);
3657 status
= _cairo_surface_offset_stroke (image
, x
, y
,
3659 &_cairo_pattern_white
.base
,
3662 tolerance
, antialias
,
3664 _cairo_clip_destroy (clip
);
3665 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3666 cairo_surface_pattern_t mask
;
3668 _cairo_pattern_init_for_surface (&mask
, image
);
3669 mask
.base
.filter
= CAIRO_FILTER_NEAREST
;
3671 cairo_matrix_init_translate (&mask
.base
.matrix
, -x
, -y
);
3672 status
= _clip_and_composite (dst
, op
, source
,
3673 _composite_mask
, NULL
, &mask
.base
,
3674 extents
, need_bounded_clip (extents
));
3675 _cairo_pattern_fini (&mask
.base
);
3678 cairo_surface_finish (image
);
3679 cairo_surface_destroy (image
);
3685 _cairo_xcb_render_compositor_stroke (const cairo_compositor_t
*compositor
,
3686 cairo_composite_rectangles_t
*composite
,
3687 const cairo_path_fixed_t
*path
,
3688 const cairo_stroke_style_t
*style
,
3689 const cairo_matrix_t
*ctm
,
3690 const cairo_matrix_t
*ctm_inverse
,
3692 cairo_antialias_t antialias
)
3694 cairo_xcb_surface_t
*surface
= (cairo_xcb_surface_t
*) composite
->surface
;
3695 cairo_operator_t op
= composite
->op
;
3696 cairo_pattern_t
*source
= &composite
->source_pattern
.base
;
3697 cairo_int_status_t status
;
3699 if (unlikely (! _operator_is_supported (surface
->connection
->flags
, op
)))
3700 return CAIRO_INT_STATUS_UNSUPPORTED
;
3702 if ((surface
->connection
->flags
& (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
|
3703 CAIRO_XCB_RENDER_HAS_COMPOSITE
)) == 0)
3705 return CAIRO_INT_STATUS_UNSUPPORTED
;
3708 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
3709 if (_cairo_path_fixed_stroke_is_rectilinear (path
)) {
3710 cairo_boxes_t boxes
;
3712 _cairo_boxes_init_with_clip (&boxes
, composite
->clip
);
3713 status
= _cairo_path_fixed_stroke_rectilinear_to_boxes (path
,
3718 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
)) {
3719 status
= _clip_and_composite_boxes (surface
, op
, source
,
3722 _cairo_boxes_fini (&boxes
);
3725 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
3726 if (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
) {
3727 status
= _cairo_xcb_surface_render_stroke_as_polygon (surface
, op
, source
,
3730 tolerance
, antialias
,
3732 } else if (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE
) {
3733 status
= _cairo_xcb_surface_render_stroke_via_mask (surface
, op
, source
,
3736 tolerance
, antialias
,
3746 static cairo_status_t
3747 _cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t
*dst
,
3748 cairo_operator_t op
,
3749 const cairo_pattern_t
*source
,
3750 const cairo_path_fixed_t
*path
,
3751 cairo_fill_rule_t fill_rule
,
3753 cairo_antialias_t antialias
,
3754 cairo_composite_rectangles_t
*extents
)
3756 cairo_polygon_t polygon
;
3757 cairo_status_t status
;
3759 _cairo_polygon_init_with_clip (&polygon
, extents
->clip
);
3760 status
= _cairo_path_fixed_fill_to_polygon (path
, tolerance
, &polygon
);
3761 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3762 status
= _composite_polygon (dst
, op
, source
,
3768 _cairo_polygon_fini (&polygon
);
3773 static cairo_status_t
3774 _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t
*dst
,
3775 cairo_operator_t op
,
3776 const cairo_pattern_t
*source
,
3777 const cairo_path_fixed_t
*path
,
3778 cairo_fill_rule_t fill_rule
,
3780 cairo_antialias_t antialias
,
3781 cairo_composite_rectangles_t
*extents
)
3783 cairo_surface_t
*image
;
3784 cairo_status_t status
;
3788 x
= extents
->bounded
.x
;
3789 y
= extents
->bounded
.y
;
3790 image
= _cairo_xcb_surface_create_similar_image (dst
, CAIRO_FORMAT_A8
,
3791 extents
->bounded
.width
,
3792 extents
->bounded
.height
);
3793 if (unlikely (image
->status
))
3794 return image
->status
;
3796 clip
= _cairo_clip_copy_region (extents
->clip
);
3797 status
= _cairo_surface_offset_fill (image
, x
, y
,
3799 &_cairo_pattern_white
.base
,
3800 path
, fill_rule
, tolerance
, antialias
,
3802 _cairo_clip_destroy (clip
);
3803 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3804 cairo_surface_pattern_t mask
;
3806 _cairo_pattern_init_for_surface (&mask
, image
);
3807 mask
.base
.filter
= CAIRO_FILTER_NEAREST
;
3809 cairo_matrix_init_translate (&mask
.base
.matrix
, -x
, -y
);
3810 status
= _clip_and_composite (dst
, op
, source
,
3811 _composite_mask
, NULL
, &mask
.base
,
3812 extents
, need_bounded_clip (extents
));
3814 _cairo_pattern_fini (&mask
.base
);
3817 cairo_surface_finish (image
);
3818 cairo_surface_destroy (image
);
3824 _cairo_xcb_render_compositor_fill (const cairo_compositor_t
*compositor
,
3825 cairo_composite_rectangles_t
*composite
,
3826 const cairo_path_fixed_t
*path
,
3827 cairo_fill_rule_t fill_rule
,
3829 cairo_antialias_t antialias
)
3831 cairo_xcb_surface_t
*surface
= (cairo_xcb_surface_t
*) composite
->surface
;
3832 cairo_operator_t op
= composite
->op
;
3833 cairo_pattern_t
*source
= &composite
->source_pattern
.base
;
3834 cairo_int_status_t status
;
3836 if (unlikely (! _operator_is_supported (surface
->connection
->flags
, op
)))
3837 return CAIRO_INT_STATUS_UNSUPPORTED
;
3839 if ((surface
->connection
->flags
& (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
|
3840 CAIRO_XCB_RENDER_HAS_COMPOSITE
)) == 0)
3842 return CAIRO_INT_STATUS_UNSUPPORTED
;
3845 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
3846 if (_cairo_path_fixed_fill_is_rectilinear (path
)) {
3847 cairo_boxes_t boxes
;
3849 _cairo_boxes_init_with_clip (&boxes
, composite
->clip
);
3850 status
= _cairo_path_fixed_fill_rectilinear_to_boxes (path
,
3854 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
)) {
3855 status
= _clip_and_composite_boxes (surface
, op
, source
,
3858 _cairo_boxes_fini (&boxes
);
3861 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
3862 if (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
) {
3863 status
= _cairo_xcb_surface_render_fill_as_polygon (surface
, op
, source
, path
,
3864 fill_rule
, tolerance
, antialias
,
3866 } else if (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE
) {
3867 status
= _cairo_xcb_surface_render_fill_via_mask (surface
, op
, source
, path
,
3868 fill_rule
, tolerance
, antialias
,
3878 static cairo_status_t
3879 _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t
*dst
,
3880 cairo_operator_t op
,
3881 const cairo_pattern_t
*source
,
3882 cairo_scaled_font_t
*scaled_font
,
3883 cairo_glyph_t
*glyphs
,
3885 cairo_composite_rectangles_t
*extents
)
3887 cairo_surface_t
*image
;
3888 cairo_content_t content
;
3889 cairo_status_t status
;
3893 content
= CAIRO_CONTENT_ALPHA
;
3894 if (scaled_font
->options
.antialias
== CAIRO_ANTIALIAS_SUBPIXEL
)
3895 content
= CAIRO_CONTENT_COLOR_ALPHA
;
3897 x
= extents
->bounded
.x
;
3898 y
= extents
->bounded
.y
;
3899 image
= _cairo_xcb_surface_create_similar_image (dst
,
3900 _cairo_format_from_content (content
),
3901 extents
->bounded
.width
,
3902 extents
->bounded
.height
);
3903 if (unlikely (image
->status
))
3904 return image
->status
;
3906 clip
= _cairo_clip_copy_region (extents
->clip
);
3907 status
= _cairo_surface_offset_glyphs (image
, x
, y
,
3909 &_cairo_pattern_white
.base
,
3910 scaled_font
, glyphs
, num_glyphs
,
3912 _cairo_clip_destroy (clip
);
3913 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
3914 cairo_surface_pattern_t mask
;
3916 _cairo_pattern_init_for_surface (&mask
, image
);
3917 mask
.base
.filter
= CAIRO_FILTER_NEAREST
;
3918 if (content
& CAIRO_CONTENT_COLOR
)
3919 mask
.base
.has_component_alpha
= TRUE
;
3921 cairo_matrix_init_translate (&mask
.base
.matrix
, -x
, -y
);
3922 status
= _clip_and_composite (dst
, op
, source
,
3923 _composite_mask
, NULL
, &mask
.base
,
3924 extents
, need_bounded_clip (extents
));
3926 _cairo_pattern_fini (&mask
.base
);
3929 cairo_surface_finish (image
);
3930 cairo_surface_destroy (image
);
3935 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
3936 * an input glyph with double coordinates, and as "working" glyph with
3937 * integer from-current-point offsets. */
3940 unsigned long index
;
3942 unsigned long index
;
3946 } cairo_xcb_glyph_t
;
3948 /* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */
3949 COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t
) == sizeof (cairo_glyph_t
));
3952 cairo_scaled_font_t
*font
;
3953 cairo_xcb_glyph_t
*glyphs
;
3955 cairo_bool_t use_mask
;
3956 } composite_glyphs_info_t
;
3958 static cairo_status_t
3959 _can_composite_glyphs (cairo_xcb_surface_t
*dst
,
3960 cairo_rectangle_int_t
*extents
,
3961 cairo_scaled_font_t
*scaled_font
,
3962 cairo_glyph_t
*glyphs
,
3965 #define GLYPH_CACHE_SIZE 64
3966 cairo_box_t bbox_cache
[GLYPH_CACHE_SIZE
];
3967 unsigned long glyph_cache
[GLYPH_CACHE_SIZE
];
3968 #undef GLYPH_CACHE_SIZE
3969 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
3970 cairo_glyph_t
*glyphs_end
, *valid_glyphs
;
3971 const int max_glyph_size
= dst
->connection
->maximum_request_length
- 64;
3973 /* We must initialize the cache with values that cannot match the
3974 * "hash" to guarantee that when compared for the first time they
3975 * will result in a mismatch. The hash function is simply modulus,
3976 * so we cannot use 0 in glyph_cache[0], but we can use it in all
3977 * other array cells.
3979 memset (glyph_cache
, 0, sizeof (glyph_cache
));
3982 /* Scan for oversized glyphs or glyphs outside the representable
3983 * range and fallback in that case, discard glyphs outside of the
3986 valid_glyphs
= glyphs
;
3987 for (glyphs_end
= glyphs
+ *num_glyphs
; glyphs
!= glyphs_end
; glyphs
++) {
3988 double x1
, y1
, x2
, y2
;
3989 cairo_scaled_glyph_t
*glyph
;
3991 int width
, height
, len
;
3994 g
= glyphs
->index
% ARRAY_LENGTH (glyph_cache
);
3995 if (glyph_cache
[g
] != glyphs
->index
) {
3996 status
= _cairo_scaled_glyph_lookup (scaled_font
,
3998 CAIRO_SCALED_GLYPH_INFO_METRICS
,
4000 if (unlikely (status
))
4003 glyph_cache
[g
] = glyphs
->index
;
4004 bbox_cache
[g
] = glyph
->bbox
;
4006 bbox
= &bbox_cache
[g
];
4008 /* Drop glyphs outside the clipping */
4009 x1
= _cairo_fixed_to_double (bbox
->p1
.x
);
4010 y1
= _cairo_fixed_to_double (bbox
->p1
.y
);
4011 y2
= _cairo_fixed_to_double (bbox
->p2
.y
);
4012 x2
= _cairo_fixed_to_double (bbox
->p2
.x
);
4013 if (unlikely (glyphs
->x
+ x2
<= extents
->x
||
4014 glyphs
->y
+ y2
<= extents
->y
||
4015 glyphs
->x
+ x1
>= extents
->x
+ extents
->width
||
4016 glyphs
->y
+ y1
>= extents
->y
+ extents
->height
))
4022 /* XRenderAddGlyph does not handle a glyph surface larger than
4023 * the extended maximum XRequest size.
4025 width
= _cairo_fixed_integer_ceil (bbox
->p2
.x
- bbox
->p1
.x
);
4026 height
= _cairo_fixed_integer_ceil (bbox
->p2
.y
- bbox
->p1
.y
);
4027 len
= CAIRO_STRIDE_FOR_WIDTH_BPP (width
, 32) * height
;
4028 if (unlikely (len
>= max_glyph_size
)) {
4029 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
4033 /* The glyph coordinates must be representable in an int16_t.
4034 * When possible, they will be expressed as an offset from the
4035 * previous glyph, otherwise they will be an offset from the
4036 * operation extents or from the surface origin. If the last
4037 * two options are not valid, fallback.
4039 if (unlikely (glyphs
->x
> INT16_MAX
||
4040 glyphs
->y
> INT16_MAX
||
4041 glyphs
->x
- extents
->x
< INT16_MIN
||
4042 glyphs
->y
- extents
->y
< INT16_MIN
))
4044 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
4049 if (unlikely (valid_glyphs
!= glyphs
))
4050 *valid_glyphs
= *glyphs
;
4054 if (unlikely (valid_glyphs
!= glyphs
)) {
4055 for (; glyphs
!= glyphs_end
; glyphs
++) {
4056 *valid_glyphs
= *glyphs
;
4064 /* Start a new element for the first glyph,
4065 * or for any glyph that has unexpected position,
4066 * or if current element has too many glyphs
4067 * (Xrender limits each element to 252 glyphs, we limit them to 128)
4069 * These same conditions need to be mirrored between
4070 * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks
4072 #define _start_new_glyph_elt(count, glyph) \
4073 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
4075 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
4076 * enough room for padding */
4084 #define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
4087 _cairo_xcb_font_destroy (cairo_xcb_font_t
*font
)
4091 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
4092 cairo_xcb_font_glyphset_info_t
*info
;
4094 info
= &font
->glyphset_info
[i
];
4095 free (info
->pending_free_glyphs
);
4098 cairo_list_del (&font
->base
.link
);
4099 cairo_list_del (&font
->link
);
4101 _cairo_xcb_connection_destroy (font
->connection
);
4107 _cairo_xcb_font_fini (cairo_scaled_font_private_t
*abstract_private
,
4108 cairo_scaled_font_t
*scaled_font
)
4110 cairo_xcb_font_t
*font_private
= (cairo_xcb_font_t
*)abstract_private
;
4111 cairo_xcb_connection_t
*connection
;
4112 cairo_bool_t have_connection
;
4113 cairo_status_t status
;
4116 connection
= font_private
->connection
;
4118 status
= _cairo_xcb_connection_acquire (connection
);
4119 have_connection
= status
== CAIRO_STATUS_SUCCESS
;
4121 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
4122 cairo_xcb_font_glyphset_info_t
*info
;
4124 info
= &font_private
->glyphset_info
[i
];
4125 if (info
->glyphset
&& status
== CAIRO_STATUS_SUCCESS
) {
4126 _cairo_xcb_connection_render_free_glyph_set (connection
,
4131 if (have_connection
)
4132 _cairo_xcb_connection_release (connection
);
4134 _cairo_xcb_font_destroy (font_private
);
4138 static cairo_xcb_font_t
*
4139 _cairo_xcb_font_create (cairo_xcb_connection_t
*connection
,
4140 cairo_scaled_font_t
*font
)
4142 cairo_xcb_font_t
*priv
;
4145 priv
= malloc (sizeof (cairo_xcb_font_t
));
4146 if (unlikely (priv
== NULL
))
4149 _cairo_scaled_font_attach_private (font
, &priv
->base
, connection
,
4150 _cairo_xcb_font_fini
);
4152 priv
->scaled_font
= font
;
4153 priv
->connection
= _cairo_xcb_connection_reference (connection
);
4154 cairo_list_add (&priv
->link
, &connection
->fonts
);
4156 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
4157 cairo_xcb_font_glyphset_info_t
*info
= &priv
->glyphset_info
[i
];
4159 case GLYPHSET_INDEX_ARGB32
: info
->format
= CAIRO_FORMAT_ARGB32
; break;
4160 case GLYPHSET_INDEX_A8
: info
->format
= CAIRO_FORMAT_A8
; break;
4161 case GLYPHSET_INDEX_A1
: info
->format
= CAIRO_FORMAT_A1
; break;
4162 default: ASSERT_NOT_REACHED
; break;
4164 info
->xrender_format
= 0;
4165 info
->glyphset
= XCB_NONE
;
4166 info
->pending_free_glyphs
= NULL
;
4173 _cairo_xcb_font_close (cairo_xcb_font_t
*font
)
4175 cairo_scaled_font_t
*scaled_font
;
4177 scaled_font
= font
->scaled_font
;
4179 //scaled_font->surface_private = NULL;
4180 _cairo_scaled_font_reset_cache (scaled_font
);
4182 _cairo_xcb_font_destroy (font
);
4186 _cairo_xcb_render_free_glyphs (cairo_xcb_connection_t
*connection
,
4187 cairo_xcb_font_glyphset_free_glyphs_t
*to_free
)
4189 _cairo_xcb_connection_render_free_glyphs (connection
,
4191 to_free
->glyph_count
,
4192 to_free
->glyph_indices
);
4196 _cairo_xcb_get_glyphset_index_for_format (cairo_format_t format
)
4198 if (format
== CAIRO_FORMAT_A8
)
4199 return GLYPHSET_INDEX_A8
;
4200 if (format
== CAIRO_FORMAT_A1
)
4201 return GLYPHSET_INDEX_A1
;
4203 assert (format
== CAIRO_FORMAT_ARGB32
);
4204 return GLYPHSET_INDEX_ARGB32
;
4209 static inline cairo_xcb_font_t
*
4210 _cairo_xcb_font_get (const cairo_xcb_connection_t
*c
,
4211 cairo_scaled_font_t
*font
)
4213 return (cairo_xcb_font_t
*)_cairo_scaled_font_find_private (font
, c
);
4217 static cairo_xcb_font_glyphset_info_t
*
4218 _cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_xcb_connection_t
*c
,
4219 cairo_scaled_font_t
*font
,
4220 cairo_format_t format
)
4222 cairo_xcb_font_t
*priv
;
4223 cairo_xcb_font_glyphset_info_t
*info
;
4226 glyphset_index
= _cairo_xcb_get_glyphset_index_for_format (format
);
4228 priv
= _cairo_xcb_font_get (c
, font
);
4230 priv
= _cairo_xcb_font_create (c
, font
);
4235 info
= &priv
->glyphset_info
[glyphset_index
];
4236 if (info
->glyphset
== XCB_NONE
) {
4237 info
->glyphset
= _cairo_xcb_connection_get_xid (c
);
4238 info
->xrender_format
= c
->standard_formats
[info
->format
];
4240 _cairo_xcb_connection_render_create_glyph_set (c
,
4242 info
->xrender_format
);
4249 _cairo_xcb_glyphset_info_has_pending_free_glyph (
4250 cairo_xcb_font_glyphset_info_t
*info
,
4251 unsigned long glyph_index
)
4253 if (info
->pending_free_glyphs
!= NULL
) {
4254 cairo_xcb_font_glyphset_free_glyphs_t
*to_free
;
4257 to_free
= info
->pending_free_glyphs
;
4258 for (i
= 0; i
< to_free
->glyph_count
; i
++) {
4259 if (to_free
->glyph_indices
[i
] == glyph_index
) {
4260 to_free
->glyph_count
--;
4261 memmove (&to_free
->glyph_indices
[i
],
4262 &to_free
->glyph_indices
[i
+1],
4263 (to_free
->glyph_count
- i
) * sizeof (to_free
->glyph_indices
[0]));
4273 cairo_scaled_glyph_private_t base
;
4275 cairo_xcb_font_glyphset_info_t
*glyphset
;
4276 } cairo_xcb_glyph_private_t
;
4278 static cairo_xcb_font_glyphset_info_t
*
4279 _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (cairo_xcb_connection_t
*c
,
4280 cairo_scaled_font_t
*font
,
4281 unsigned long glyph_index
,
4282 cairo_image_surface_t
*surface
)
4284 cairo_xcb_font_t
*priv
;
4287 priv
= _cairo_xcb_font_get (c
, font
);
4291 if (surface
!= NULL
) {
4292 i
= _cairo_xcb_get_glyphset_index_for_format (surface
->format
);
4294 if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
4295 &priv
->glyphset_info
[i
],
4298 return &priv
->glyphset_info
[i
];
4301 for (i
= 0; i
< NUM_GLYPHSETS
; i
++) {
4302 if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
4303 &priv
->glyphset_info
[i
],
4306 return &priv
->glyphset_info
[i
];
4315 _cairo_xcb_glyph_fini (cairo_scaled_glyph_private_t
*glyph_private
,
4316 cairo_scaled_glyph_t
*glyph
,
4317 cairo_scaled_font_t
*font
)
4319 cairo_xcb_glyph_private_t
*priv
= (cairo_xcb_glyph_private_t
*)glyph_private
;
4321 if (! font
->finished
) {
4322 cairo_xcb_font_glyphset_info_t
*info
= priv
->glyphset
;
4323 cairo_xcb_font_glyphset_free_glyphs_t
*to_free
;
4324 cairo_xcb_font_t
*font_private
;
4326 font_private
= _cairo_xcb_font_get (glyph_private
->key
, font
);
4327 assert (font_private
);
4329 to_free
= info
->pending_free_glyphs
;
4330 if (to_free
!= NULL
&&
4331 to_free
->glyph_count
== ARRAY_LENGTH (to_free
->glyph_indices
))
4333 _cairo_xcb_render_free_glyphs (font_private
->connection
, to_free
);
4334 to_free
= info
->pending_free_glyphs
= NULL
;
4337 if (to_free
== NULL
) {
4338 to_free
= malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t
));
4339 if (unlikely (to_free
== NULL
)) {
4340 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
4341 return; /* XXX cannot propagate failure */
4344 to_free
->glyphset
= info
->glyphset
;
4345 to_free
->glyph_count
= 0;
4346 info
->pending_free_glyphs
= to_free
;
4349 to_free
->glyph_indices
[to_free
->glyph_count
++] =
4350 _cairo_scaled_glyph_index (glyph
);
4353 cairo_list_del (&glyph_private
->link
);
4354 free (glyph_private
);
4358 static cairo_status_t
4359 _cairo_xcb_glyph_attach (cairo_xcb_connection_t
*c
,
4360 cairo_scaled_glyph_t
*glyph
,
4361 cairo_xcb_font_glyphset_info_t
*info
)
4363 cairo_xcb_glyph_private_t
*priv
;
4365 priv
= malloc (sizeof (*priv
));
4366 if (unlikely (priv
== NULL
))
4367 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
4369 _cairo_scaled_glyph_attach_private (glyph
, &priv
->base
, c
,
4370 _cairo_xcb_glyph_fini
);
4371 priv
->glyphset
= info
;
4373 glyph
->dev_private
= info
;
4374 glyph
->dev_private_key
= c
;
4375 return CAIRO_STATUS_SUCCESS
;
4378 static cairo_status_t
4379 _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t
*connection
,
4380 cairo_scaled_font_t
*font
,
4381 cairo_scaled_glyph_t
**scaled_glyph_out
)
4383 xcb_render_glyphinfo_t glyph_info
;
4384 uint32_t glyph_index
;
4386 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
4387 cairo_scaled_glyph_t
*scaled_glyph
= *scaled_glyph_out
;
4388 cairo_image_surface_t
*glyph_surface
= scaled_glyph
->surface
;
4389 cairo_bool_t already_had_glyph_surface
;
4390 cairo_xcb_font_glyphset_info_t
*info
;
4392 glyph_index
= _cairo_scaled_glyph_index (scaled_glyph
);
4394 /* check to see if we have a pending XRenderFreeGlyph for this glyph */
4395 info
= _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (connection
, font
, glyph_index
, glyph_surface
);
4397 return _cairo_xcb_glyph_attach (connection
, scaled_glyph
, info
);
4399 if (glyph_surface
== NULL
) {
4400 status
= _cairo_scaled_glyph_lookup (font
,
4402 CAIRO_SCALED_GLYPH_INFO_METRICS
|
4403 CAIRO_SCALED_GLYPH_INFO_SURFACE
,
4405 if (unlikely (status
))
4408 scaled_glyph
= *scaled_glyph_out
;
4409 glyph_surface
= scaled_glyph
->surface
;
4410 already_had_glyph_surface
= FALSE
;
4412 already_had_glyph_surface
= TRUE
;
4415 info
= _cairo_xcb_scaled_font_get_glyphset_info_for_format (connection
,
4417 glyph_surface
->format
);
4418 if (unlikely (info
== NULL
)) {
4419 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
4424 /* If the glyph surface has zero height or width, we create
4425 * a clear 1x1 surface, to avoid various X server bugs.
4427 if (glyph_surface
->width
== 0 || glyph_surface
->height
== 0) {
4428 cairo_surface_t
*tmp_surface
;
4430 tmp_surface
= cairo_image_surface_create (info
->format
, 1, 1);
4431 status
= tmp_surface
->status
;
4432 if (unlikely (status
))
4435 tmp_surface
->device_transform
= glyph_surface
->base
.device_transform
;
4436 tmp_surface
->device_transform_inverse
= glyph_surface
->base
.device_transform_inverse
;
4438 glyph_surface
= (cairo_image_surface_t
*) tmp_surface
;
4442 /* If the glyph format does not match the font format, then we
4443 * create a temporary surface for the glyph image with the font's
4446 if (glyph_surface
->format
!= info
->format
) {
4447 glyph_surface
= _cairo_image_surface_coerce_to_format (glyph_surface
,
4449 status
= glyph_surface
->base
.status
;
4450 if (unlikely (status
))
4454 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
4455 glyph_info
.x
= _cairo_lround (glyph_surface
->base
.device_transform
.x0
);
4456 glyph_info
.y
= _cairo_lround (glyph_surface
->base
.device_transform
.y0
);
4457 glyph_info
.width
= glyph_surface
->width
;
4458 glyph_info
.height
= glyph_surface
->height
;
4459 glyph_info
.x_off
= scaled_glyph
->x_advance
;
4460 glyph_info
.y_off
= scaled_glyph
->y_advance
;
4462 data
= glyph_surface
->data
;
4464 /* flip formats around */
4465 switch (_cairo_xcb_get_glyphset_index_for_format (scaled_glyph
->surface
->format
)) {
4466 case GLYPHSET_INDEX_A1
:
4467 /* local bitmaps are always stored with bit == byte */
4468 if (_cairo_is_little_endian() != (connection
->root
->bitmap_format_bit_order
== XCB_IMAGE_ORDER_LSB_FIRST
)) {
4469 int c
= glyph_surface
->stride
* glyph_surface
->height
;
4477 if (unlikely (new == NULL
)) {
4478 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
4486 b
= ((b
<< 1) & 0xaa) | ((b
>> 1) & 0x55);
4487 b
= ((b
<< 2) & 0xcc) | ((b
>> 2) & 0x33);
4488 b
= ((b
<< 4) & 0xf0) | ((b
>> 4) & 0x0f);
4495 case GLYPHSET_INDEX_A8
:
4498 case GLYPHSET_INDEX_ARGB32
:
4499 if (_cairo_is_little_endian() != (connection
->root
->image_byte_order
== XCB_IMAGE_ORDER_LSB_FIRST
)) {
4500 unsigned int c
= glyph_surface
->stride
* glyph_surface
->height
/ 4;
4507 new = malloc (4 * c
);
4508 if (unlikely (new == NULL
)) {
4509 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
4514 d
= (uint32_t *) data
;
4516 *n
++ = bswap_32 (*d
);
4519 data
= (uint8_t *) new;
4527 /* XXX assume X server wants pixman padding. Xft assumes this as well */
4529 _cairo_xcb_connection_render_add_glyphs (connection
,
4531 1, &glyph_index
, &glyph_info
,
4532 glyph_surface
->stride
* glyph_surface
->height
,
4535 if (data
!= glyph_surface
->data
)
4538 status
= _cairo_xcb_glyph_attach (connection
, scaled_glyph
, info
);
4541 if (glyph_surface
!= scaled_glyph
->surface
)
4542 cairo_surface_destroy (&glyph_surface
->base
);
4544 /* If the scaled glyph didn't already have a surface attached
4545 * to it, release the created surface now that we have it
4546 * uploaded to the X server. If the surface has already been
4547 * there (e.g. because image backend requested it), leave it in
4550 if (! already_had_glyph_surface
)
4551 _cairo_scaled_glyph_set_surface (scaled_glyph
, font
, NULL
);
4556 typedef void (*cairo_xcb_render_composite_text_func_t
)
4557 (cairo_xcb_connection_t
*connection
,
4559 xcb_render_picture_t src
,
4560 xcb_render_picture_t dst
,
4561 xcb_render_pictformat_t mask_format
,
4562 xcb_render_glyphset_t glyphset
,
4569 static cairo_status_t
4570 _emit_glyphs_chunk (cairo_xcb_surface_t
*dst
,
4571 cairo_operator_t op
,
4572 cairo_xcb_picture_t
*src
,
4573 /* info for this chunk */
4574 cairo_xcb_glyph_t
*glyphs
,
4577 int estimated_req_size
,
4578 cairo_xcb_font_glyphset_info_t
*info
,
4579 xcb_render_pictformat_t mask_format
)
4581 cairo_xcb_render_composite_text_func_t composite_text_func
;
4582 uint8_t stack_buf
[CAIRO_STACK_BUFFER_SIZE
];
4583 uint8_t *buf
= stack_buf
;
4584 x_glyph_elt_t
*elt
= NULL
; /* silence compiler */
4588 if (estimated_req_size
> ARRAY_LENGTH (stack_buf
)) {
4589 buf
= malloc (estimated_req_size
);
4590 if (unlikely (buf
== NULL
))
4591 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
4595 for (i
= 0; i
< num_glyphs
; i
++) {
4596 if (_start_new_glyph_elt (i
, &glyphs
[i
])) {
4598 len
+= 4 - (len
& 3);
4600 elt
= (x_glyph_elt_t
*) (buf
+ len
);
4602 elt
->deltax
= glyphs
[i
].i
.x
;
4603 elt
->deltay
= glyphs
[i
].i
.y
;
4604 len
+= sizeof (x_glyph_elt_t
);
4608 case 1: *(uint8_t *) (buf
+ len
) = glyphs
[i
].index
; break;
4609 case 2: *(uint16_t *) (buf
+ len
) = glyphs
[i
].index
; break;
4611 case 4: *(uint32_t *) (buf
+ len
) = glyphs
[i
].index
; break;
4617 len
+= 4 - (len
& 3);
4621 composite_text_func
= _cairo_xcb_connection_render_composite_glyphs_8
;
4624 composite_text_func
= _cairo_xcb_connection_render_composite_glyphs_16
;
4628 composite_text_func
= _cairo_xcb_connection_render_composite_glyphs_32
;
4631 composite_text_func (dst
->connection
,
4632 _render_operator (op
),
4637 src
->x
+ glyphs
[0].i
.x
,
4638 src
->y
+ glyphs
[0].i
.y
,
4641 if (buf
!= stack_buf
)
4644 return CAIRO_STATUS_SUCCESS
;
4647 static cairo_int_status_t
4648 _composite_glyphs (void *closure
,
4649 cairo_xcb_surface_t
*dst
,
4650 cairo_operator_t op
,
4651 const cairo_pattern_t
*pattern
,
4654 const cairo_rectangle_int_t
*extents
,
4657 composite_glyphs_info_t
*info
= closure
;
4658 cairo_scaled_glyph_t
*glyph_cache
[64];
4659 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
4660 cairo_fixed_t x
= 0, y
= 0;
4661 cairo_xcb_font_glyphset_info_t
*glyphset_info
= NULL
, *this_glyphset_info
;
4662 const unsigned int max_request_size
= dst
->connection
->maximum_request_length
- 64;
4663 cairo_xcb_picture_t
*src
;
4665 unsigned long max_index
= 0;
4668 unsigned int request_size
= 0;
4671 if (dst
->deferred_clear
) {
4672 status
= _cairo_xcb_surface_clear (dst
);
4673 if (unlikely (status
))
4677 src
= _cairo_xcb_picture_for_pattern (dst
, pattern
, extents
);
4678 if (unlikely (src
->base
.status
))
4679 return src
->base
.status
;
4681 memset (glyph_cache
, 0, sizeof (glyph_cache
));
4683 for (i
= 0; i
< info
->num_glyphs
; i
++) {
4684 cairo_scaled_glyph_t
*glyph
;
4685 unsigned long glyph_index
= info
->glyphs
[i
].index
;
4686 int cache_index
= glyph_index
% ARRAY_LENGTH (glyph_cache
);
4687 int old_width
= width
;
4690 glyph
= glyph_cache
[cache_index
];
4691 if (glyph
== NULL
||
4692 _cairo_scaled_glyph_index (glyph
) != glyph_index
)
4694 status
= _cairo_scaled_glyph_lookup (info
->font
,
4696 CAIRO_SCALED_GLYPH_INFO_METRICS
,
4698 if (unlikely (status
)) {
4699 cairo_surface_destroy (&src
->base
);
4703 /* Send unseen glyphs to the server */
4704 if (glyph
->dev_private_key
!= dst
->connection
) {
4705 status
= _cairo_xcb_surface_add_glyph (dst
->connection
,
4708 if (unlikely (status
)) {
4709 cairo_surface_destroy (&src
->base
);
4714 glyph_cache
[cache_index
] = glyph
;
4717 this_x
= _cairo_lround (info
->glyphs
[i
].d
.x
) - dst_x
;
4718 this_y
= _cairo_lround (info
->glyphs
[i
].d
.y
) - dst_y
;
4720 this_glyphset_info
= glyph
->dev_private
;
4721 if (glyphset_info
== NULL
)
4722 glyphset_info
= this_glyphset_info
;
4724 /* Update max glyph index */
4725 if (glyph_index
> max_index
) {
4726 max_index
= glyph_index
;
4727 if (max_index
>= 65536)
4729 else if (max_index
>= 256)
4731 if (width
!= old_width
)
4732 request_size
+= (width
- old_width
) * i
;
4735 /* If we will pass the max request size by adding this glyph,
4736 * flush current glyphs. Note that we account for a
4737 * possible element being added below.
4739 * Also flush if changing glyphsets, as Xrender limits one mask
4740 * format per request, so we can either break up, or use a
4741 * wide-enough mask format. We do the former. One reason to
4742 * prefer the latter is the fact that Xserver ADDs all glyphs
4743 * to the mask first, and then composes that to final surface,
4744 * though it's not a big deal.
4746 * If the glyph has a coordinate which cannot be represented
4747 * as a 16-bit offset from the previous glyph, flush the
4748 * current chunk. The current glyph will be the first one in
4749 * the next chunk, thus its coordinates will be an offset from
4750 * the destination origin. This offset is guaranteed to be
4751 * representable as 16-bit offset in _can_composite_glyphs().
4753 if (request_size
+ width
> max_request_size
- _cairo_sz_x_glyph_elt_t
||
4754 this_x
- x
> INT16_MAX
|| this_x
- x
< INT16_MIN
||
4755 this_y
- y
> INT16_MAX
|| this_y
- y
< INT16_MIN
||
4756 this_glyphset_info
!= glyphset_info
)
4758 status
= _emit_glyphs_chunk (dst
, op
, src
,
4760 old_width
, request_size
,
4762 info
->use_mask
? glyphset_info
->xrender_format
: 0);
4763 if (unlikely (status
)) {
4764 cairo_surface_destroy (&src
->base
);
4769 info
->num_glyphs
-= i
;
4772 max_index
= info
->glyphs
[0].index
;
4773 width
= max_index
< 256 ? 1 : max_index
< 65536 ? 2 : 4;
4778 glyphset_info
= this_glyphset_info
;
4781 /* Convert absolute glyph position to relative-to-current-point
4783 info
->glyphs
[i
].i
.x
= this_x
- x
;
4784 info
->glyphs
[i
].i
.y
= this_y
- y
;
4786 /* Start a new element for the first glyph,
4787 * or for any glyph that has unexpected position,
4788 * or if current element has too many glyphs.
4790 * These same conditions are mirrored in _emit_glyphs_chunk().
4792 if (_start_new_glyph_elt (i
, &info
->glyphs
[i
]))
4793 request_size
+= _cairo_sz_x_glyph_elt_t
;
4795 /* adjust current-position */
4796 x
= this_x
+ glyph
->x_advance
;
4797 y
= this_y
+ glyph
->y_advance
;
4799 request_size
+= width
;
4803 status
= _emit_glyphs_chunk (dst
, op
, src
,
4805 width
, request_size
,
4807 info
->use_mask
? glyphset_info
->xrender_format
: 0);
4810 cairo_surface_destroy (&src
->base
);
4816 _cairo_xcb_render_compositor_glyphs (const cairo_compositor_t
*compositor
,
4817 cairo_composite_rectangles_t
*composite
,
4818 cairo_scaled_font_t
*scaled_font
,
4819 cairo_glyph_t
*glyphs
,
4821 cairo_bool_t overlap
)
4823 cairo_xcb_surface_t
*surface
= (cairo_xcb_surface_t
*) composite
->surface
;
4824 cairo_operator_t op
= composite
->op
;
4825 cairo_pattern_t
*source
= &composite
->source_pattern
.base
;
4826 cairo_int_status_t status
;
4828 if (unlikely (! _operator_is_supported (surface
->connection
->flags
, op
)))
4829 return CAIRO_INT_STATUS_UNSUPPORTED
;
4831 if ((surface
->connection
->flags
& (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS
| CAIRO_XCB_RENDER_HAS_COMPOSITE
)) == 0)
4832 return CAIRO_INT_STATUS_UNSUPPORTED
;
4834 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
4835 if (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS
) {
4836 _cairo_scaled_font_freeze_cache (scaled_font
);
4838 status
= _can_composite_glyphs (surface
, &composite
->bounded
,
4839 scaled_font
, glyphs
, &num_glyphs
);
4840 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
)) {
4841 composite_glyphs_info_t info
;
4844 info
.font
= scaled_font
;
4845 info
.glyphs
= (cairo_xcb_glyph_t
*) glyphs
;
4846 info
.num_glyphs
= num_glyphs
;
4849 ! composite
->is_bounded
||
4850 ! _cairo_clip_is_region(composite
->clip
);
4852 if (composite
->mask
.width
> composite
->unbounded
.width
||
4853 composite
->mask
.height
> composite
->unbounded
.height
)
4855 /* Glyphs are tricky since we do not directly control the
4856 * geometry and their inked extents depend on the
4857 * individual glyph-surface size. We must set a clip region
4858 * so that the X server can trim the glyphs appropriately.
4860 flags
|= FORCE_CLIP_REGION
;
4862 status
= _clip_and_composite (surface
, op
, source
,
4863 _composite_glyphs
, NULL
,
4865 need_bounded_clip (composite
) |
4869 _cairo_scaled_font_thaw_cache (scaled_font
);
4872 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
4873 assert (surface
->connection
->flags
& CAIRO_XCB_RENDER_HAS_COMPOSITE
);
4875 _cairo_xcb_surface_render_glyphs_via_mask (surface
, op
, source
,
4876 scaled_font
, glyphs
, num_glyphs
,