1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
37 * Carl D. Worth <cworth@cworth.org>
38 * Behdad Esfahbod <behdad@behdad.org>
39 * Chris Wilson <chris@chris-wilson.co.uk>
40 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
45 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
47 #include "cairo-xlib-private.h"
49 #include "cairo-compositor-private.h"
50 #include "cairo-image-surface-private.h"
51 #include "cairo-list-inline.h"
52 #include "cairo-pattern-private.h"
53 #include "cairo-traps-private.h"
54 #include "cairo-tristrip-private.h"
56 static cairo_int_status_t
57 acquire (void *abstract_dst)
59 cairo_xlib_surface_t *dst = abstract_dst;
60 cairo_int_status_t status;
62 status = _cairo_xlib_display_acquire (dst->base.device, &dst->display);
63 if (unlikely (status))
66 dst->dpy = dst->display->display;
67 return CAIRO_STATUS_SUCCESS;
70 static cairo_int_status_t
71 release (void *abstract_dst)
73 cairo_xlib_surface_t *dst = abstract_dst;
75 cairo_device_release (&dst->display->base);
78 return CAIRO_STATUS_SUCCESS;
81 static cairo_int_status_t
82 set_clip_region (void *_surface,
83 cairo_region_t *region)
85 cairo_xlib_surface_t *surface = _surface;
87 _cairo_xlib_surface_ensure_picture (surface);
90 XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
91 XRectangle *rects = stack_rects;
94 n_rects = cairo_region_num_rectangles (region);
95 if (n_rects > ARRAY_LENGTH (stack_rects)) {
96 rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
97 if (unlikely (rects == NULL))
98 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
100 for (i = 0; i < n_rects; i++) {
101 cairo_rectangle_int_t rect;
103 cairo_region_get_rectangle (region, i, &rect);
107 rects[i].width = rect.width;
108 rects[i].height = rect.height;
110 XRenderSetPictureClipRectangles (surface->dpy,
114 if (rects != stack_rects)
117 XRenderPictureAttributes pa;
119 XRenderChangePicture (surface->dpy,
124 return CAIRO_STATUS_SUCCESS;
127 static cairo_int_status_t
128 draw_image_boxes (void *_dst,
129 cairo_image_surface_t *image,
130 cairo_boxes_t *boxes,
133 struct _cairo_boxes_chunk *chunk;
136 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
137 for (i = 0; i < chunk->count; i++) {
138 cairo_box_t *b = &chunk->base[i];
139 int x1 = _cairo_fixed_integer_part (b->p1.x);
140 int y1 = _cairo_fixed_integer_part (b->p1.y);
141 int x2 = _cairo_fixed_integer_part (b->p2.x);
142 int y2 = _cairo_fixed_integer_part (b->p2.y);
143 if ( _cairo_xlib_surface_draw_image (_dst, image,
147 return CAIRO_INT_STATUS_UNSUPPORTED;
151 return CAIRO_STATUS_SUCCESS;
154 static cairo_int_status_t
155 copy_boxes (void *_dst,
156 cairo_surface_t *_src,
157 cairo_boxes_t *boxes,
158 const cairo_rectangle_int_t *extents,
161 cairo_xlib_surface_t *dst = _dst;
162 cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)_src;
163 struct _cairo_boxes_chunk *chunk;
164 cairo_int_status_t status;
168 if (! _cairo_xlib_surface_same_screen (dst, src))
169 return CAIRO_INT_STATUS_UNSUPPORTED;
171 if (dst->depth != src->depth)
172 return CAIRO_INT_STATUS_UNSUPPORTED;
174 status = acquire (dst);
175 if (unlikely (status))
178 status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
179 if (unlikely (status)) {
184 if (! src->owns_pixmap) {
187 gcv.subwindow_mode = IncludeInferiors;
188 XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
191 if (boxes->num_boxes == 1) {
192 int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
193 int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
194 int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
195 int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
197 XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
202 /* We can only have a single control for subwindow_mode on the
203 * GC. If we have a Window destination, we need to set ClipByChildren,
204 * but if we have a Window source, we need IncludeInferiors. If we have
205 * both a Window destination and source, we must fallback. There is
206 * no convenient way to detect if a drawable is a Pixmap or Window,
207 * therefore we can only rely on those surfaces that we created
208 * ourselves to be Pixmaps, and treat everything else as a potential
211 if (src == dst || (!src->owns_pixmap && !dst->owns_pixmap)) {
212 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
213 for (i = 0; i < chunk->count; i++) {
214 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
215 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
216 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
217 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
218 XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
225 XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
226 XRectangle *rects = stack_rects;
228 if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
229 rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
230 if (unlikely (rects == NULL))
231 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
235 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
236 for (i = 0; i < chunk->count; i++) {
237 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
238 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
239 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
240 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
244 rects[j].width = x2 - x1;
245 rects[j].height = y2 - y1;
249 assert (j == boxes->num_boxes);
251 XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
253 XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
254 extents->x + dx, extents->y + dy,
255 extents->width, extents->height,
256 extents->x, extents->y);
258 XSetClipMask (dst->dpy, gc, None);
260 if (rects != stack_rects)
265 if (! src->owns_pixmap) {
268 gcv.subwindow_mode = ClipByChildren;
269 XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
272 _cairo_xlib_surface_put_gc (dst->display, dst, gc);
274 return CAIRO_STATUS_SUCCESS;
278 _render_operator (cairo_operator_t op)
281 case CAIRO_OPERATOR_CLEAR:
284 case CAIRO_OPERATOR_SOURCE:
286 case CAIRO_OPERATOR_OVER:
288 case CAIRO_OPERATOR_IN:
290 case CAIRO_OPERATOR_OUT:
292 case CAIRO_OPERATOR_ATOP:
295 case CAIRO_OPERATOR_DEST:
297 case CAIRO_OPERATOR_DEST_OVER:
298 return PictOpOverReverse;
299 case CAIRO_OPERATOR_DEST_IN:
300 return PictOpInReverse;
301 case CAIRO_OPERATOR_DEST_OUT:
302 return PictOpOutReverse;
303 case CAIRO_OPERATOR_DEST_ATOP:
304 return PictOpAtopReverse;
306 case CAIRO_OPERATOR_XOR:
308 case CAIRO_OPERATOR_ADD:
310 case CAIRO_OPERATOR_SATURATE:
311 return PictOpSaturate;
313 case CAIRO_OPERATOR_MULTIPLY:
314 return PictOpMultiply;
315 case CAIRO_OPERATOR_SCREEN:
317 case CAIRO_OPERATOR_OVERLAY:
318 return PictOpOverlay;
319 case CAIRO_OPERATOR_DARKEN:
321 case CAIRO_OPERATOR_LIGHTEN:
322 return PictOpLighten;
323 case CAIRO_OPERATOR_COLOR_DODGE:
324 return PictOpColorDodge;
325 case CAIRO_OPERATOR_COLOR_BURN:
326 return PictOpColorBurn;
327 case CAIRO_OPERATOR_HARD_LIGHT:
328 return PictOpHardLight;
329 case CAIRO_OPERATOR_SOFT_LIGHT:
330 return PictOpSoftLight;
331 case CAIRO_OPERATOR_DIFFERENCE:
332 return PictOpDifference;
333 case CAIRO_OPERATOR_EXCLUSION:
334 return PictOpExclusion;
335 case CAIRO_OPERATOR_HSL_HUE:
337 case CAIRO_OPERATOR_HSL_SATURATION:
338 return PictOpHSLSaturation;
339 case CAIRO_OPERATOR_HSL_COLOR:
340 return PictOpHSLColor;
341 case CAIRO_OPERATOR_HSL_LUMINOSITY:
342 return PictOpHSLLuminosity;
351 fill_reduces_to_source (cairo_operator_t op,
352 const cairo_color_t *color,
353 cairo_xlib_surface_t *dst)
355 if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color)) {
356 if (op == CAIRO_OPERATOR_OVER)
358 if (op == CAIRO_OPERATOR_ADD)
359 return (dst->base.content & CAIRO_CONTENT_COLOR) == 0;
365 static cairo_int_status_t
366 fill_rectangles (void *abstract_surface,
368 const cairo_color_t *color,
369 cairo_rectangle_int_t *rects,
372 cairo_xlib_surface_t *dst = abstract_surface;
373 XRenderColor render_color;
376 //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
378 render_color.red = color->red_short;
379 render_color.green = color->green_short;
380 render_color.blue = color->blue_short;
381 render_color.alpha = color->alpha_short;
383 if (fill_reduces_to_source (op, color, dst))
384 op = CAIRO_OPERATOR_SOURCE;
386 _cairo_xlib_surface_ensure_picture (dst);
387 if (num_rects == 1) {
388 /* Take advantage of the protocol compaction that libXrender performs
389 * to amalgamate sequences of XRenderFillRectangle().
391 XRenderFillRectangle (dst->dpy,
392 _render_operator (op),
396 rects->width, rects->height);
398 XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
399 XRectangle *xrects = stack_xrects;
401 if (num_rects > ARRAY_LENGTH (stack_xrects)) {
402 xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
403 if (unlikely (xrects == NULL))
404 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
407 for (i = 0; i < num_rects; i++) {
408 xrects[i].x = rects[i].x;
409 xrects[i].y = rects[i].y;
410 xrects[i].width = rects[i].width;
411 xrects[i].height = rects[i].height;
414 XRenderFillRectangles (dst->dpy,
415 _render_operator (op),
417 &render_color, xrects, num_rects);
419 if (xrects != stack_xrects)
423 return CAIRO_STATUS_SUCCESS;
426 static cairo_int_status_t
427 fill_boxes (void *abstract_surface,
429 const cairo_color_t *color,
430 cairo_boxes_t *boxes)
432 cairo_xlib_surface_t *dst = abstract_surface;
433 XRenderColor render_color;
435 render_color.red = color->red_short;
436 render_color.green = color->green_short;
437 render_color.blue = color->blue_short;
438 render_color.alpha = color->alpha_short;
440 if (fill_reduces_to_source (op, color, dst))
441 op = CAIRO_OPERATOR_SOURCE;
443 _cairo_xlib_surface_ensure_picture (dst);
444 if (boxes->num_boxes == 1) {
445 int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
446 int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
447 int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
448 int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
450 /* Take advantage of the protocol compaction that libXrender performs
451 * to amalgamate sequences of XRenderFillRectangle().
453 XRenderFillRectangle (dst->dpy,
454 _render_operator (op),
460 XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
461 XRectangle *xrects = stack_xrects;
462 struct _cairo_boxes_chunk *chunk;
465 if (boxes->num_boxes > ARRAY_LENGTH (stack_xrects)) {
466 xrects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
467 if (unlikely (xrects == NULL))
468 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
472 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
473 for (i = 0; i < chunk->count; i++) {
474 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
475 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
476 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
477 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
481 xrects[j].width = x2 - x1;
482 xrects[j].height = y2 - y1;
487 XRenderFillRectangles (dst->dpy,
488 _render_operator (op),
490 &render_color, xrects, j);
492 if (xrects != stack_xrects)
496 return CAIRO_STATUS_SUCCESS;
501 operation = _categorize_composite_operation (dst, op, src_pattern,
502 mask_pattern != NULL);
503 if (operation == DO_UNSUPPORTED)
504 return UNSUPPORTED ("unsupported operation");
506 //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
508 operation = _recategorize_composite_operation (dst, op, src, &src_attr,
509 mask_pattern != NULL);
510 if (operation == DO_UNSUPPORTED) {
511 status = UNSUPPORTED ("unsupported operation");
516 static cairo_int_status_t
517 composite (void *abstract_dst,
519 cairo_surface_t *abstract_src,
520 cairo_surface_t *abstract_mask,
530 cairo_xlib_surface_t *dst = abstract_dst;
531 cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
533 op = _render_operator (op);
535 _cairo_xlib_surface_ensure_picture (dst);
537 cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
539 XRenderComposite (dst->dpy, op,
540 src->picture, mask->picture, dst->picture,
546 XRenderComposite (dst->dpy, op,
547 src->picture, 0, dst->picture,
554 return CAIRO_STATUS_SUCCESS;
557 static cairo_int_status_t
558 lerp (void *abstract_dst,
559 cairo_surface_t *abstract_src,
560 cairo_surface_t *abstract_mask,
570 cairo_xlib_surface_t *dst = abstract_dst;
571 cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
572 cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
574 _cairo_xlib_surface_ensure_picture (dst);
575 XRenderComposite (dst->dpy, PictOpOutReverse,
576 mask->picture, None, dst->picture,
581 XRenderComposite (dst->dpy, PictOpAdd,
582 src->picture, mask->picture, dst->picture,
588 return CAIRO_STATUS_SUCCESS;
591 static cairo_int_status_t
592 composite_boxes (void *abstract_dst,
594 cairo_surface_t *abstract_src,
595 cairo_surface_t *abstract_mask,
602 cairo_boxes_t *boxes,
603 const cairo_rectangle_int_t *extents)
605 cairo_xlib_surface_t *dst = abstract_dst;
606 Picture src = ((cairo_xlib_source_t *)abstract_src)->picture;
607 Picture mask = abstract_mask ? ((cairo_xlib_source_t *)abstract_mask)->picture : 0;
608 XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
609 XRectangle *rects = stack_rects;
610 struct _cairo_boxes_chunk *chunk;
613 op = _render_operator (op);
614 _cairo_xlib_surface_ensure_picture (dst);
615 if (boxes->num_boxes == 1) {
616 int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
617 int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
618 int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
619 int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
621 XRenderComposite (dst->dpy, op,
622 src, mask, dst->picture,
623 x1 + src_x, y1 + src_y,
624 x1 + mask_x, y1 + mask_y,
625 x1 - dst_x, y1 - dst_y,
627 return CAIRO_STATUS_SUCCESS;
630 if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
631 rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
632 if (unlikely (rects == NULL))
633 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
637 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
638 for (i = 0; i < chunk->count; i++) {
639 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
640 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
641 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
642 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
644 rects[j].x = x1 - dst_x;
645 rects[j].y = y1 - dst_y;
646 rects[j].width = x2 - x1;
647 rects[j].height = y2 - y1;
651 assert (j == boxes->num_boxes);
653 XRenderSetPictureClipRectangles (dst->dpy,
657 if (rects != stack_rects)
660 XRenderComposite (dst->dpy, op,
661 src, mask, dst->picture,
662 extents->x + src_x, extents->y + src_y,
663 extents->x + mask_x, extents->y + mask_y,
664 extents->x - dst_x, extents->y - dst_y,
665 extents->width, extents->height);
667 set_clip_region (dst, NULL);
669 return CAIRO_STATUS_SUCCESS;
675 _cairo_xlib_font_close (cairo_xlib_font_t *priv)
677 cairo_xlib_display_t *display = (cairo_xlib_display_t *)priv->base.key;
680 /* XXX All I really want is to do is zap my glyphs... */
681 _cairo_scaled_font_reset_cache (priv->font);
683 for (i = 0; i < NUM_GLYPHSETS; i++) {
684 cairo_xlib_font_glyphset_t *info;
686 info = &priv->glyphset[i];
688 XRenderFreeGlyphSet (display->display, info->glyphset);
692 cairo_list_del (&priv->link);
693 cairo_list_del (&priv->base.link);
698 _cairo_xlib_font_fini (cairo_scaled_font_private_t *abstract_private,
699 cairo_scaled_font_t *font)
701 cairo_xlib_font_t *priv = (cairo_xlib_font_t *) abstract_private;
702 cairo_status_t status;
703 cairo_xlib_display_t *display;
706 cairo_list_del (&priv->base.link);
707 cairo_list_del (&priv->link);
709 status = _cairo_xlib_display_acquire (priv->device, &display);
713 for (i = 0; i < NUM_GLYPHSETS; i++) {
714 cairo_xlib_font_glyphset_t *info;
716 info = &priv->glyphset[i];
718 XRenderFreeGlyphSet (display->display, info->glyphset);
721 cairo_device_release (&display->base);
723 cairo_device_destroy (&display->base);
727 static cairo_xlib_font_t *
728 _cairo_xlib_font_create (cairo_xlib_display_t *display,
729 cairo_scaled_font_t *font)
731 cairo_xlib_font_t *priv;
734 priv = malloc (sizeof (cairo_xlib_font_t));
735 if (unlikely (priv == NULL))
738 _cairo_scaled_font_attach_private (font, &priv->base, display,
739 _cairo_xlib_font_fini);
741 priv->device = cairo_device_reference (&display->base);
743 cairo_list_add (&priv->link, &display->fonts);
745 for (i = 0; i < NUM_GLYPHSETS; i++) {
746 cairo_xlib_font_glyphset_t *info = &priv->glyphset[i];
748 case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
749 case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break;
750 case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break;
751 default: ASSERT_NOT_REACHED; break;
753 info->xrender_format = NULL;
754 info->glyphset = None;
755 info->to_free.count = 0;
762 _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
764 if (format == CAIRO_FORMAT_A8)
765 return GLYPHSET_INDEX_A8;
766 if (format == CAIRO_FORMAT_A1)
767 return GLYPHSET_INDEX_A1;
769 assert (format == CAIRO_FORMAT_ARGB32);
770 return GLYPHSET_INDEX_ARGB32;
773 static inline cairo_xlib_font_t *
774 _cairo_xlib_font_get (const cairo_xlib_display_t *display,
775 cairo_scaled_font_t *font)
777 return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display);
781 cairo_scaled_glyph_private_t base;
784 cairo_xlib_font_glyphset_t *glyphset;
785 } cairo_xlib_glyph_private_t;
788 _cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
789 cairo_scaled_glyph_t *glyph,
790 cairo_scaled_font_t *font)
792 cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private;
794 if (! font->finished) {
795 cairo_xlib_font_t *font_private;
796 struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
797 cairo_xlib_font_glyphset_t *info;
799 font_private = _cairo_xlib_font_get (glyph_private->key, font);
800 assert (font_private);
802 info = priv->glyphset;
803 to_free = &info->to_free;
804 if (to_free->count == ARRAY_LENGTH (to_free->indices)) {
805 cairo_xlib_display_t *display;
807 if (_cairo_xlib_display_acquire (font_private->device,
808 &display) == CAIRO_STATUS_SUCCESS) {
809 XRenderFreeGlyphs (display->display,
813 cairo_device_release (&display->base);
819 to_free->indices[to_free->count++] =
820 _cairo_scaled_glyph_index (glyph);
823 cairo_list_del (&glyph_private->link);
824 free (glyph_private);
827 static cairo_status_t
828 _cairo_xlib_glyph_attach (cairo_xlib_display_t *display,
829 cairo_scaled_glyph_t *glyph,
830 cairo_xlib_font_glyphset_t *info)
832 cairo_xlib_glyph_private_t *priv;
834 priv = malloc (sizeof (*priv));
835 if (unlikely (priv == NULL))
836 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
838 _cairo_scaled_glyph_attach_private (glyph, &priv->base, display,
839 _cairo_xlib_glyph_fini);
840 priv->glyphset = info;
842 glyph->dev_private = info;
843 glyph->dev_private_key = display;
844 return CAIRO_STATUS_SUCCESS;
847 static cairo_xlib_font_glyphset_t *
848 _cairo_xlib_font_get_glyphset_info_for_format (cairo_xlib_display_t *display,
849 cairo_scaled_font_t *font,
850 cairo_format_t format)
852 cairo_xlib_font_t *priv;
853 cairo_xlib_font_glyphset_t *info;
856 glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
858 priv = _cairo_xlib_font_get (display, font);
860 priv = _cairo_xlib_font_create (display, font);
865 info = &priv->glyphset[glyphset_index];
866 if (info->glyphset == None) {
867 info->xrender_format =
868 _cairo_xlib_display_get_xrender_format (display, info->format);
869 info->glyphset = XRenderCreateGlyphSet (display->display,
870 info->xrender_format);
877 has_pending_free_glyph (cairo_xlib_font_glyphset_t *info,
878 unsigned long glyph_index)
880 struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
883 to_free = &info->to_free;
884 for (i = 0; i < to_free->count; i++) {
885 if (to_free->indices[i] == glyph_index) {
887 memmove (&to_free->indices[i],
888 &to_free->indices[i+1],
889 (to_free->count - i) * sizeof (to_free->indices[0]));
897 static cairo_xlib_font_glyphset_t *
898 find_pending_free_glyph (cairo_xlib_display_t *display,
899 cairo_scaled_font_t *font,
900 unsigned long glyph_index,
901 cairo_image_surface_t *surface)
903 cairo_xlib_font_t *priv;
906 priv = _cairo_xlib_font_get (display, font);
910 if (surface != NULL) {
911 i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
912 if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
913 return &priv->glyphset[i];
915 for (i = 0; i < NUM_GLYPHSETS; i++) {
916 if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
917 return &priv->glyphset[i];
924 static cairo_status_t
925 _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
926 cairo_scaled_font_t *font,
927 cairo_scaled_glyph_t **pscaled_glyph)
929 XGlyphInfo glyph_info;
930 unsigned long glyph_index;
932 cairo_status_t status = CAIRO_STATUS_SUCCESS;
933 cairo_scaled_glyph_t *glyph = *pscaled_glyph;
934 cairo_image_surface_t *glyph_surface = glyph->surface;
935 cairo_bool_t already_had_glyph_surface;
936 cairo_xlib_font_glyphset_t *info;
938 glyph_index = _cairo_scaled_glyph_index (glyph);
940 /* check to see if we have a pending XRenderFreeGlyph for this glyph */
941 info = find_pending_free_glyph (display, font, glyph_index, glyph_surface);
943 return _cairo_xlib_glyph_attach (display, glyph, info);
945 if (glyph_surface == NULL) {
946 status = _cairo_scaled_glyph_lookup (font,
948 CAIRO_SCALED_GLYPH_INFO_METRICS |
949 CAIRO_SCALED_GLYPH_INFO_SURFACE,
951 if (unlikely (status))
954 glyph = *pscaled_glyph;
955 glyph_surface = glyph->surface;
956 already_had_glyph_surface = FALSE;
958 already_had_glyph_surface = TRUE;
961 info = _cairo_xlib_font_get_glyphset_info_for_format (display, font,
962 glyph_surface->format);
965 /* If the glyph surface has zero height or width, we create
966 * a clear 1x1 surface, to avoid various X server bugs.
968 if (glyph_surface->width == 0 || glyph_surface->height == 0) {
969 cairo_surface_t *tmp_surface;
971 tmp_surface = cairo_image_surface_create (info->format, 1, 1);
972 status = tmp_surface->status;
973 if (unlikely (status))
976 tmp_surface->device_transform = glyph_surface->base.device_transform;
977 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
979 glyph_surface = (cairo_image_surface_t *) tmp_surface;
983 /* If the glyph format does not match the font format, then we
984 * create a temporary surface for the glyph image with the font's
987 if (glyph_surface->format != info->format) {
988 cairo_surface_pattern_t pattern;
989 cairo_surface_t *tmp_surface;
991 tmp_surface = cairo_image_surface_create (info->format,
992 glyph_surface->width,
993 glyph_surface->height);
994 status = tmp_surface->status;
995 if (unlikely (status))
998 tmp_surface->device_transform = glyph_surface->base.device_transform;
999 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
1001 _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
1002 status = _cairo_surface_paint (tmp_surface,
1003 CAIRO_OPERATOR_SOURCE, &pattern.base,
1005 _cairo_pattern_fini (&pattern.base);
1007 glyph_surface = (cairo_image_surface_t *) tmp_surface;
1009 if (unlikely (status))
1013 /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
1014 glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
1015 glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
1016 glyph_info.width = glyph_surface->width;
1017 glyph_info.height = glyph_surface->height;
1018 glyph_info.xOff = glyph->x_advance;
1019 glyph_info.yOff = glyph->y_advance;
1021 data = glyph_surface->data;
1023 /* flip formats around */
1024 switch (_cairo_xlib_get_glyphset_index_for_format (glyph->surface->format)) {
1025 case GLYPHSET_INDEX_A1:
1026 /* local bitmaps are always stored with bit == byte */
1027 if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) {
1028 int c = glyph_surface->stride * glyph_surface->height;
1030 unsigned char *new, *n;
1034 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1041 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
1042 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
1043 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
1049 case GLYPHSET_INDEX_A8:
1051 case GLYPHSET_INDEX_ARGB32:
1052 if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
1053 unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
1057 new = malloc (4 * c);
1058 if (unlikely (new == NULL)) {
1059 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1063 d = (uint32_t *) data;
1065 *n++ = bswap_32 (*d);
1068 data = (uint8_t *) new;
1075 /* XXX assume X server wants pixman padding. Xft assumes this as well */
1077 XRenderAddGlyphs (display->display, info->glyphset,
1078 &glyph_index, &glyph_info, 1,
1080 glyph_surface->stride * glyph_surface->height);
1082 if (data != glyph_surface->data)
1085 status = _cairo_xlib_glyph_attach (display, glyph, info);
1088 if (glyph_surface != glyph->surface)
1089 cairo_surface_destroy (&glyph_surface->base);
1091 /* if the scaled glyph didn't already have a surface attached
1092 * to it, release the created surface now that we have it
1093 * uploaded to the X server. If the surface has already been
1094 * there (eg. because image backend requested it), leave it in
1097 if (!already_had_glyph_surface)
1098 _cairo_scaled_glyph_set_surface (glyph, font, NULL);
1103 typedef void (*cairo_xrender_composite_text_func_t)
1108 _Xconst XRenderPictFormat *maskFormat,
1113 _Xconst XGlyphElt8 *elts,
1116 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
1117 * an input glyph with double coordinates, and as "working" glyph with
1118 * integer from-current-point offsets. */
1121 unsigned long index;
1123 unsigned long index;
1127 } cairo_xlib_glyph_t;
1129 /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
1130 COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
1132 /* Start a new element for the first glyph,
1133 * or for any glyph that has unexpected position,
1134 * or if current element has too many glyphs
1135 * (Xrender limits each element to 252 glyphs, we limit them to 128)
1137 * These same conditions need to be mirrored between
1138 * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
1140 #define _start_new_glyph_elt(count, glyph) \
1141 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
1143 static cairo_status_t
1144 _emit_glyphs_chunk (cairo_xlib_display_t *display,
1145 cairo_xlib_surface_t *dst,
1146 int dst_x, int dst_y,
1147 cairo_xlib_glyph_t *glyphs,
1149 cairo_scaled_font_t *font,
1150 cairo_bool_t use_mask,
1151 cairo_operator_t op,
1152 cairo_xlib_source_t *src,
1153 int src_x, int src_y,
1154 /* info for this chunk */
1157 cairo_xlib_font_glyphset_t *info)
1159 /* Which XRenderCompositeText function to use */
1160 cairo_xrender_composite_text_func_t composite_text_func;
1163 /* Element buffer stuff */
1165 XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
1167 /* Reuse the input glyph array for output char generation */
1168 char *char8 = (char *) glyphs;
1169 unsigned short *char16 = (unsigned short *) glyphs;
1170 unsigned int *char32 = (unsigned int *) glyphs;
1173 int nelt; /* Element index */
1174 int n; /* Num output glyphs in current element */
1175 int j; /* Num output glyphs so far */
1179 /* don't cast the 8-variant, to catch possible mismatches */
1180 composite_text_func = XRenderCompositeText8;
1181 size = sizeof (char);
1184 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
1185 size = sizeof (unsigned short);
1189 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
1190 size = sizeof (unsigned int);
1193 /* Allocate element array */
1194 if (num_elts <= ARRAY_LENGTH (stack_elts)) {
1197 elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
1198 if (unlikely (elts == NULL))
1199 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1206 for (i = 0; i < num_glyphs; i++) {
1207 /* Start a new element for first output glyph,
1208 * or for any glyph that has unexpected position,
1209 * or if current element has too many glyphs.
1211 * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
1213 if (_start_new_glyph_elt (j, &glyphs[i])) {
1215 elts[nelt].nchars = n;
1219 elts[nelt].chars = char8 + size * j;
1220 elts[nelt].glyphset = info->glyphset;
1221 elts[nelt].xOff = glyphs[i].i.x - dst_x;
1222 elts[nelt].yOff = glyphs[i].i.y - dst_y;
1226 case 1: char8 [j] = (char) glyphs[i].index; break;
1227 case 2: char16[j] = (unsigned short) glyphs[i].index; break;
1229 case 4: char32[j] = (unsigned int) glyphs[i].index; break;
1237 elts[nelt].nchars = n;
1241 /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
1242 * expected number of xGlyphElts. */
1243 assert (nelt == num_elts);
1245 composite_text_func (display->display, op,
1248 use_mask ? info->xrender_format : NULL,
1249 src_x + elts[0].xOff + dst_x,
1250 src_y + elts[0].yOff + dst_y,
1251 elts[0].xOff, elts[0].yOff,
1252 (XGlyphElt8 *) elts, nelt);
1254 if (elts != stack_elts)
1257 return CAIRO_STATUS_SUCCESS;
1260 static cairo_int_status_t
1261 check_composite_glyphs (const cairo_composite_rectangles_t *extents,
1262 cairo_scaled_font_t *font,
1263 cairo_glyph_t *glyphs,
1266 cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
1267 cairo_xlib_display_t *display = dst->display;
1268 int max_request_size, size;
1270 if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
1271 return CAIRO_INT_STATUS_UNSUPPORTED;
1273 /* The glyph coordinates must be representable in an int16_t.
1274 * When possible, they will be expressed as an offset from the
1275 * previous glyph, otherwise they will be an offset from the
1276 * surface origin. If we can't guarantee this to be possible,
1279 if (extents->bounded.x + extents->bounded.width > INT16_MAX ||
1280 extents->bounded.y + extents->bounded.height> INT16_MAX ||
1281 extents->bounded.x < INT16_MIN ||
1282 extents->bounded.y < INT16_MIN)
1284 return CAIRO_INT_STATUS_UNSUPPORTED;
1287 /* Approximate the size of the largest glyph and fallback if we can not
1288 * upload it to the xserver.
1290 size = ceil (font->max_scale);
1291 size = 4 * size * size;
1292 max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
1293 : XMaxRequestSize (display->display)) * 4 -
1294 sz_xRenderAddGlyphsReq -
1297 if (size >= max_request_size)
1298 return CAIRO_INT_STATUS_UNSUPPORTED;
1300 return CAIRO_STATUS_SUCCESS;
1303 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
1304 * enough room for padding */
1305 #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
1307 static cairo_int_status_t
1308 composite_glyphs (void *surface,
1309 cairo_operator_t op,
1310 cairo_surface_t *_src,
1315 cairo_composite_glyphs_info_t *info)
1317 cairo_xlib_surface_t *dst = surface;
1318 cairo_xlib_glyph_t *glyphs = (cairo_xlib_glyph_t *)info->glyphs;
1319 cairo_xlib_source_t *src = (cairo_xlib_source_t *)_src;
1320 cairo_xlib_display_t *display = dst->display;
1321 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1322 cairo_scaled_glyph_t *glyph;
1323 cairo_fixed_t x = 0, y = 0;
1324 cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
1326 unsigned long max_index = 0;
1329 int num_out_glyphs = 0;
1330 int num_glyphs = info->num_glyphs;
1332 int max_request_size = XMaxRequestSize (display->display) * 4
1333 - MAX (sz_xRenderCompositeGlyphs8Req,
1334 MAX(sz_xRenderCompositeGlyphs16Req,
1335 sz_xRenderCompositeGlyphs32Req));
1336 int request_size = 0;
1339 op = _render_operator (op),
1340 _cairo_xlib_surface_ensure_picture (dst);
1341 for (i = 0; i < num_glyphs; i++) {
1345 status = _cairo_scaled_glyph_lookup (info->font,
1347 CAIRO_SCALED_GLYPH_INFO_METRICS,
1349 if (unlikely (status))
1352 this_x = _cairo_lround (glyphs[i].d.x);
1353 this_y = _cairo_lround (glyphs[i].d.y);
1355 /* Send unsent glyphs to the server */
1356 if (glyph->dev_private_key != display) {
1357 status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph);
1358 if (unlikely (status))
1362 this_glyphset_info = glyph->dev_private;
1364 glyphset = this_glyphset_info;
1366 /* The invariant here is that we can always flush the glyphs
1367 * accumulated before this one, using old_width, and they
1368 * would fit in the request.
1372 /* Update max glyph index */
1373 if (glyphs[i].index > max_index) {
1374 max_index = glyphs[i].index;
1375 if (max_index >= 65536)
1377 else if (max_index >= 256)
1379 if (width != old_width)
1380 request_size += (width - old_width) * num_out_glyphs;
1383 /* If we will pass the max request size by adding this glyph,
1384 * flush current glyphs. Note that we account for a
1385 * possible element being added below.
1387 * Also flush if changing glyphsets, as Xrender limits one mask
1388 * format per request, so we can either break up, or use a
1389 * wide-enough mask format. We do the former. One reason to
1390 * prefer the latter is the fact that Xserver ADDs all glyphs
1391 * to the mask first, and then composes that to final surface,
1392 * though it's not a big deal.
1394 * If the glyph has a coordinate which cannot be represented
1395 * as a 16-bit offset from the previous glyph, flush the
1396 * current chunk. The current glyph will be the first one in
1397 * the next chunk, thus its coordinates will be an offset from
1398 * the destination origin. This offset is guaranteed to be
1399 * representable as 16-bit offset (otherwise we would have
1402 if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
1403 this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
1404 this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
1405 (this_glyphset_info != glyphset)) {
1406 status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
1407 glyphs, i, info->font, info->use_mask,
1408 op, src, src_x, src_y,
1409 num_elts, old_width, glyphset);
1410 if (unlikely (status))
1416 max_index = glyphs[i].index;
1417 width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
1422 glyphset = this_glyphset_info;
1425 /* Convert absolute glyph position to relative-to-current-point
1427 glyphs[i].i.x = this_x - x;
1428 glyphs[i].i.y = this_y - y;
1430 /* Start a new element for the first glyph,
1431 * or for any glyph that has unexpected position,
1432 * or if current element has too many glyphs.
1434 * These same conditions are mirrored in _emit_glyphs_chunk().
1436 if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
1438 request_size += _cairo_sz_xGlyphElt;
1441 /* adjust current-position */
1442 x = this_x + glyph->x_advance;
1443 y = this_y + glyph->y_advance;
1446 request_size += width;
1450 status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
1451 glyphs, i, info->font, info->use_mask,
1452 op, src, src_x, src_y,
1453 num_elts, width, glyphset);
1459 const cairo_compositor_t *
1460 _cairo_xlib_mask_compositor_get (void)
1462 static cairo_mask_compositor_t compositor;
1464 if (compositor.base.delegate == NULL) {
1465 _cairo_mask_compositor_init (&compositor,
1466 _cairo_xlib_fallback_compositor_get ());
1468 compositor.acquire = acquire;
1469 compositor.release = release;
1470 compositor.set_clip_region = set_clip_region;
1471 compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
1472 compositor.draw_image_boxes = draw_image_boxes;
1473 compositor.fill_rectangles = fill_rectangles;
1474 compositor.fill_boxes = fill_boxes;
1475 compositor.copy_boxes = copy_boxes;
1476 //compositor.check_composite = check_composite;
1477 compositor.composite = composite;
1478 //compositor.check_composite_boxes = check_composite_boxes;
1479 compositor.composite_boxes = composite_boxes;
1480 compositor.check_composite_glyphs = check_composite_glyphs;
1481 compositor.composite_glyphs = composite_glyphs;
1484 return &compositor.base;
1487 #define CAIRO_FIXED_16_16_MIN -32768
1488 #define CAIRO_FIXED_16_16_MAX 32767
1491 line_exceeds_16_16 (const cairo_line_t *line)
1494 line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1495 line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1496 line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1497 line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1498 line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1499 line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1500 line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1501 line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
1505 project_line_x_onto_16_16 (const cairo_line_t *line,
1507 cairo_fixed_t bottom,
1510 cairo_point_double_t p1, p2;
1513 p1.x = _cairo_fixed_to_double (line->p1.x);
1514 p1.y = _cairo_fixed_to_double (line->p1.y);
1516 p2.x = _cairo_fixed_to_double (line->p2.x);
1517 p2.y = _cairo_fixed_to_double (line->p2.y);
1519 m = (p2.x - p1.x) / (p2.y - p1.y);
1520 out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
1521 out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
1524 static cairo_int_status_T
1525 check_composite_trapezoids ()
1527 operation = _categorize_composite_operation (dst, op, pattern, TRUE);
1528 if (operation == DO_UNSUPPORTED)
1529 return UNSUPPORTED ("unsupported operation");
1531 operation = _recategorize_composite_operation (dst, op, src,
1533 if (operation == DO_UNSUPPORTED) {
1534 status = UNSUPPORTED ("unsupported operation");
1541 static cairo_int_status_t
1542 composite_traps (void *abstract_dst,
1543 cairo_operator_t op,
1544 cairo_surface_t *abstract_src,
1549 const cairo_rectangle_int_t *extents,
1550 cairo_antialias_t antialias,
1551 cairo_traps_t *traps)
1553 cairo_xlib_surface_t *dst = abstract_dst;
1554 cairo_xlib_display_t *display = dst->display;
1555 cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
1556 XRenderPictFormat *pict_format;
1557 XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
1558 XTrapezoid *xtraps = xtraps_stack;
1562 //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1564 if (dst->base.is_clear &&
1565 (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))
1567 op = CAIRO_OPERATOR_SOURCE;
1571 _cairo_xlib_display_get_xrender_format (display,
1572 antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1574 if (traps->num_traps > ARRAY_LENGTH (xtraps_stack)) {
1575 xtraps = _cairo_malloc_ab (traps->num_traps, sizeof (XTrapezoid));
1576 if (unlikely (xtraps == NULL))
1577 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1582 for (i = 0; i < traps->num_traps; i++) {
1583 cairo_trapezoid_t *t = &traps->traps[i];
1585 /* top/bottom will be clamped to surface bounds */
1586 xtraps[i].top = _cairo_fixed_to_16_16(t->top) + dy;
1587 xtraps[i].bottom = _cairo_fixed_to_16_16(t->bottom) + dy;
1589 /* However, all the other coordinates will have been left untouched so
1590 * as not to introduce numerical error. Recompute them if they
1591 * exceed the 16.16 limits.
1593 if (unlikely (line_exceeds_16_16 (&t->left))) {
1594 project_line_x_onto_16_16 (&t->left, t->top, t->bottom,
1596 xtraps[i].left.p1.x += dx;
1597 xtraps[i].left.p2.x += dx;
1598 xtraps[i].left.p1.y = xtraps[i].top;
1599 xtraps[i].left.p2.y = xtraps[i].bottom;
1601 xtraps[i].left.p1.x = _cairo_fixed_to_16_16(t->left.p1.x) + dx;
1602 xtraps[i].left.p1.y = _cairo_fixed_to_16_16(t->left.p1.y) + dy;
1603 xtraps[i].left.p2.x = _cairo_fixed_to_16_16(t->left.p2.x) + dx;
1604 xtraps[i].left.p2.y = _cairo_fixed_to_16_16(t->left.p2.y) + dy;
1607 if (unlikely (line_exceeds_16_16 (&t->right))) {
1608 project_line_x_onto_16_16 (&t->right, t->top, t->bottom,
1610 xtraps[i].right.p1.x += dx;
1611 xtraps[i].right.p2.x += dx;
1612 xtraps[i].right.p1.y = xtraps[i].top;
1613 xtraps[i].right.p2.y = xtraps[i].bottom;
1615 xtraps[i].right.p1.x = _cairo_fixed_to_16_16(t->right.p1.x) + dx;
1616 xtraps[i].right.p1.y = _cairo_fixed_to_16_16(t->right.p1.y) + dy;
1617 xtraps[i].right.p2.x = _cairo_fixed_to_16_16(t->right.p2.x) + dx;
1618 xtraps[i].right.p2.y = _cairo_fixed_to_16_16(t->right.p2.y) + dy;
1622 if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
1623 src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
1624 src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
1626 src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
1627 src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
1632 _cairo_xlib_surface_ensure_picture (dst);
1633 _cairo_xlib_surface_set_precision (dst, antialias);
1634 XRenderCompositeTrapezoids (dst->dpy,
1635 _render_operator (op),
1636 src->picture, dst->picture,
1639 xtraps, traps->num_traps);
1641 if (xtraps != xtraps_stack)
1644 return CAIRO_STATUS_SUCCESS;
1647 static cairo_int_status_t
1648 composite_tristrip (void *abstract_dst,
1649 cairo_operator_t op,
1650 cairo_surface_t *abstract_src,
1655 const cairo_rectangle_int_t *extents,
1656 cairo_antialias_t antialias,
1657 cairo_tristrip_t *strip)
1659 cairo_xlib_surface_t *dst = abstract_dst;
1660 cairo_xlib_display_t *display = dst->display;
1661 cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
1662 XRenderPictFormat *pict_format;
1663 XPointFixed points_stack[CAIRO_STACK_ARRAY_LENGTH (XPointFixed)];
1664 XPointFixed *points = points_stack;
1668 //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1671 _cairo_xlib_display_get_xrender_format (display,
1672 antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1674 if (strip->num_points > ARRAY_LENGTH (points_stack)) {
1675 points = _cairo_malloc_ab (strip->num_points, sizeof (XPointFixed));
1676 if (unlikely (points == NULL))
1677 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1682 for (i = 0; i < strip->num_points; i++) {
1683 cairo_point_t *p = &strip->points[i];
1685 points[i].x = _cairo_fixed_to_16_16(p->x) + dx;
1686 points[i].y = _cairo_fixed_to_16_16(p->y) + dy;
1689 src_x += _cairo_fixed_16_16_floor (points[0].x) + dst_x;
1690 src_y += _cairo_fixed_16_16_floor (points[0].y) + dst_y;
1692 _cairo_xlib_surface_ensure_picture (dst);
1693 _cairo_xlib_surface_set_precision (dst, antialias);
1694 XRenderCompositeTriStrip (dst->dpy,
1695 _render_operator (op),
1696 src->picture, dst->picture,
1699 points, strip->num_points);
1701 if (points != points_stack)
1704 return CAIRO_STATUS_SUCCESS;
1707 static cairo_int_status_t
1708 check_composite (const cairo_composite_rectangles_t *extents)
1710 cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
1712 if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
1713 return CAIRO_INT_STATUS_UNSUPPORTED;
1715 return CAIRO_STATUS_SUCCESS;
1718 const cairo_compositor_t *
1719 _cairo_xlib_traps_compositor_get (void)
1721 static cairo_traps_compositor_t compositor;
1723 if (compositor.base.delegate == NULL) {
1724 _cairo_traps_compositor_init (&compositor,
1725 _cairo_xlib_mask_compositor_get ());
1727 compositor.acquire = acquire;
1728 compositor.release = release;
1729 compositor.set_clip_region = set_clip_region;
1730 compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
1731 compositor.draw_image_boxes = draw_image_boxes;
1732 compositor.copy_boxes = copy_boxes;
1733 compositor.fill_boxes = fill_boxes;
1734 compositor.check_composite = check_composite;
1735 compositor.composite = composite;
1736 compositor.lerp = lerp;
1737 //compositor.check_composite_boxes = check_composite_boxes;
1738 compositor.composite_boxes = composite_boxes;
1739 //compositor.check_composite_traps = check_composite_traps;
1740 compositor.composite_traps = composite_traps;
1741 //compositor.check_composite_tristrip = check_composite_tristrip;
1742 compositor.composite_tristrip = composite_tristrip;
1743 compositor.check_composite_glyphs = check_composite_glyphs;
1744 compositor.composite_glyphs = composite_glyphs;
1747 return &compositor.base;
1750 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */