a892985b7d7e4958e6bc3dd8dd94d3172d63c0d9
[framework/graphics/cairo.git] / src / cairo-xlib-render-compositor.c
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
3  *
4  * Copyright © 2002 University of Southern California
5  * Copyright © 2005 Red Hat, Inc.
6  * Copyright © 2011 Intel Corporation
7  *
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.
15  *
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
21  *
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/
26  *
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.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is University of Southern
34  * California.
35  *
36  * Contributor(s):
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
41  */
42
43 #include "cairoint.h"
44
45 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
46
47 #include "cairo-xlib-private.h"
48
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"
55
56 static cairo_int_status_t
57 acquire (void *abstract_dst)
58 {
59     cairo_xlib_surface_t *dst = abstract_dst;
60     cairo_int_status_t status;
61
62     status = _cairo_xlib_display_acquire (dst->base.device, &dst->display);
63     if (unlikely (status))
64         return status;
65
66     dst->dpy = dst->display->display;
67     return CAIRO_STATUS_SUCCESS;
68 }
69
70 static cairo_int_status_t
71 release (void *abstract_dst)
72 {
73     cairo_xlib_surface_t *dst = abstract_dst;
74
75     cairo_device_release (&dst->display->base);
76     dst->dpy = NULL;
77
78     return CAIRO_STATUS_SUCCESS;
79 }
80
81 static cairo_int_status_t
82 set_clip_region (void *_surface,
83                  cairo_region_t *region)
84 {
85     cairo_xlib_surface_t *surface = _surface;
86
87     _cairo_xlib_surface_ensure_picture (surface);
88
89     if (region != NULL) {
90         XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
91         XRectangle *rects = stack_rects;
92         int n_rects, i;
93
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);
99         }
100         for (i = 0; i < n_rects; i++) {
101             cairo_rectangle_int_t rect;
102
103             cairo_region_get_rectangle (region, i, &rect);
104
105             rects[i].x = rect.x;
106             rects[i].y = rect.y;
107             rects[i].width  = rect.width;
108             rects[i].height = rect.height;
109         }
110         XRenderSetPictureClipRectangles (surface->dpy,
111                                          surface->picture,
112                                          0, 0,
113                                          rects, n_rects);
114         if (rects != stack_rects)
115             free (rects);
116     } else {
117         XRenderPictureAttributes pa;
118         pa.clip_mask = None;
119         XRenderChangePicture (surface->dpy,
120                               surface->picture,
121                               CPClipMask, &pa);
122     }
123
124     return CAIRO_STATUS_SUCCESS;
125 }
126
127 static cairo_int_status_t
128 draw_image_boxes (void *_dst,
129                   cairo_image_surface_t *image,
130                   cairo_boxes_t *boxes,
131                   int dx, int dy)
132 {
133     struct _cairo_boxes_chunk *chunk;
134     int i;
135
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,
144                                                  x1 + dx, y1 + dy,
145                                                  x2 - x1, y2 - y1,
146                                                  x1, y1))
147                 return CAIRO_INT_STATUS_UNSUPPORTED;
148         }
149     }
150
151     return CAIRO_STATUS_SUCCESS;
152 }
153
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,
159             int dx, int dy)
160 {
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;
165     GC gc;
166     int i, j;
167
168     if (! _cairo_xlib_surface_same_screen  (dst, src))
169         return CAIRO_INT_STATUS_UNSUPPORTED;
170
171     if (dst->depth != src->depth)
172         return CAIRO_INT_STATUS_UNSUPPORTED;
173
174     status = acquire (dst);
175     if (unlikely (status))
176         return status;
177
178     status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
179     if (unlikely (status)) {
180         release (dst);
181         return status;
182     }
183
184     if (! src->owns_pixmap) {
185         XGCValues gcv;
186
187         gcv.subwindow_mode = IncludeInferiors;
188         XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
189     }
190
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);
196
197         XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
198                    x1 + dx, y1 + dy,
199                    x2 - x1, y2 - y1,
200                    x1,      y1);
201     } else {
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
209          * Window.
210          */
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,
219                                x1 + dx, y1 + dy,
220                                x2 - x1, y2 - y1,
221                                x1,      y1);
222                 }
223             }
224         } else {
225             XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
226             XRectangle *rects = stack_rects;
227
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);
232             }
233
234             j = 0;
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);
241
242                     rects[j].x = x1;
243                     rects[j].y = y1;
244                     rects[j].width  = x2 - x1;
245                     rects[j].height = y2 - y1;
246                     j++;
247                 }
248             }
249             assert (j == boxes->num_boxes);
250
251             XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
252
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);
257
258             XSetClipMask (dst->dpy, gc, None);
259
260             if (rects != stack_rects)
261                 free (rects);
262         }
263     }
264
265     if (! src->owns_pixmap) {
266         XGCValues gcv;
267
268         gcv.subwindow_mode = ClipByChildren;
269         XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
270     }
271
272     _cairo_xlib_surface_put_gc (dst->display, dst, gc);
273     release (dst);
274     return CAIRO_STATUS_SUCCESS;
275 }
276
277 static int
278 _render_operator (cairo_operator_t op)
279 {
280     switch (op) {
281     case CAIRO_OPERATOR_CLEAR:
282         return PictOpClear;
283
284     case CAIRO_OPERATOR_SOURCE:
285         return PictOpSrc;
286     case CAIRO_OPERATOR_OVER:
287         return PictOpOver;
288     case CAIRO_OPERATOR_IN:
289         return PictOpIn;
290     case CAIRO_OPERATOR_OUT:
291         return PictOpOut;
292     case CAIRO_OPERATOR_ATOP:
293         return PictOpAtop;
294
295     case CAIRO_OPERATOR_DEST:
296         return PictOpDst;
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;
305
306     case CAIRO_OPERATOR_XOR:
307         return PictOpXor;
308     case CAIRO_OPERATOR_ADD:
309         return PictOpAdd;
310     case CAIRO_OPERATOR_SATURATE:
311         return PictOpSaturate;
312
313     case CAIRO_OPERATOR_MULTIPLY:
314         return PictOpMultiply;
315     case CAIRO_OPERATOR_SCREEN:
316         return PictOpScreen;
317     case CAIRO_OPERATOR_OVERLAY:
318         return PictOpOverlay;
319     case CAIRO_OPERATOR_DARKEN:
320         return PictOpDarken;
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:
336         return PictOpHSLHue;
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;
343
344     default:
345         ASSERT_NOT_REACHED;
346         return PictOpOver;
347     }
348 }
349
350 static cairo_bool_t
351 fill_reduces_to_source (cairo_operator_t op,
352                         const cairo_color_t *color,
353                         cairo_xlib_surface_t *dst)
354 {
355     if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color)) {
356         if (op == CAIRO_OPERATOR_OVER)
357             return TRUE;
358         if (op == CAIRO_OPERATOR_ADD)
359             return (dst->base.content & CAIRO_CONTENT_COLOR) == 0;
360     }
361
362     return FALSE;
363 }
364
365 static cairo_int_status_t
366 fill_rectangles (void                           *abstract_surface,
367                  cairo_operator_t                op,
368                  const cairo_color_t            *color,
369                  cairo_rectangle_int_t          *rects,
370                  int                             num_rects)
371 {
372     cairo_xlib_surface_t *dst = abstract_surface;
373     XRenderColor render_color;
374     int i;
375
376     //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
377
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;
382
383     if (fill_reduces_to_source (op, color, dst))
384         op = CAIRO_OPERATOR_SOURCE;
385
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().
390          */
391         XRenderFillRectangle (dst->dpy,
392                               _render_operator (op),
393                               dst->picture,
394                               &render_color,
395                               rects->x, rects->y,
396                               rects->width, rects->height);
397     } else {
398         XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
399         XRectangle *xrects = stack_xrects;
400
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);
405         }
406
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;
412         }
413
414         XRenderFillRectangles (dst->dpy,
415                                _render_operator (op),
416                                dst->picture,
417                                &render_color, xrects, num_rects);
418
419         if (xrects != stack_xrects)
420             free (xrects);
421     }
422
423     return CAIRO_STATUS_SUCCESS;
424 }
425
426 static cairo_int_status_t
427 fill_boxes (void                *abstract_surface,
428             cairo_operator_t     op,
429             const cairo_color_t *color,
430             cairo_boxes_t       *boxes)
431 {
432     cairo_xlib_surface_t *dst = abstract_surface;
433     XRenderColor render_color;
434
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;
439
440     if (fill_reduces_to_source (op, color, dst))
441         op = CAIRO_OPERATOR_SOURCE;
442
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);
449
450         /* Take advantage of the protocol compaction that libXrender performs
451          * to amalgamate sequences of XRenderFillRectangle().
452          */
453         XRenderFillRectangle (dst->dpy,
454                               _render_operator (op),
455                               dst->picture,
456                               &render_color,
457                               x1, y1,
458                               x2 - x1, y2 - y1);
459     } else {
460         XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
461         XRectangle *xrects = stack_xrects;
462         struct _cairo_boxes_chunk *chunk;
463         int i, j;
464
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);
469         }
470
471         j = 0;
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);
478
479                 xrects[j].x = x1;
480                 xrects[j].y = y1;
481                 xrects[j].width  = x2 - x1;
482                 xrects[j].height = y2 - y1;
483                 j++;
484             }
485         }
486
487         XRenderFillRectangles (dst->dpy,
488                                _render_operator (op),
489                                dst->picture,
490                                &render_color, xrects, j);
491
492         if (xrects != stack_xrects)
493             free (xrects);
494     }
495
496     return CAIRO_STATUS_SUCCESS;
497 }
498
499 #if 0
500 check_composite ()
501     operation = _categorize_composite_operation (dst, op, src_pattern,
502                                                  mask_pattern != NULL);
503     if (operation == DO_UNSUPPORTED)
504         return UNSUPPORTED ("unsupported operation");
505
506     //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
507
508     operation = _recategorize_composite_operation (dst, op, src, &src_attr,
509                                                    mask_pattern != NULL);
510     if (operation == DO_UNSUPPORTED) {
511         status = UNSUPPORTED ("unsupported operation");
512         goto BAIL;
513     }
514 #endif
515
516 static cairo_int_status_t
517 composite (void *abstract_dst,
518            cairo_operator_t     op,
519            cairo_surface_t      *abstract_src,
520            cairo_surface_t      *abstract_mask,
521            int                  src_x,
522            int                  src_y,
523            int                  mask_x,
524            int                  mask_y,
525            int                  dst_x,
526            int                  dst_y,
527            unsigned int         width,
528            unsigned int         height)
529 {
530     cairo_xlib_surface_t *dst = abstract_dst;
531     cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
532
533     op = _render_operator (op);
534
535     _cairo_xlib_surface_ensure_picture (dst);
536     if (abstract_mask) {
537         cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
538
539         XRenderComposite (dst->dpy, op,
540                           src->picture, mask->picture, dst->picture,
541                           src_x,  src_y,
542                           mask_x, mask_y,
543                           dst_x,  dst_y,
544                           width,  height);
545     } else {
546         XRenderComposite (dst->dpy, op,
547                           src->picture, 0, dst->picture,
548                           src_x, src_y,
549                           0, 0,
550                           dst_x, dst_y,
551                           width, height);
552     }
553
554     return CAIRO_STATUS_SUCCESS;
555 }
556
557 static cairo_int_status_t
558 lerp (void *abstract_dst,
559       cairo_surface_t   *abstract_src,
560       cairo_surface_t   *abstract_mask,
561       int                       src_x,
562       int                       src_y,
563       int                       mask_x,
564       int                       mask_y,
565       int                       dst_x,
566       int                       dst_y,
567       unsigned int              width,
568       unsigned int              height)
569 {
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;
573
574     _cairo_xlib_surface_ensure_picture (dst);
575     XRenderComposite (dst->dpy, PictOpOutReverse,
576                       mask->picture, None, dst->picture,
577                       mask_x, mask_y,
578                       0,      0,
579                       dst_x,  dst_y,
580                       width,  height);
581     XRenderComposite (dst->dpy, PictOpAdd,
582                       src->picture, mask->picture, dst->picture,
583                       src_x,  src_y,
584                       mask_x, mask_y,
585                       dst_x,  dst_y,
586                       width,  height);
587
588     return CAIRO_STATUS_SUCCESS;
589 }
590
591 static cairo_int_status_t
592 composite_boxes (void                   *abstract_dst,
593                  cairo_operator_t        op,
594                  cairo_surface_t        *abstract_src,
595                  cairo_surface_t        *abstract_mask,
596                  int                    src_x,
597                  int                    src_y,
598                  int                    mask_x,
599                  int                    mask_y,
600                  int                    dst_x,
601                  int                    dst_y,
602                  cairo_boxes_t          *boxes,
603                  const cairo_rectangle_int_t  *extents)
604 {
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;
611     int i, j;
612
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);
620
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,
626                           x2 - x1,      y2 - y1);
627         return CAIRO_STATUS_SUCCESS;
628     }
629
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);
634     }
635
636     j = 0;
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);
643
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;
648             j++;
649         }
650     }
651     assert (j == boxes->num_boxes);
652
653     XRenderSetPictureClipRectangles (dst->dpy,
654                                      dst->picture,
655                                      0, 0,
656                                      rects, j);
657     if (rects != stack_rects)
658         free (rects);
659
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);
666
667     set_clip_region (dst, NULL);
668
669     return CAIRO_STATUS_SUCCESS;
670 }
671
672 /* font rendering */
673
674 void
675 _cairo_xlib_font_close (cairo_xlib_font_t *priv)
676 {
677     cairo_xlib_display_t *display = (cairo_xlib_display_t *)priv->base.key;
678     int i;
679
680     /* XXX All I really want is to do is zap my glyphs... */
681     _cairo_scaled_font_reset_cache (priv->font);
682
683     for (i = 0; i < NUM_GLYPHSETS; i++) {
684         cairo_xlib_font_glyphset_t *info;
685
686         info = &priv->glyphset[i];
687         if (info->glyphset)
688             XRenderFreeGlyphSet (display->display, info->glyphset);
689     }
690
691     /* XXX locking */
692     cairo_list_del (&priv->link);
693     cairo_list_del (&priv->base.link);
694     free (priv);
695 }
696
697 static void
698 _cairo_xlib_font_fini (cairo_scaled_font_private_t *abstract_private,
699                        cairo_scaled_font_t *font)
700 {
701     cairo_xlib_font_t *priv = (cairo_xlib_font_t *) abstract_private;
702     cairo_status_t status;
703     cairo_xlib_display_t *display;
704     int i;
705
706     cairo_list_del (&priv->base.link);
707     cairo_list_del (&priv->link);
708
709     status = _cairo_xlib_display_acquire (priv->device, &display);
710     if (status)
711         goto BAIL;
712
713     for (i = 0; i < NUM_GLYPHSETS; i++) {
714         cairo_xlib_font_glyphset_t *info;
715
716         info = &priv->glyphset[i];
717         if (info->glyphset)
718             XRenderFreeGlyphSet (display->display, info->glyphset);
719     }
720
721     cairo_device_release (&display->base);
722 BAIL:
723     cairo_device_destroy (&display->base);
724     free (priv);
725 }
726
727 static cairo_xlib_font_t *
728 _cairo_xlib_font_create (cairo_xlib_display_t *display,
729                          cairo_scaled_font_t  *font)
730 {
731     cairo_xlib_font_t *priv;
732     int i;
733
734     priv = malloc (sizeof (cairo_xlib_font_t));
735     if (unlikely (priv == NULL))
736         return NULL;
737
738     _cairo_scaled_font_attach_private (font, &priv->base, display,
739                                        _cairo_xlib_font_fini);
740
741     priv->device = cairo_device_reference (&display->base);
742     priv->font = font;
743     cairo_list_add (&priv->link, &display->fonts);
744
745     for (i = 0; i < NUM_GLYPHSETS; i++) {
746         cairo_xlib_font_glyphset_t *info = &priv->glyphset[i];
747         switch (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;
752         }
753         info->xrender_format = NULL;
754         info->glyphset = None;
755         info->to_free.count = 0;
756     }
757
758     return priv;
759 }
760
761 static int
762 _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
763 {
764     if (format == CAIRO_FORMAT_A8)
765         return GLYPHSET_INDEX_A8;
766     if (format == CAIRO_FORMAT_A1)
767         return GLYPHSET_INDEX_A1;
768
769     assert (format == CAIRO_FORMAT_ARGB32);
770     return GLYPHSET_INDEX_ARGB32;
771 }
772
773 static inline cairo_xlib_font_t *
774 _cairo_xlib_font_get (const cairo_xlib_display_t *display,
775                       cairo_scaled_font_t *font)
776 {
777     return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display);
778 }
779
780 typedef struct {
781     cairo_scaled_glyph_private_t base;
782
783
784     cairo_xlib_font_glyphset_t *glyphset;
785 } cairo_xlib_glyph_private_t;
786
787 static void
788 _cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
789                         cairo_scaled_glyph_t *glyph,
790                         cairo_scaled_font_t  *font)
791 {
792     cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private;
793
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;
798
799         font_private = _cairo_xlib_font_get (glyph_private->key, font);
800         assert (font_private);
801
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;
806
807             if (_cairo_xlib_display_acquire (font_private->device,
808                                              &display) == CAIRO_STATUS_SUCCESS) {
809                 XRenderFreeGlyphs (display->display,
810                                    info->glyphset,
811                                    to_free->indices,
812                                    to_free->count);
813                 cairo_device_release (&display->base);
814             }
815
816             to_free->count = 0;
817         }
818
819         to_free->indices[to_free->count++] =
820             _cairo_scaled_glyph_index (glyph);
821     }
822
823     cairo_list_del (&glyph_private->link);
824     free (glyph_private);
825 }
826
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)
831 {
832     cairo_xlib_glyph_private_t *priv;
833
834     priv = malloc (sizeof (*priv));
835     if (unlikely (priv == NULL))
836         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
837
838     _cairo_scaled_glyph_attach_private (glyph, &priv->base, display,
839                                         _cairo_xlib_glyph_fini);
840     priv->glyphset = info;
841
842     glyph->dev_private = info;
843     glyph->dev_private_key = display;
844     return CAIRO_STATUS_SUCCESS;
845 }
846
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)
851 {
852     cairo_xlib_font_t *priv;
853     cairo_xlib_font_glyphset_t *info;
854     int glyphset_index;
855
856     glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
857
858     priv = _cairo_xlib_font_get (display, font);
859     if (priv == NULL) {
860         priv = _cairo_xlib_font_create (display, font);
861         if (priv == NULL)
862             return NULL;
863     }
864
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);
871     }
872
873     return info;
874 }
875
876 static cairo_bool_t
877 has_pending_free_glyph (cairo_xlib_font_glyphset_t *info,
878                         unsigned long glyph_index)
879 {
880     struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
881     int i;
882
883     to_free = &info->to_free;
884     for (i = 0; i < to_free->count; i++) {
885         if (to_free->indices[i] == glyph_index) {
886             to_free->count--;
887             memmove (&to_free->indices[i],
888                      &to_free->indices[i+1],
889                      (to_free->count - i) * sizeof (to_free->indices[0]));
890             return TRUE;
891         }
892     }
893
894     return FALSE;
895 }
896
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)
902 {
903     cairo_xlib_font_t *priv;
904     int i;
905
906     priv = _cairo_xlib_font_get (display, font);
907     if (priv == NULL)
908         return NULL;
909
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];
914     } else {
915         for (i = 0; i < NUM_GLYPHSETS; i++) {
916             if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
917                 return &priv->glyphset[i];
918         }
919     }
920
921     return NULL;
922 }
923
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)
928 {
929     XGlyphInfo glyph_info;
930     unsigned long glyph_index;
931     unsigned char *data;
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;
937
938     glyph_index = _cairo_scaled_glyph_index (glyph);
939
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);
942     if (info != NULL)
943         return _cairo_xlib_glyph_attach (display, glyph, info);
944
945     if (glyph_surface == NULL) {
946         status = _cairo_scaled_glyph_lookup (font,
947                                              glyph_index,
948                                              CAIRO_SCALED_GLYPH_INFO_METRICS |
949                                              CAIRO_SCALED_GLYPH_INFO_SURFACE,
950                                              pscaled_glyph);
951         if (unlikely (status))
952             return status;
953
954         glyph = *pscaled_glyph;
955         glyph_surface = glyph->surface;
956         already_had_glyph_surface = FALSE;
957     } else {
958         already_had_glyph_surface = TRUE;
959     }
960
961     info = _cairo_xlib_font_get_glyphset_info_for_format (display, font,
962                                                           glyph_surface->format);
963
964 #if 0
965     /* If the glyph surface has zero height or width, we create
966      * a clear 1x1 surface, to avoid various X server bugs.
967      */
968     if (glyph_surface->width == 0 || glyph_surface->height == 0) {
969         cairo_surface_t *tmp_surface;
970
971         tmp_surface = cairo_image_surface_create (info->format, 1, 1);
972         status = tmp_surface->status;
973         if (unlikely (status))
974             goto BAIL;
975
976         tmp_surface->device_transform = glyph_surface->base.device_transform;
977         tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
978
979         glyph_surface = (cairo_image_surface_t *) tmp_surface;
980     }
981 #endif
982
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
985      * format.
986      */
987     if (glyph_surface->format != info->format) {
988         cairo_surface_pattern_t pattern;
989         cairo_surface_t *tmp_surface;
990
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))
996             goto BAIL;
997
998         tmp_surface->device_transform = glyph_surface->base.device_transform;
999         tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
1000
1001         _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
1002         status = _cairo_surface_paint (tmp_surface,
1003                                        CAIRO_OPERATOR_SOURCE, &pattern.base,
1004                                        NULL);
1005         _cairo_pattern_fini (&pattern.base);
1006
1007         glyph_surface = (cairo_image_surface_t *) tmp_surface;
1008
1009         if (unlikely (status))
1010             goto BAIL;
1011     }
1012
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;
1020
1021     data = glyph_surface->data;
1022
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;
1029             unsigned char   *d;
1030             unsigned char   *new, *n;
1031
1032             new = malloc (c);
1033             if (!new) {
1034                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1035                 goto BAIL;
1036             }
1037             n = new;
1038             d = data;
1039             do {
1040                 char    b = *d++;
1041                 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
1042                 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
1043                 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
1044                 *n++ = b;
1045             } while (--c);
1046             data = new;
1047         }
1048         break;
1049     case GLYPHSET_INDEX_A8:
1050         break;
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;
1054             const uint32_t *d;
1055             uint32_t *new, *n;
1056
1057             new = malloc (4 * c);
1058             if (unlikely (new == NULL)) {
1059                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1060                 goto BAIL;
1061             }
1062             n = new;
1063             d = (uint32_t *) data;
1064             do {
1065                 *n++ = bswap_32 (*d);
1066                 d++;
1067             } while (--c);
1068             data = (uint8_t *) new;
1069         }
1070         break;
1071     default:
1072         ASSERT_NOT_REACHED;
1073         break;
1074     }
1075     /* XXX assume X server wants pixman padding. Xft assumes this as well */
1076
1077     XRenderAddGlyphs (display->display, info->glyphset,
1078                       &glyph_index, &glyph_info, 1,
1079                       (char *) data,
1080                       glyph_surface->stride * glyph_surface->height);
1081
1082     if (data != glyph_surface->data)
1083         free (data);
1084
1085     status = _cairo_xlib_glyph_attach (display, glyph, info);
1086
1087  BAIL:
1088     if (glyph_surface != glyph->surface)
1089         cairo_surface_destroy (&glyph_surface->base);
1090
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
1095      * the cache
1096      */
1097     if (!already_had_glyph_surface)
1098         _cairo_scaled_glyph_set_surface (glyph, font, NULL);
1099
1100     return status;
1101 }
1102
1103 typedef void (*cairo_xrender_composite_text_func_t)
1104               (Display                      *dpy,
1105                int                          op,
1106                Picture                      src,
1107                Picture                      dst,
1108                _Xconst XRenderPictFormat    *maskFormat,
1109                int                          xSrc,
1110                int                          ySrc,
1111                int                          xDst,
1112                int                          yDst,
1113                _Xconst XGlyphElt8           *elts,
1114                int                          nelt);
1115
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. */
1119 typedef union {
1120     cairo_glyph_t d;
1121     unsigned long index;
1122     struct {
1123         unsigned long index;
1124         int x;
1125         int y;
1126     } i;
1127 } cairo_xlib_glyph_t;
1128
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));
1131
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)
1136  *
1137  * These same conditions need to be mirrored between
1138  * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
1139  */
1140 #define _start_new_glyph_elt(count, glyph) \
1141     (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
1142
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,
1148                     int num_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 */
1155                     int num_elts,
1156                     int width,
1157                     cairo_xlib_font_glyphset_t *info)
1158 {
1159     /* Which XRenderCompositeText function to use */
1160     cairo_xrender_composite_text_func_t composite_text_func;
1161     int size;
1162
1163     /* Element buffer stuff */
1164     XGlyphElt8 *elts;
1165     XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
1166
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;
1171
1172     int i;
1173     int nelt; /* Element index */
1174     int n; /* Num output glyphs in current element */
1175     int j; /* Num output glyphs so far */
1176
1177     switch (width) {
1178     case 1:
1179         /* don't cast the 8-variant, to catch possible mismatches */
1180         composite_text_func = XRenderCompositeText8;
1181         size = sizeof (char);
1182         break;
1183     case 2:
1184         composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
1185         size = sizeof (unsigned short);
1186         break;
1187     default:
1188     case 4:
1189         composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
1190         size = sizeof (unsigned int);
1191     }
1192
1193     /* Allocate element array */
1194     if (num_elts <= ARRAY_LENGTH (stack_elts)) {
1195       elts = stack_elts;
1196     } else {
1197       elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
1198       if (unlikely (elts == NULL))
1199           return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1200     }
1201
1202     /* Fill them in */
1203     nelt = 0;
1204     n = 0;
1205     j = 0;
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.
1210        *
1211        * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
1212        */
1213       if (_start_new_glyph_elt (j, &glyphs[i])) {
1214           if (j) {
1215             elts[nelt].nchars = n;
1216             nelt++;
1217             n = 0;
1218           }
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;
1223       }
1224
1225       switch (width) {
1226       case 1: char8 [j] = (char)           glyphs[i].index; break;
1227       case 2: char16[j] = (unsigned short) glyphs[i].index; break;
1228       default:
1229       case 4: char32[j] = (unsigned int)   glyphs[i].index; break;
1230       }
1231
1232       n++;
1233       j++;
1234     }
1235
1236     if (n) {
1237         elts[nelt].nchars = n;
1238         nelt++;
1239     }
1240
1241     /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
1242      * expected number of xGlyphElts.  */
1243     assert (nelt == num_elts);
1244
1245     composite_text_func (display->display, op,
1246                          src->picture,
1247                          dst->picture,
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);
1253
1254     if (elts != stack_elts)
1255       free (elts);
1256
1257     return CAIRO_STATUS_SUCCESS;
1258 }
1259
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,
1264                         int *num_glyphs)
1265 {
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;
1269
1270     if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
1271         return CAIRO_INT_STATUS_UNSUPPORTED;
1272
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,
1277      * fallback.
1278      */
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)
1283     {
1284         return CAIRO_INT_STATUS_UNSUPPORTED;
1285     }
1286
1287     /* Approximate the size of the largest glyph and fallback if we can not
1288      * upload it to the xserver.
1289      */
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 -
1295         sz_xGlyphInfo          -
1296         8;
1297     if (size >= max_request_size)
1298         return CAIRO_INT_STATUS_UNSUPPORTED;
1299
1300     return CAIRO_STATUS_SUCCESS;
1301 }
1302
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)
1306
1307 static cairo_int_status_t
1308 composite_glyphs (void                          *surface,
1309                   cairo_operator_t               op,
1310                   cairo_surface_t               *_src,
1311                   int                            src_x,
1312                   int                            src_y,
1313                   int                            dst_x,
1314                   int                            dst_y,
1315                   cairo_composite_glyphs_info_t *info)
1316 {
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;
1325
1326     unsigned long max_index = 0;
1327     int width = 1;
1328     int num_elts = 0;
1329     int num_out_glyphs = 0;
1330     int num_glyphs = info->num_glyphs;
1331
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;
1337     int i;
1338
1339     op = _render_operator (op),
1340     _cairo_xlib_surface_ensure_picture (dst);
1341     for (i = 0; i < num_glyphs; i++) {
1342         int this_x, this_y;
1343         int old_width;
1344
1345         status = _cairo_scaled_glyph_lookup (info->font,
1346                                              glyphs[i].index,
1347                                              CAIRO_SCALED_GLYPH_INFO_METRICS,
1348                                              &glyph);
1349         if (unlikely (status))
1350             return status;
1351
1352         this_x = _cairo_lround (glyphs[i].d.x);
1353         this_y = _cairo_lround (glyphs[i].d.y);
1354
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))
1359                 return status;
1360         }
1361
1362         this_glyphset_info = glyph->dev_private;
1363         if (!glyphset)
1364             glyphset = this_glyphset_info;
1365
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.
1369          */
1370         old_width = width;
1371
1372         /* Update max glyph index */
1373         if (glyphs[i].index > max_index) {
1374             max_index = glyphs[i].index;
1375             if (max_index >= 65536)
1376               width = 4;
1377             else if (max_index >= 256)
1378               width = 2;
1379             if (width != old_width)
1380               request_size += (width - old_width) * num_out_glyphs;
1381         }
1382
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.
1386          *
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.
1393          *
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
1400          * fallen back).
1401          */
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))
1411                 return status;
1412
1413             glyphs += i;
1414             num_glyphs -= i;
1415             i = 0;
1416             max_index = glyphs[i].index;
1417             width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
1418             request_size = 0;
1419             num_elts = 0;
1420             num_out_glyphs = 0;
1421             x = y = 0;
1422             glyphset = this_glyphset_info;
1423         }
1424
1425         /* Convert absolute glyph position to relative-to-current-point
1426          * position */
1427         glyphs[i].i.x = this_x - x;
1428         glyphs[i].i.y = this_y - y;
1429
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.
1433          *
1434          * These same conditions are mirrored in _emit_glyphs_chunk().
1435          */
1436       if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
1437             num_elts++;
1438             request_size += _cairo_sz_xGlyphElt;
1439         }
1440
1441         /* adjust current-position */
1442         x = this_x + glyph->x_advance;
1443         y = this_y + glyph->y_advance;
1444
1445         num_out_glyphs++;
1446         request_size += width;
1447     }
1448
1449     if (num_elts) {
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);
1454     }
1455
1456     return status;
1457 }
1458
1459 const cairo_compositor_t *
1460 _cairo_xlib_mask_compositor_get (void)
1461 {
1462     static cairo_mask_compositor_t compositor;
1463
1464     if (compositor.base.delegate == NULL) {
1465         _cairo_mask_compositor_init (&compositor,
1466                                      _cairo_xlib_fallback_compositor_get ());
1467
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;
1482     }
1483
1484     return &compositor.base;
1485 }
1486
1487 #define CAIRO_FIXED_16_16_MIN -32768
1488 #define CAIRO_FIXED_16_16_MAX 32767
1489
1490 static cairo_bool_t
1491 line_exceeds_16_16 (const cairo_line_t *line)
1492 {
1493     return
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);
1502 }
1503
1504 static void
1505 project_line_x_onto_16_16 (const cairo_line_t *line,
1506                             cairo_fixed_t top,
1507                             cairo_fixed_t bottom,
1508                             XLineFixed *out)
1509 {
1510     cairo_point_double_t p1, p2;
1511     double m;
1512
1513     p1.x = _cairo_fixed_to_double (line->p1.x);
1514     p1.y = _cairo_fixed_to_double (line->p1.y);
1515
1516     p2.x = _cairo_fixed_to_double (line->p2.x);
1517     p2.y = _cairo_fixed_to_double (line->p2.y);
1518
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));
1522 }
1523 #if 0
1524 static cairo_int_status_T
1525 check_composite_trapezoids ()
1526 {
1527     operation = _categorize_composite_operation (dst, op, pattern, TRUE);
1528     if (operation == DO_UNSUPPORTED)
1529         return UNSUPPORTED ("unsupported operation");
1530
1531     operation = _recategorize_composite_operation (dst, op, src,
1532                                                    &attributes, TRUE);
1533     if (operation == DO_UNSUPPORTED) {
1534         status = UNSUPPORTED ("unsupported operation");
1535         goto BAIL;
1536     }
1537
1538 }
1539 #endif
1540
1541 static cairo_int_status_t
1542 composite_traps (void                   *abstract_dst,
1543                  cairo_operator_t       op,
1544                  cairo_surface_t        *abstract_src,
1545                  int                    src_x,
1546                  int                    src_y,
1547                  int                    dst_x,
1548                  int                    dst_y,
1549                  const cairo_rectangle_int_t *extents,
1550                  cairo_antialias_t      antialias,
1551                  cairo_traps_t          *traps)
1552 {
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;
1559     int dx, dy;
1560     int i;
1561
1562     //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1563
1564     if (dst->base.is_clear &&
1565         (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))
1566     {
1567         op = CAIRO_OPERATOR_SOURCE;
1568     }
1569
1570     pict_format =
1571         _cairo_xlib_display_get_xrender_format (display,
1572                                                 antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1573
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);
1578     }
1579
1580     dx = -dst_x << 16;
1581     dy = -dst_y << 16;
1582     for (i = 0; i < traps->num_traps; i++) {
1583         cairo_trapezoid_t *t = &traps->traps[i];
1584
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;
1588
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.
1592          */
1593         if (unlikely (line_exceeds_16_16 (&t->left))) {
1594             project_line_x_onto_16_16 (&t->left, t->top, t->bottom,
1595                                         &xtraps[i].left);
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;
1600         } else {
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;
1605         }
1606
1607         if (unlikely (line_exceeds_16_16 (&t->right))) {
1608             project_line_x_onto_16_16 (&t->right, t->top, t->bottom,
1609                                        &xtraps[i].right);
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;
1614         } else {
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;
1619         }
1620     }
1621
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);
1625     } else {
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);
1628     }
1629     src_x += dst_x;
1630     src_y += dst_y;
1631
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,
1637                                 pict_format,
1638                                 src_x, src_y,
1639                                 xtraps, traps->num_traps);
1640
1641     if (xtraps != xtraps_stack)
1642         free (xtraps);
1643
1644     return CAIRO_STATUS_SUCCESS;
1645 }
1646
1647 static cairo_int_status_t
1648 composite_tristrip (void                *abstract_dst,
1649                     cairo_operator_t    op,
1650                     cairo_surface_t     *abstract_src,
1651                     int                 src_x,
1652                     int                 src_y,
1653                     int                 dst_x,
1654                     int                 dst_y,
1655                     const cairo_rectangle_int_t *extents,
1656                     cairo_antialias_t   antialias,
1657                     cairo_tristrip_t    *strip)
1658 {
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;
1665     int dx, dy;
1666     int i;
1667
1668     //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1669
1670     pict_format =
1671         _cairo_xlib_display_get_xrender_format (display,
1672                                                 antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1673
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);
1678     }
1679
1680     dx = -dst_x << 16;
1681     dy = -dst_y << 16;
1682     for (i = 0; i < strip->num_points; i++) {
1683         cairo_point_t *p = &strip->points[i];
1684
1685         points[i].x = _cairo_fixed_to_16_16(p->x) + dx;
1686         points[i].y = _cairo_fixed_to_16_16(p->y) + dy;
1687     }
1688
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;
1691
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,
1697                               pict_format,
1698                               src_x, src_y,
1699                               points, strip->num_points);
1700
1701     if (points != points_stack)
1702         free (points);
1703
1704     return CAIRO_STATUS_SUCCESS;
1705 }
1706
1707 static cairo_int_status_t
1708 check_composite (const cairo_composite_rectangles_t *extents)
1709 {
1710     cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
1711
1712     if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
1713         return CAIRO_INT_STATUS_UNSUPPORTED;
1714
1715     return CAIRO_STATUS_SUCCESS;
1716 }
1717
1718 const cairo_compositor_t *
1719 _cairo_xlib_traps_compositor_get (void)
1720 {
1721     static cairo_traps_compositor_t compositor;
1722
1723     if (compositor.base.delegate == NULL) {
1724         _cairo_traps_compositor_init (&compositor,
1725                                       _cairo_xlib_mask_compositor_get ());
1726
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;
1745     }
1746
1747     return &compositor.base;
1748 }
1749
1750 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */