Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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-damage-private.h"
  51. #include "cairo-image-surface-private.h"
  52. #include "cairo-list-inline.h"
  53. #include "cairo-pattern-private.h"
  54. #include "cairo-pixman-private.h"
  55. #include "cairo-traps-private.h"
  56. #include "cairo-tristrip-private.h"
  57.  
  58. static cairo_int_status_t
  59. check_composite (const cairo_composite_rectangles_t *extents)
  60. {
  61.     cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
  62.  
  63.     if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
  64.         return CAIRO_INT_STATUS_UNSUPPORTED;
  65.  
  66.     return CAIRO_STATUS_SUCCESS;
  67. }
  68.  
  69. static cairo_int_status_t
  70. acquire (void *abstract_dst)
  71. {
  72.     cairo_xlib_surface_t *dst = abstract_dst;
  73.     cairo_int_status_t status;
  74.  
  75.     status = _cairo_xlib_display_acquire (dst->base.device, &dst->display);
  76.     if (unlikely (status))
  77.         return status;
  78.  
  79.     dst->dpy = dst->display->display;
  80.     return CAIRO_STATUS_SUCCESS;
  81. }
  82.  
  83. static cairo_int_status_t
  84. release (void *abstract_dst)
  85. {
  86.     cairo_xlib_surface_t *dst = abstract_dst;
  87.  
  88.     cairo_device_release (&dst->display->base);
  89.     dst->dpy = NULL;
  90.  
  91.     return CAIRO_STATUS_SUCCESS;
  92. }
  93.  
  94. static cairo_int_status_t
  95. set_clip_region (void *_surface,
  96.                  cairo_region_t *region)
  97. {
  98.     cairo_xlib_surface_t *surface = _surface;
  99.  
  100.     _cairo_xlib_surface_ensure_picture (surface);
  101.  
  102.     if (region != NULL) {
  103.         XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
  104.         XRectangle *rects = stack_rects;
  105.         int n_rects, i;
  106.  
  107.         n_rects = cairo_region_num_rectangles (region);
  108.         if (n_rects > ARRAY_LENGTH (stack_rects)) {
  109.             rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
  110.             if (unlikely (rects == NULL))
  111.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  112.         }
  113.         for (i = 0; i < n_rects; i++) {
  114.             cairo_rectangle_int_t rect;
  115.  
  116.             cairo_region_get_rectangle (region, i, &rect);
  117.  
  118.             rects[i].x = rect.x;
  119.             rects[i].y = rect.y;
  120.             rects[i].width  = rect.width;
  121.             rects[i].height = rect.height;
  122.         }
  123.         XRenderSetPictureClipRectangles (surface->dpy,
  124.                                          surface->picture,
  125.                                          0, 0,
  126.                                          rects, n_rects);
  127.         if (rects != stack_rects)
  128.             free (rects);
  129.     } else {
  130.         XRenderPictureAttributes pa;
  131.         pa.clip_mask = None;
  132.         XRenderChangePicture (surface->dpy,
  133.                               surface->picture,
  134.                               CPClipMask, &pa);
  135.     }
  136.  
  137.     return CAIRO_STATUS_SUCCESS;
  138. }
  139.  
  140. static cairo_int_status_t
  141. copy_image_boxes (void *_dst,
  142.                   cairo_image_surface_t *image,
  143.                   cairo_boxes_t *boxes,
  144.                   int dx, int dy)
  145. {
  146.     cairo_xlib_surface_t *dst = _dst;
  147.     struct _cairo_boxes_chunk *chunk;
  148.     cairo_int_status_t status;
  149.     Pixmap src;
  150.     GC gc;
  151.     int i, j;
  152.  
  153.     assert (image->depth == dst->depth);
  154.  
  155.     status = acquire (dst);
  156.     if (unlikely (status))
  157.         return status;
  158.  
  159.     status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
  160.     if (unlikely (status)) {
  161.         release (dst);
  162.         return status;
  163.     }
  164.  
  165.     src = _cairo_xlib_shm_surface_get_pixmap (&image->base);
  166.     if (boxes->num_boxes == 1) {
  167.         int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
  168.         int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
  169.         int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
  170.         int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
  171.  
  172.         _cairo_xlib_shm_surface_mark_active (&image->base);
  173.         XCopyArea (dst->dpy, src, dst->drawable, gc,
  174.                    x1 + dx, y1 + dy,
  175.                    x2 - x1, y2 - y1,
  176.                    x1,      y1);
  177.     } else {
  178.         XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
  179.         XRectangle *rects = stack_rects;
  180.  
  181.         if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
  182.             rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
  183.             if (unlikely (rects == NULL))
  184.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  185.         }
  186.  
  187.         j = 0;
  188.         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  189.             for (i = 0; i < chunk->count; i++) {
  190.                 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  191.                 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  192.                 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  193.                 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  194.  
  195.                 if (x2 > x1 && y2 > y1) {
  196.                     rects[j].x = x1;
  197.                     rects[j].y = y1;
  198.                     rects[j].width  = x2 - x1;
  199.                     rects[j].height = y2 - y1;
  200.                     j++;
  201.                 }
  202.             }
  203.         }
  204.  
  205.         XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
  206.         _cairo_xlib_shm_surface_mark_active (&image->base);
  207.         XCopyArea (dst->dpy, src, dst->drawable, gc,
  208.                    0, 0, image->width, image->height, -dx, -dy);
  209.         XSetClipMask (dst->dpy, gc, None);
  210.  
  211.         if (rects != stack_rects)
  212.             free (rects);
  213.     }
  214.  
  215.     _cairo_xlib_surface_put_gc (dst->display, dst, gc);
  216.     release (dst);
  217.     return CAIRO_STATUS_SUCCESS;
  218. }
  219.  
  220. static cairo_bool_t
  221. boxes_cover_surface (cairo_boxes_t *boxes,
  222.                      cairo_xlib_surface_t *surface)
  223. {
  224.     cairo_box_t *b;
  225.  
  226.     if (boxes->num_boxes != 1)
  227.             return FALSE;
  228.  
  229.     b = &boxes->chunks.base[0];
  230.  
  231.     if (_cairo_fixed_integer_part (b->p1.x) > 0 ||
  232.         _cairo_fixed_integer_part (b->p1.y) > 0)
  233.         return FALSE;
  234.  
  235.     if (_cairo_fixed_integer_part (b->p2.x) < surface->width ||
  236.         _cairo_fixed_integer_part (b->p2.y) < surface->height)
  237.         return FALSE;
  238.  
  239.     return TRUE;
  240. }
  241.  
  242. static cairo_int_status_t
  243. draw_image_boxes (void *_dst,
  244.                   cairo_image_surface_t *image,
  245.                   cairo_boxes_t *boxes,
  246.                   int dx, int dy)
  247. {
  248.     cairo_xlib_surface_t *dst = _dst;
  249.     struct _cairo_boxes_chunk *chunk;
  250.     cairo_image_surface_t *shm = NULL;
  251.     cairo_int_status_t status;
  252.     int i;
  253.  
  254.     if (image->base.device == dst->base.device) {
  255.         if (image->depth != dst->depth)
  256.             return CAIRO_INT_STATUS_UNSUPPORTED;
  257.  
  258.         if (_cairo_xlib_shm_surface_get_pixmap (&image->base))
  259.             return copy_image_boxes (dst, image, boxes, dx, dy);
  260.  
  261.         goto draw_image_boxes;
  262.     }
  263.  
  264.     if (boxes_cover_surface (boxes, dst))
  265.         shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst, TRUE);
  266.     if (shm) {
  267.         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  268.             for (i = 0; i < chunk->count; i++) {
  269.                 cairo_box_t *b = &chunk->base[i];
  270.                 cairo_rectangle_int_t r;
  271.  
  272.                 r.x = _cairo_fixed_integer_part (b->p1.x);
  273.                 r.y = _cairo_fixed_integer_part (b->p1.y);
  274.                 r.width = _cairo_fixed_integer_part (b->p2.x) - r.x;
  275.                 r.height = _cairo_fixed_integer_part (b->p2.y) - r.y;
  276.  
  277.                 if (shm->pixman_format != image->pixman_format ||
  278.                     ! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data,
  279.                                   image->stride / sizeof (uint32_t),
  280.                                   shm->stride / sizeof (uint32_t),
  281.                                   PIXMAN_FORMAT_BPP (image->pixman_format),
  282.                                   PIXMAN_FORMAT_BPP (shm->pixman_format),
  283.                                   r.x + dx, r.y + dy,
  284.                                   r.x, r.y,
  285.                                   r.width, r.height))
  286.                 {
  287.                     pixman_image_composite32 (PIXMAN_OP_SRC,
  288.                                               image->pixman_image, NULL, shm->pixman_image,
  289.                                               r.x + dx, r.y + dy,
  290.                                               0, 0,
  291.                                               r.x, r.y,
  292.                                               r.width, r.height);
  293.                 }
  294.  
  295.                 shm->base.damage =
  296.                     _cairo_damage_add_rectangle (shm->base.damage, &r);
  297.             }
  298.         }
  299.         dst->base.is_clear = FALSE;
  300.         dst->fallback++;
  301.         dst->base.serial++;
  302.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  303.     }
  304.  
  305.     if (image->depth == dst->depth &&
  306.         ((cairo_xlib_display_t *)dst->display)->shm) {
  307.         cairo_box_t extents;
  308.         cairo_rectangle_int_t r;
  309.  
  310.         _cairo_boxes_extents (boxes, &extents);
  311.         _cairo_box_round_to_rectangle (&extents, &r);
  312.  
  313.         shm = (cairo_image_surface_t *)
  314.             _cairo_xlib_surface_create_shm (dst, image->pixman_format,
  315.                                             r.width, r.height);
  316.         if (shm) {
  317.             int tx = -r.x, ty = -r.y;
  318.  
  319.             assert (shm->pixman_format == image->pixman_format);
  320.             for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  321.                 for (i = 0; i < chunk->count; i++) {
  322.                     cairo_box_t *b = &chunk->base[i];
  323.  
  324.                     r.x = _cairo_fixed_integer_part (b->p1.x);
  325.                     r.y = _cairo_fixed_integer_part (b->p1.y);
  326.                     r.width  = _cairo_fixed_integer_part (b->p2.x) - r.x;
  327.                     r.height = _cairo_fixed_integer_part (b->p2.y) - r.y;
  328.  
  329.                     if (! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data,
  330.                                       image->stride / sizeof (uint32_t),
  331.                                       shm->stride / sizeof (uint32_t),
  332.                                       PIXMAN_FORMAT_BPP (image->pixman_format),
  333.                                       PIXMAN_FORMAT_BPP (shm->pixman_format),
  334.                                       r.x + dx, r.y + dy,
  335.                                       r.x + tx, r.y + ty,
  336.                                       r.width, r.height))
  337.                     {
  338.                         pixman_image_composite32 (PIXMAN_OP_SRC,
  339.                                                   image->pixman_image, NULL, shm->pixman_image,
  340.                                                   r.x + dx, r.y + dy,
  341.                                                   0, 0,
  342.                                                   r.x + tx, r.y + ty,
  343.                                                   r.width, r.height);
  344.                     }
  345.                 }
  346.             }
  347.  
  348.             dx = tx;
  349.             dy = ty;
  350.             image = shm;
  351.  
  352.             if (_cairo_xlib_shm_surface_get_pixmap (&image->base)) {
  353.                 status = copy_image_boxes (dst, image, boxes, dx, dy);
  354.                 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  355.                     goto out;
  356.             }
  357.         }
  358.     }
  359.  
  360. draw_image_boxes:
  361.     status = CAIRO_STATUS_SUCCESS;
  362.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  363.         for (i = 0; i < chunk->count; i++) {
  364.             cairo_box_t *b = &chunk->base[i];
  365.             int x1 = _cairo_fixed_integer_part (b->p1.x);
  366.             int y1 = _cairo_fixed_integer_part (b->p1.y);
  367.             int x2 = _cairo_fixed_integer_part (b->p2.x);
  368.             int y2 = _cairo_fixed_integer_part (b->p2.y);
  369.             if (_cairo_xlib_surface_draw_image (dst, image,
  370.                                                 x1 + dx, y1 + dy,
  371.                                                 x2 - x1, y2 - y1,
  372.                                                 x1, y1)) {
  373.                 status = CAIRO_INT_STATUS_UNSUPPORTED;
  374.                 goto out;
  375.             }
  376.         }
  377.     }
  378.  
  379. out:
  380.     cairo_surface_destroy (&shm->base);
  381.     return status;
  382. }
  383.  
  384. static cairo_int_status_t
  385. copy_boxes (void *_dst,
  386.             cairo_surface_t *_src,
  387.             cairo_boxes_t *boxes,
  388.             const cairo_rectangle_int_t *extents,
  389.             int dx, int dy)
  390. {
  391.     cairo_xlib_surface_t *dst = _dst;
  392.     cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)_src;
  393.     struct _cairo_boxes_chunk *chunk;
  394.     cairo_int_status_t status;
  395.     GC gc;
  396.     Drawable d;
  397.     int i, j;
  398.  
  399.     if (! _cairo_xlib_surface_same_screen  (dst, src))
  400.         return CAIRO_INT_STATUS_UNSUPPORTED;
  401.  
  402.     if (dst->depth != src->depth)
  403.         return CAIRO_INT_STATUS_UNSUPPORTED;
  404.  
  405.     status = acquire (dst);
  406.     if (unlikely (status))
  407.         return status;
  408.  
  409.     status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
  410.     if (unlikely (status)) {
  411.         release (dst);
  412.         return status;
  413.     }
  414.  
  415.     if (src->fallback && src->shm->damage->dirty) {
  416.         assert (src != dst);
  417.         d = _cairo_xlib_shm_surface_get_pixmap (src->shm);
  418.         assert (d != 0);
  419.     } else {
  420.         if (! src->owns_pixmap) {
  421.             XGCValues gcv;
  422.  
  423.             gcv.subwindow_mode = IncludeInferiors;
  424.             XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
  425.         }
  426.         d = src->drawable;
  427.     }
  428.  
  429.     if (boxes->num_boxes == 1) {
  430.         int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
  431.         int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
  432.         int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
  433.         int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
  434.  
  435.         XCopyArea (dst->dpy, d, dst->drawable, gc,
  436.                    x1 + dx, y1 + dy,
  437.                    x2 - x1, y2 - y1,
  438.                    x1,      y1);
  439.     } else {
  440.         /* We can only have a single control for subwindow_mode on the
  441.          * GC. If we have a Window destination, we need to set ClipByChildren,
  442.          * but if we have a Window source, we need IncludeInferiors. If we have
  443.          * both a Window destination and source, we must fallback. There is
  444.          * no convenient way to detect if a drawable is a Pixmap or Window,
  445.          * therefore we can only rely on those surfaces that we created
  446.          * ourselves to be Pixmaps, and treat everything else as a potential
  447.          * Window.
  448.          */
  449.         if (src == dst || (!src->owns_pixmap && !dst->owns_pixmap)) {
  450.             for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  451.                 for (i = 0; i < chunk->count; i++) {
  452.                     int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  453.                     int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  454.                     int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  455.                     int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  456.                     XCopyArea (dst->dpy, d, dst->drawable, gc,
  457.                                x1 + dx, y1 + dy,
  458.                                x2 - x1, y2 - y1,
  459.                                x1,      y1);
  460.                 }
  461.             }
  462.         } else {
  463.             XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
  464.             XRectangle *rects = stack_rects;
  465.  
  466.             if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
  467.                 rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
  468.                 if (unlikely (rects == NULL))
  469.                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  470.             }
  471.  
  472.             j = 0;
  473.             for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  474.                 for (i = 0; i < chunk->count; i++) {
  475.                     int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  476.                     int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  477.                     int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  478.                     int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  479.  
  480.                     rects[j].x = x1;
  481.                     rects[j].y = y1;
  482.                     rects[j].width  = x2 - x1;
  483.                     rects[j].height = y2 - y1;
  484.                     j++;
  485.                 }
  486.             }
  487.             assert (j == boxes->num_boxes);
  488.  
  489.             XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
  490.  
  491.             XCopyArea (dst->dpy, d, dst->drawable, gc,
  492.                        extents->x + dx, extents->y + dy,
  493.                        extents->width,  extents->height,
  494.                        extents->x,      extents->y);
  495.  
  496.             XSetClipMask (dst->dpy, gc, None);
  497.  
  498.             if (rects != stack_rects)
  499.                 free (rects);
  500.         }
  501.     }
  502.  
  503.     if (src->fallback && src->shm->damage->dirty) {
  504.         _cairo_xlib_shm_surface_mark_active (src->shm);
  505.     } else if (! src->owns_pixmap) {
  506.         XGCValues gcv;
  507.  
  508.         gcv.subwindow_mode = ClipByChildren;
  509.         XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
  510.     }
  511.  
  512.     _cairo_xlib_surface_put_gc (dst->display, dst, gc);
  513.     release (dst);
  514.     return CAIRO_STATUS_SUCCESS;
  515. }
  516.  
  517. static int
  518. _render_operator (cairo_operator_t op)
  519. {
  520.     switch (op) {
  521.     case CAIRO_OPERATOR_CLEAR:
  522.         return PictOpClear;
  523.  
  524.     case CAIRO_OPERATOR_SOURCE:
  525.         return PictOpSrc;
  526.     case CAIRO_OPERATOR_OVER:
  527.         return PictOpOver;
  528.     case CAIRO_OPERATOR_IN:
  529.         return PictOpIn;
  530.     case CAIRO_OPERATOR_OUT:
  531.         return PictOpOut;
  532.     case CAIRO_OPERATOR_ATOP:
  533.         return PictOpAtop;
  534.  
  535.     case CAIRO_OPERATOR_DEST:
  536.         return PictOpDst;
  537.     case CAIRO_OPERATOR_DEST_OVER:
  538.         return PictOpOverReverse;
  539.     case CAIRO_OPERATOR_DEST_IN:
  540.         return PictOpInReverse;
  541.     case CAIRO_OPERATOR_DEST_OUT:
  542.         return PictOpOutReverse;
  543.     case CAIRO_OPERATOR_DEST_ATOP:
  544.         return PictOpAtopReverse;
  545.  
  546.     case CAIRO_OPERATOR_XOR:
  547.         return PictOpXor;
  548.     case CAIRO_OPERATOR_ADD:
  549.         return PictOpAdd;
  550.     case CAIRO_OPERATOR_SATURATE:
  551.         return PictOpSaturate;
  552.  
  553.     case CAIRO_OPERATOR_MULTIPLY:
  554.         return PictOpMultiply;
  555.     case CAIRO_OPERATOR_SCREEN:
  556.         return PictOpScreen;
  557.     case CAIRO_OPERATOR_OVERLAY:
  558.         return PictOpOverlay;
  559.     case CAIRO_OPERATOR_DARKEN:
  560.         return PictOpDarken;
  561.     case CAIRO_OPERATOR_LIGHTEN:
  562.         return PictOpLighten;
  563.     case CAIRO_OPERATOR_COLOR_DODGE:
  564.         return PictOpColorDodge;
  565.     case CAIRO_OPERATOR_COLOR_BURN:
  566.         return PictOpColorBurn;
  567.     case CAIRO_OPERATOR_HARD_LIGHT:
  568.         return PictOpHardLight;
  569.     case CAIRO_OPERATOR_SOFT_LIGHT:
  570.         return PictOpSoftLight;
  571.     case CAIRO_OPERATOR_DIFFERENCE:
  572.         return PictOpDifference;
  573.     case CAIRO_OPERATOR_EXCLUSION:
  574.         return PictOpExclusion;
  575.     case CAIRO_OPERATOR_HSL_HUE:
  576.         return PictOpHSLHue;
  577.     case CAIRO_OPERATOR_HSL_SATURATION:
  578.         return PictOpHSLSaturation;
  579.     case CAIRO_OPERATOR_HSL_COLOR:
  580.         return PictOpHSLColor;
  581.     case CAIRO_OPERATOR_HSL_LUMINOSITY:
  582.         return PictOpHSLLuminosity;
  583.  
  584.     default:
  585.         ASSERT_NOT_REACHED;
  586.         return PictOpOver;
  587.     }
  588. }
  589.  
  590. static cairo_bool_t
  591. fill_reduces_to_source (cairo_operator_t op,
  592.                         const cairo_color_t *color,
  593.                         cairo_xlib_surface_t *dst)
  594. {
  595.     if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color)) {
  596.         if (op == CAIRO_OPERATOR_OVER)
  597.             return TRUE;
  598.         if (op == CAIRO_OPERATOR_ADD)
  599.             return (dst->base.content & CAIRO_CONTENT_COLOR) == 0;
  600.     }
  601.  
  602.     return FALSE;
  603. }
  604.  
  605. static cairo_int_status_t
  606. fill_rectangles (void                           *abstract_surface,
  607.                  cairo_operator_t                op,
  608.                  const cairo_color_t            *color,
  609.                  cairo_rectangle_int_t          *rects,
  610.                  int                             num_rects)
  611. {
  612.     cairo_xlib_surface_t *dst = abstract_surface;
  613.     XRenderColor render_color;
  614.     int i;
  615.  
  616.     //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
  617.  
  618.     if (fill_reduces_to_source (op, color, dst))
  619.         op = CAIRO_OPERATOR_SOURCE;
  620.  
  621.     if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
  622.         cairo_int_status_t status;
  623.  
  624.         status = CAIRO_INT_STATUS_UNSUPPORTED;
  625.         if (op == CAIRO_OPERATOR_SOURCE)
  626.             status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects);
  627.         return status;
  628.     }
  629.  
  630.     render_color.red   = color->red_short;
  631.     render_color.green = color->green_short;
  632.     render_color.blue  = color->blue_short;
  633.     render_color.alpha = color->alpha_short;
  634.  
  635.     _cairo_xlib_surface_ensure_picture (dst);
  636.     if (num_rects == 1) {
  637.         /* Take advantage of the protocol compaction that libXrender performs
  638.          * to amalgamate sequences of XRenderFillRectangle().
  639.          */
  640.         XRenderFillRectangle (dst->dpy,
  641.                               _render_operator (op),
  642.                               dst->picture,
  643.                               &render_color,
  644.                               rects->x, rects->y,
  645.                               rects->width, rects->height);
  646.     } else {
  647.         XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
  648.         XRectangle *xrects = stack_xrects;
  649.  
  650.         if (num_rects > ARRAY_LENGTH (stack_xrects)) {
  651.             xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
  652.             if (unlikely (xrects == NULL))
  653.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  654.         }
  655.  
  656.         for (i = 0; i < num_rects; i++) {
  657.             xrects[i].x = rects[i].x;
  658.             xrects[i].y = rects[i].y;
  659.             xrects[i].width  = rects[i].width;
  660.             xrects[i].height = rects[i].height;
  661.         }
  662.  
  663.         XRenderFillRectangles (dst->dpy,
  664.                                _render_operator (op),
  665.                                dst->picture,
  666.                                &render_color, xrects, num_rects);
  667.  
  668.         if (xrects != stack_xrects)
  669.             free (xrects);
  670.     }
  671.  
  672.     return CAIRO_STATUS_SUCCESS;
  673. }
  674.  
  675. static cairo_int_status_t
  676. fill_boxes (void                *abstract_surface,
  677.             cairo_operator_t     op,
  678.             const cairo_color_t *color,
  679.             cairo_boxes_t       *boxes)
  680. {
  681.     cairo_xlib_surface_t *dst = abstract_surface;
  682.     XRenderColor render_color;
  683.  
  684.     if (fill_reduces_to_source (op, color, dst))
  685.         op = CAIRO_OPERATOR_SOURCE;
  686.  
  687.     if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
  688.         cairo_int_status_t status;
  689.  
  690.         status = CAIRO_INT_STATUS_UNSUPPORTED;
  691.         if (op == CAIRO_OPERATOR_SOURCE)
  692.             status = _cairo_xlib_core_fill_boxes (dst, color, boxes);
  693.         return status;
  694.     }
  695.  
  696.     render_color.red   = color->red_short;
  697.     render_color.green = color->green_short;
  698.     render_color.blue  = color->blue_short;
  699.     render_color.alpha = color->alpha_short;
  700.  
  701.     _cairo_xlib_surface_ensure_picture (dst);
  702.     if (boxes->num_boxes == 1) {
  703.         int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
  704.         int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
  705.         int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
  706.         int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
  707.  
  708.         /* Take advantage of the protocol compaction that libXrender performs
  709.          * to amalgamate sequences of XRenderFillRectangle().
  710.          */
  711.         XRenderFillRectangle (dst->dpy,
  712.                               _render_operator (op),
  713.                               dst->picture,
  714.                               &render_color,
  715.                               x1, y1,
  716.                               x2 - x1, y2 - y1);
  717.     } else {
  718.         XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
  719.         XRectangle *xrects = stack_xrects;
  720.         struct _cairo_boxes_chunk *chunk;
  721.         int i, j;
  722.  
  723.         if (boxes->num_boxes > ARRAY_LENGTH (stack_xrects)) {
  724.             xrects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
  725.             if (unlikely (xrects == NULL))
  726.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  727.         }
  728.  
  729.         j = 0;
  730.         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  731.             for (i = 0; i < chunk->count; i++) {
  732.                 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  733.                 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  734.                 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  735.                 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  736.  
  737.                 xrects[j].x = x1;
  738.                 xrects[j].y = y1;
  739.                 xrects[j].width  = x2 - x1;
  740.                 xrects[j].height = y2 - y1;
  741.                 j++;
  742.             }
  743.         }
  744.  
  745.         XRenderFillRectangles (dst->dpy,
  746.                                _render_operator (op),
  747.                                dst->picture,
  748.                                &render_color, xrects, j);
  749.  
  750.         if (xrects != stack_xrects)
  751.             free (xrects);
  752.     }
  753.  
  754.     return CAIRO_STATUS_SUCCESS;
  755. }
  756.  
  757. #if 0
  758. check_composite ()
  759.     operation = _categorize_composite_operation (dst, op, src_pattern,
  760.                                                  mask_pattern != NULL);
  761.     if (operation == DO_UNSUPPORTED)
  762.         return UNSUPPORTED ("unsupported operation");
  763.  
  764.     //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
  765.  
  766.     operation = _recategorize_composite_operation (dst, op, src, &src_attr,
  767.                                                    mask_pattern != NULL);
  768.     if (operation == DO_UNSUPPORTED) {
  769.         status = UNSUPPORTED ("unsupported operation");
  770.         goto BAIL;
  771.     }
  772. #endif
  773.  
  774. static cairo_int_status_t
  775. composite (void *abstract_dst,
  776.            cairo_operator_t     op,
  777.            cairo_surface_t      *abstract_src,
  778.            cairo_surface_t      *abstract_mask,
  779.            int                  src_x,
  780.            int                  src_y,
  781.            int                  mask_x,
  782.            int                  mask_y,
  783.            int                  dst_x,
  784.            int                  dst_y,
  785.            unsigned int         width,
  786.            unsigned int         height)
  787. {
  788.     cairo_xlib_surface_t *dst = abstract_dst;
  789.     cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
  790.  
  791.     op = _render_operator (op);
  792.  
  793.     _cairo_xlib_surface_ensure_picture (dst);
  794.     if (abstract_mask) {
  795.         cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
  796.  
  797.         XRenderComposite (dst->dpy, op,
  798.                           src->picture, mask->picture, dst->picture,
  799.                           src_x,  src_y,
  800.                           mask_x, mask_y,
  801.                           dst_x,  dst_y,
  802.                           width,  height);
  803.     } else {
  804.         XRenderComposite (dst->dpy, op,
  805.                           src->picture, 0, dst->picture,
  806.                           src_x, src_y,
  807.                           0, 0,
  808.                           dst_x, dst_y,
  809.                           width, height);
  810.     }
  811.  
  812.     return CAIRO_STATUS_SUCCESS;
  813. }
  814.  
  815. static cairo_int_status_t
  816. lerp (void *abstract_dst,
  817.       cairo_surface_t   *abstract_src,
  818.       cairo_surface_t   *abstract_mask,
  819.       int                       src_x,
  820.       int                       src_y,
  821.       int                       mask_x,
  822.       int                       mask_y,
  823.       int                       dst_x,
  824.       int                       dst_y,
  825.       unsigned int              width,
  826.       unsigned int              height)
  827. {
  828.     cairo_xlib_surface_t *dst = abstract_dst;
  829.     cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
  830.     cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
  831.  
  832.     _cairo_xlib_surface_ensure_picture (dst);
  833.     XRenderComposite (dst->dpy, PictOpOutReverse,
  834.                       mask->picture, None, dst->picture,
  835.                       mask_x, mask_y,
  836.                       0,      0,
  837.                       dst_x,  dst_y,
  838.                       width,  height);
  839.     XRenderComposite (dst->dpy, PictOpAdd,
  840.                       src->picture, mask->picture, dst->picture,
  841.                       src_x,  src_y,
  842.                       mask_x, mask_y,
  843.                       dst_x,  dst_y,
  844.                       width,  height);
  845.  
  846.     return CAIRO_STATUS_SUCCESS;
  847. }
  848.  
  849. static cairo_int_status_t
  850. composite_boxes (void                   *abstract_dst,
  851.                  cairo_operator_t        op,
  852.                  cairo_surface_t        *abstract_src,
  853.                  cairo_surface_t        *abstract_mask,
  854.                  int                    src_x,
  855.                  int                    src_y,
  856.                  int                    mask_x,
  857.                  int                    mask_y,
  858.                  int                    dst_x,
  859.                  int                    dst_y,
  860.                  cairo_boxes_t          *boxes,
  861.                  const cairo_rectangle_int_t  *extents)
  862. {
  863.     cairo_xlib_surface_t *dst = abstract_dst;
  864.     Picture src = ((cairo_xlib_source_t *)abstract_src)->picture;
  865.     Picture mask = abstract_mask ? ((cairo_xlib_source_t *)abstract_mask)->picture : 0;
  866.     XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
  867.     XRectangle *rects = stack_rects;
  868.     struct _cairo_boxes_chunk *chunk;
  869.     int i, j;
  870.  
  871.     op = _render_operator (op);
  872.     _cairo_xlib_surface_ensure_picture (dst);
  873.     if (boxes->num_boxes == 1) {
  874.         int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
  875.         int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
  876.         int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
  877.         int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
  878.  
  879.         XRenderComposite (dst->dpy, op,
  880.                           src, mask, dst->picture,
  881.                           x1 + src_x,   y1 + src_y,
  882.                           x1 + mask_x,  y1 + mask_y,
  883.                           x1 - dst_x,   y1 - dst_y,
  884.                           x2 - x1,      y2 - y1);
  885.         return CAIRO_STATUS_SUCCESS;
  886.     }
  887.  
  888.     if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
  889.         rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
  890.         if (unlikely (rects == NULL))
  891.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  892.     }
  893.  
  894.     j = 0;
  895.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  896.         for (i = 0; i < chunk->count; i++) {
  897.             int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  898.             int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  899.             int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  900.             int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  901.  
  902.             rects[j].x = x1 - dst_x;
  903.             rects[j].y = y1 - dst_y;
  904.             rects[j].width  = x2 - x1;
  905.             rects[j].height = y2 - y1;
  906.             j++;
  907.         }
  908.     }
  909.     assert (j == boxes->num_boxes);
  910.  
  911.     XRenderSetPictureClipRectangles (dst->dpy,
  912.                                      dst->picture,
  913.                                      0, 0,
  914.                                      rects, j);
  915.     if (rects != stack_rects)
  916.         free (rects);
  917.  
  918.     XRenderComposite (dst->dpy, op,
  919.                       src, mask, dst->picture,
  920.                       extents->x + src_x,  extents->y + src_y,
  921.                       extents->x + mask_x, extents->y + mask_y,
  922.                       extents->x - dst_x,  extents->y - dst_y,
  923.                       extents->width,      extents->height);
  924.  
  925.     set_clip_region (dst, NULL);
  926.  
  927.     return CAIRO_STATUS_SUCCESS;
  928. }
  929.  
  930. /* font rendering */
  931.  
  932. void
  933. _cairo_xlib_font_close (cairo_xlib_font_t *priv)
  934. {
  935.     cairo_xlib_display_t *display = (cairo_xlib_display_t *)priv->base.key;
  936.     int i;
  937.  
  938.     /* XXX All I really want is to do is zap my glyphs... */
  939.     _cairo_scaled_font_reset_cache (priv->font);
  940.  
  941.     for (i = 0; i < NUM_GLYPHSETS; i++) {
  942.         cairo_xlib_font_glyphset_t *info;
  943.  
  944.         info = &priv->glyphset[i];
  945.         if (info->glyphset)
  946.             XRenderFreeGlyphSet (display->display, info->glyphset);
  947.     }
  948.  
  949.     /* XXX locking */
  950.     cairo_list_del (&priv->link);
  951.     cairo_list_del (&priv->base.link);
  952.     free (priv);
  953. }
  954.  
  955. static void
  956. _cairo_xlib_font_fini (cairo_scaled_font_private_t *abstract_private,
  957.                        cairo_scaled_font_t *font)
  958. {
  959.     cairo_xlib_font_t *priv = (cairo_xlib_font_t *) abstract_private;
  960.     cairo_status_t status;
  961.     cairo_xlib_display_t *display;
  962.     int i;
  963.  
  964.     cairo_list_del (&priv->base.link);
  965.     cairo_list_del (&priv->link);
  966.  
  967.     status = _cairo_xlib_display_acquire (priv->device, &display);
  968.     if (status)
  969.         goto BAIL;
  970.  
  971.     for (i = 0; i < NUM_GLYPHSETS; i++) {
  972.         cairo_xlib_font_glyphset_t *info;
  973.  
  974.         info = &priv->glyphset[i];
  975.         if (info->glyphset)
  976.             XRenderFreeGlyphSet (display->display, info->glyphset);
  977.     }
  978.  
  979.     cairo_device_release (&display->base);
  980. BAIL:
  981.     cairo_device_destroy (&display->base);
  982.     free (priv);
  983. }
  984.  
  985. static cairo_xlib_font_t *
  986. _cairo_xlib_font_create (cairo_xlib_display_t *display,
  987.                          cairo_scaled_font_t  *font)
  988. {
  989.     cairo_xlib_font_t *priv;
  990.     int i;
  991.  
  992.     priv = malloc (sizeof (cairo_xlib_font_t));
  993.     if (unlikely (priv == NULL))
  994.         return NULL;
  995.  
  996.     _cairo_scaled_font_attach_private (font, &priv->base, display,
  997.                                        _cairo_xlib_font_fini);
  998.  
  999.     priv->device = cairo_device_reference (&display->base);
  1000.     priv->font = font;
  1001.     cairo_list_add (&priv->link, &display->fonts);
  1002.  
  1003.     for (i = 0; i < NUM_GLYPHSETS; i++) {
  1004.         cairo_xlib_font_glyphset_t *info = &priv->glyphset[i];
  1005.         switch (i) {
  1006.         case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
  1007.         case GLYPHSET_INDEX_A8:     info->format = CAIRO_FORMAT_A8;     break;
  1008.         case GLYPHSET_INDEX_A1:     info->format = CAIRO_FORMAT_A1;     break;
  1009.         default:                    ASSERT_NOT_REACHED;                          break;
  1010.         }
  1011.         info->xrender_format = NULL;
  1012.         info->glyphset = None;
  1013.         info->to_free.count = 0;
  1014.     }
  1015.  
  1016.     return priv;
  1017. }
  1018.  
  1019. static int
  1020. _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
  1021. {
  1022.     if (format == CAIRO_FORMAT_A8)
  1023.         return GLYPHSET_INDEX_A8;
  1024.     if (format == CAIRO_FORMAT_A1)
  1025.         return GLYPHSET_INDEX_A1;
  1026.  
  1027.     assert (format == CAIRO_FORMAT_ARGB32);
  1028.     return GLYPHSET_INDEX_ARGB32;
  1029. }
  1030.  
  1031. static inline cairo_xlib_font_t *
  1032. _cairo_xlib_font_get (const cairo_xlib_display_t *display,
  1033.                       cairo_scaled_font_t *font)
  1034. {
  1035.     return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display);
  1036. }
  1037.  
  1038. typedef struct {
  1039.     cairo_scaled_glyph_private_t base;
  1040.  
  1041.  
  1042.     cairo_xlib_font_glyphset_t *glyphset;
  1043. } cairo_xlib_glyph_private_t;
  1044.  
  1045. static void
  1046. _cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
  1047.                         cairo_scaled_glyph_t *glyph,
  1048.                         cairo_scaled_font_t  *font)
  1049. {
  1050.     cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private;
  1051.  
  1052.     if (! font->finished) {
  1053.         cairo_xlib_font_t *font_private;
  1054.         struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
  1055.         cairo_xlib_font_glyphset_t *info;
  1056.  
  1057.         font_private = _cairo_xlib_font_get (glyph_private->key, font);
  1058.         assert (font_private);
  1059.  
  1060.         info = priv->glyphset;
  1061.         to_free = &info->to_free;
  1062.         if (to_free->count == ARRAY_LENGTH (to_free->indices)) {
  1063.             cairo_xlib_display_t *display;
  1064.  
  1065.             if (_cairo_xlib_display_acquire (font_private->device,
  1066.                                              &display) == CAIRO_STATUS_SUCCESS) {
  1067.                 XRenderFreeGlyphs (display->display,
  1068.                                    info->glyphset,
  1069.                                    to_free->indices,
  1070.                                    to_free->count);
  1071.                 cairo_device_release (&display->base);
  1072.             }
  1073.  
  1074.             to_free->count = 0;
  1075.         }
  1076.  
  1077.         to_free->indices[to_free->count++] =
  1078.             _cairo_scaled_glyph_index (glyph);
  1079.     }
  1080.  
  1081.     cairo_list_del (&glyph_private->link);
  1082.     free (glyph_private);
  1083. }
  1084.  
  1085. static cairo_status_t
  1086. _cairo_xlib_glyph_attach (cairo_xlib_display_t  *display,
  1087.                           cairo_scaled_glyph_t  *glyph,
  1088.                           cairo_xlib_font_glyphset_t *info)
  1089. {
  1090.     cairo_xlib_glyph_private_t *priv;
  1091.  
  1092.     priv = malloc (sizeof (*priv));
  1093.     if (unlikely (priv == NULL))
  1094.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1095.  
  1096.     _cairo_scaled_glyph_attach_private (glyph, &priv->base, display,
  1097.                                         _cairo_xlib_glyph_fini);
  1098.     priv->glyphset = info;
  1099.  
  1100.     glyph->dev_private = info;
  1101.     glyph->dev_private_key = display;
  1102.     return CAIRO_STATUS_SUCCESS;
  1103. }
  1104.  
  1105. static cairo_xlib_font_glyphset_t *
  1106. _cairo_xlib_font_get_glyphset_info_for_format (cairo_xlib_display_t *display,
  1107.                                                cairo_scaled_font_t *font,
  1108.                                                cairo_format_t       format)
  1109. {
  1110.     cairo_xlib_font_t *priv;
  1111.     cairo_xlib_font_glyphset_t *info;
  1112.     int glyphset_index;
  1113.  
  1114.     glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
  1115.  
  1116.     priv = _cairo_xlib_font_get (display, font);
  1117.     if (priv == NULL) {
  1118.         priv = _cairo_xlib_font_create (display, font);
  1119.         if (priv == NULL)
  1120.             return NULL;
  1121.     }
  1122.  
  1123.     info = &priv->glyphset[glyphset_index];
  1124.     if (info->glyphset == None) {
  1125.         info->xrender_format =
  1126.             _cairo_xlib_display_get_xrender_format (display, info->format);
  1127.         info->glyphset = XRenderCreateGlyphSet (display->display,
  1128.                                                 info->xrender_format);
  1129.     }
  1130.  
  1131.     return info;
  1132. }
  1133.  
  1134. static cairo_bool_t
  1135. has_pending_free_glyph (cairo_xlib_font_glyphset_t *info,
  1136.                         unsigned long glyph_index)
  1137. {
  1138.     struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
  1139.     int i;
  1140.  
  1141.     to_free = &info->to_free;
  1142.     for (i = 0; i < to_free->count; i++) {
  1143.         if (to_free->indices[i] == glyph_index) {
  1144.             to_free->count--;
  1145.             memmove (&to_free->indices[i],
  1146.                      &to_free->indices[i+1],
  1147.                      (to_free->count - i) * sizeof (to_free->indices[0]));
  1148.             return TRUE;
  1149.         }
  1150.     }
  1151.  
  1152.     return FALSE;
  1153. }
  1154.  
  1155. static cairo_xlib_font_glyphset_t *
  1156. find_pending_free_glyph (cairo_xlib_display_t *display,
  1157.                          cairo_scaled_font_t *font,
  1158.                          unsigned long glyph_index,
  1159.                          cairo_image_surface_t *surface)
  1160. {
  1161.     cairo_xlib_font_t *priv;
  1162.     int i;
  1163.  
  1164.     priv = _cairo_xlib_font_get (display, font);
  1165.     if (priv == NULL)
  1166.         return NULL;
  1167.  
  1168.     if (surface != NULL) {
  1169.         i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
  1170.         if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
  1171.             return &priv->glyphset[i];
  1172.     } else {
  1173.         for (i = 0; i < NUM_GLYPHSETS; i++) {
  1174.             if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
  1175.                 return &priv->glyphset[i];
  1176.         }
  1177.     }
  1178.  
  1179.     return NULL;
  1180. }
  1181.  
  1182. static cairo_status_t
  1183. _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
  1184.                                cairo_scaled_font_t   *font,
  1185.                                cairo_scaled_glyph_t **pscaled_glyph)
  1186. {
  1187.     XGlyphInfo glyph_info;
  1188.     unsigned long glyph_index;
  1189.     unsigned char *data;
  1190.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  1191.     cairo_scaled_glyph_t *glyph = *pscaled_glyph;
  1192.     cairo_image_surface_t *glyph_surface = glyph->surface;
  1193.     cairo_bool_t already_had_glyph_surface;
  1194.     cairo_xlib_font_glyphset_t *info;
  1195.  
  1196.     glyph_index = _cairo_scaled_glyph_index (glyph);
  1197.  
  1198.     /* check to see if we have a pending XRenderFreeGlyph for this glyph */
  1199.     info = find_pending_free_glyph (display, font, glyph_index, glyph_surface);
  1200.     if (info != NULL)
  1201.         return _cairo_xlib_glyph_attach (display, glyph, info);
  1202.  
  1203.     if (glyph_surface == NULL) {
  1204.         status = _cairo_scaled_glyph_lookup (font,
  1205.                                              glyph_index,
  1206.                                              CAIRO_SCALED_GLYPH_INFO_METRICS |
  1207.                                              CAIRO_SCALED_GLYPH_INFO_SURFACE,
  1208.                                              pscaled_glyph);
  1209.         if (unlikely (status))
  1210.             return status;
  1211.  
  1212.         glyph = *pscaled_glyph;
  1213.         glyph_surface = glyph->surface;
  1214.         already_had_glyph_surface = FALSE;
  1215.     } else {
  1216.         already_had_glyph_surface = TRUE;
  1217.     }
  1218.  
  1219.     info = _cairo_xlib_font_get_glyphset_info_for_format (display, font,
  1220.                                                           glyph_surface->format);
  1221.  
  1222. #if 0
  1223.     /* If the glyph surface has zero height or width, we create
  1224.      * a clear 1x1 surface, to avoid various X server bugs.
  1225.      */
  1226.     if (glyph_surface->width == 0 || glyph_surface->height == 0) {
  1227.         cairo_surface_t *tmp_surface;
  1228.  
  1229.         tmp_surface = cairo_image_surface_create (info->format, 1, 1);
  1230.         status = tmp_surface->status;
  1231.         if (unlikely (status))
  1232.             goto BAIL;
  1233.  
  1234.         tmp_surface->device_transform = glyph_surface->base.device_transform;
  1235.         tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
  1236.  
  1237.         glyph_surface = (cairo_image_surface_t *) tmp_surface;
  1238.     }
  1239. #endif
  1240.  
  1241.     /* If the glyph format does not match the font format, then we
  1242.      * create a temporary surface for the glyph image with the font's
  1243.      * format.
  1244.      */
  1245.     if (glyph_surface->format != info->format) {
  1246.         cairo_surface_pattern_t pattern;
  1247.         cairo_surface_t *tmp_surface;
  1248.  
  1249.         tmp_surface = cairo_image_surface_create (info->format,
  1250.                                                   glyph_surface->width,
  1251.                                                   glyph_surface->height);
  1252.         status = tmp_surface->status;
  1253.         if (unlikely (status))
  1254.             goto BAIL;
  1255.  
  1256.         tmp_surface->device_transform = glyph_surface->base.device_transform;
  1257.         tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
  1258.  
  1259.         _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
  1260.         status = _cairo_surface_paint (tmp_surface,
  1261.                                        CAIRO_OPERATOR_SOURCE, &pattern.base,
  1262.                                        NULL);
  1263.         _cairo_pattern_fini (&pattern.base);
  1264.  
  1265.         glyph_surface = (cairo_image_surface_t *) tmp_surface;
  1266.  
  1267.         if (unlikely (status))
  1268.             goto BAIL;
  1269.     }
  1270.  
  1271.     /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
  1272.     glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
  1273.     glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
  1274.     glyph_info.width = glyph_surface->width;
  1275.     glyph_info.height = glyph_surface->height;
  1276.     glyph_info.xOff = glyph->x_advance;
  1277.     glyph_info.yOff = glyph->y_advance;
  1278.  
  1279.     data = glyph_surface->data;
  1280.  
  1281.     /* flip formats around */
  1282.     switch (_cairo_xlib_get_glyphset_index_for_format (glyph->surface->format)) {
  1283.     case GLYPHSET_INDEX_A1:
  1284.         /* local bitmaps are always stored with bit == byte */
  1285.         if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) {
  1286.             int             c = glyph_surface->stride * glyph_surface->height;
  1287.             unsigned char   *d;
  1288.             unsigned char   *new, *n;
  1289.  
  1290.             new = malloc (c);
  1291.             if (!new) {
  1292.                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1293.                 goto BAIL;
  1294.             }
  1295.             n = new;
  1296.             d = data;
  1297.             do {
  1298.                 char    b = *d++;
  1299.                 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
  1300.                 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
  1301.                 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
  1302.                 *n++ = b;
  1303.             } while (--c);
  1304.             data = new;
  1305.         }
  1306.         break;
  1307.     case GLYPHSET_INDEX_A8:
  1308.         break;
  1309.     case GLYPHSET_INDEX_ARGB32:
  1310.         if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
  1311.             unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
  1312.             const uint32_t *d;
  1313.             uint32_t *new, *n;
  1314.  
  1315.             new = malloc (4 * c);
  1316.             if (unlikely (new == NULL)) {
  1317.                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1318.                 goto BAIL;
  1319.             }
  1320.             n = new;
  1321.             d = (uint32_t *) data;
  1322.             do {
  1323.                 *n++ = bswap_32 (*d);
  1324.                 d++;
  1325.             } while (--c);
  1326.             data = (uint8_t *) new;
  1327.         }
  1328.         break;
  1329.     default:
  1330.         ASSERT_NOT_REACHED;
  1331.         break;
  1332.     }
  1333.     /* XXX assume X server wants pixman padding. Xft assumes this as well */
  1334.  
  1335.     XRenderAddGlyphs (display->display, info->glyphset,
  1336.                       &glyph_index, &glyph_info, 1,
  1337.                       (char *) data,
  1338.                       glyph_surface->stride * glyph_surface->height);
  1339.  
  1340.     if (data != glyph_surface->data)
  1341.         free (data);
  1342.  
  1343.     status = _cairo_xlib_glyph_attach (display, glyph, info);
  1344.  
  1345.  BAIL:
  1346.     if (glyph_surface != glyph->surface)
  1347.         cairo_surface_destroy (&glyph_surface->base);
  1348.  
  1349.     /* if the scaled glyph didn't already have a surface attached
  1350.      * to it, release the created surface now that we have it
  1351.      * uploaded to the X server.  If the surface has already been
  1352.      * there (eg. because image backend requested it), leave it in
  1353.      * the cache
  1354.      */
  1355.     if (!already_had_glyph_surface)
  1356.         _cairo_scaled_glyph_set_surface (glyph, font, NULL);
  1357.  
  1358.     return status;
  1359. }
  1360.  
  1361. typedef void (*cairo_xrender_composite_text_func_t)
  1362.               (Display                      *dpy,
  1363.                int                          op,
  1364.                Picture                      src,
  1365.                Picture                      dst,
  1366.                _Xconst XRenderPictFormat    *maskFormat,
  1367.                int                          xSrc,
  1368.                int                          ySrc,
  1369.                int                          xDst,
  1370.                int                          yDst,
  1371.                _Xconst XGlyphElt8           *elts,
  1372.                int                          nelt);
  1373.  
  1374. /* Build a struct of the same size of #cairo_glyph_t that can be used both as
  1375.  * an input glyph with double coordinates, and as "working" glyph with
  1376.  * integer from-current-point offsets. */
  1377. typedef union {
  1378.     cairo_glyph_t d;
  1379.     unsigned long index;
  1380.     struct {
  1381.         unsigned long index;
  1382.         int x;
  1383.         int y;
  1384.     } i;
  1385. } cairo_xlib_glyph_t;
  1386.  
  1387. /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
  1388. COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
  1389.  
  1390. /* Start a new element for the first glyph,
  1391.  * or for any glyph that has unexpected position,
  1392.  * or if current element has too many glyphs
  1393.  * (Xrender limits each element to 252 glyphs, we limit them to 128)
  1394.  *
  1395.  * These same conditions need to be mirrored between
  1396.  * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
  1397.  */
  1398. #define _start_new_glyph_elt(count, glyph) \
  1399.     (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
  1400.  
  1401. static cairo_status_t
  1402. _emit_glyphs_chunk (cairo_xlib_display_t *display,
  1403.                     cairo_xlib_surface_t *dst,
  1404.                     int dst_x, int dst_y,
  1405.                     cairo_xlib_glyph_t *glyphs,
  1406.                     int num_glyphs,
  1407.                     cairo_scaled_font_t *font,
  1408.                     cairo_bool_t use_mask,
  1409.                     cairo_operator_t op,
  1410.                     cairo_xlib_source_t *src,
  1411.                     int src_x, int src_y,
  1412.                     /* info for this chunk */
  1413.                     int num_elts,
  1414.                     int width,
  1415.                     cairo_xlib_font_glyphset_t *info)
  1416. {
  1417.     /* Which XRenderCompositeText function to use */
  1418.     cairo_xrender_composite_text_func_t composite_text_func;
  1419.     int size;
  1420.  
  1421.     /* Element buffer stuff */
  1422.     XGlyphElt8 *elts;
  1423.     XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
  1424.  
  1425.     /* Reuse the input glyph array for output char generation */
  1426.     char *char8 = (char *) glyphs;
  1427.     unsigned short *char16 = (unsigned short *) glyphs;
  1428.     unsigned int *char32 = (unsigned int *) glyphs;
  1429.  
  1430.     int i;
  1431.     int nelt; /* Element index */
  1432.     int n; /* Num output glyphs in current element */
  1433.     int j; /* Num output glyphs so far */
  1434.  
  1435.     switch (width) {
  1436.     case 1:
  1437.         /* don't cast the 8-variant, to catch possible mismatches */
  1438.         composite_text_func = XRenderCompositeText8;
  1439.         size = sizeof (char);
  1440.         break;
  1441.     case 2:
  1442.         composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
  1443.         size = sizeof (unsigned short);
  1444.         break;
  1445.     default:
  1446.     case 4:
  1447.         composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
  1448.         size = sizeof (unsigned int);
  1449.     }
  1450.  
  1451.     /* Allocate element array */
  1452.     if (num_elts <= ARRAY_LENGTH (stack_elts)) {
  1453.       elts = stack_elts;
  1454.     } else {
  1455.       elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
  1456.       if (unlikely (elts == NULL))
  1457.           return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1458.     }
  1459.  
  1460.     /* Fill them in */
  1461.     nelt = 0;
  1462.     n = 0;
  1463.     j = 0;
  1464.     for (i = 0; i < num_glyphs; i++) {
  1465.       /* Start a new element for first output glyph,
  1466.        * or for any glyph that has unexpected position,
  1467.        * or if current element has too many glyphs.
  1468.        *
  1469.        * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
  1470.        */
  1471.       if (_start_new_glyph_elt (j, &glyphs[i])) {
  1472.           if (j) {
  1473.               elts[nelt].nchars = n;
  1474.               nelt++;
  1475.               n = 0;
  1476.           }
  1477.           elts[nelt].chars = char8 + size * j;
  1478.           elts[nelt].glyphset = info->glyphset;
  1479.           elts[nelt].xOff = glyphs[i].i.x;
  1480.           elts[nelt].yOff = glyphs[i].i.y;
  1481.       }
  1482.  
  1483.       switch (width) {
  1484.       case 1: char8 [j] = (char)           glyphs[i].index; break;
  1485.       case 2: char16[j] = (unsigned short) glyphs[i].index; break;
  1486.       default:
  1487.       case 4: char32[j] = (unsigned int)   glyphs[i].index; break;
  1488.       }
  1489.  
  1490.       n++;
  1491.       j++;
  1492.     }
  1493.  
  1494.     if (n) {
  1495.         elts[nelt].nchars = n;
  1496.         nelt++;
  1497.     }
  1498.  
  1499.     /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
  1500.      * expected number of xGlyphElts.  */
  1501.     assert (nelt == num_elts);
  1502.  
  1503.     composite_text_func (display->display, op,
  1504.                          src->picture,
  1505.                          dst->picture,
  1506.                          use_mask ? info->xrender_format : NULL,
  1507.                          src_x + elts[0].xOff + dst_x,
  1508.                          src_y + elts[0].yOff + dst_y,
  1509.                          elts[0].xOff, elts[0].yOff,
  1510.                          (XGlyphElt8 *) elts, nelt);
  1511.  
  1512.     if (elts != stack_elts)
  1513.       free (elts);
  1514.  
  1515.     return CAIRO_STATUS_SUCCESS;
  1516. }
  1517.  
  1518. static cairo_int_status_t
  1519. check_composite_glyphs (const cairo_composite_rectangles_t *extents,
  1520.                         cairo_scaled_font_t *font,
  1521.                         cairo_glyph_t *glyphs,
  1522.                         int *num_glyphs)
  1523. {
  1524.     cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
  1525.     cairo_xlib_display_t *display = dst->display;
  1526.     int max_request_size, size;
  1527.  
  1528.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1529.  
  1530.     if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
  1531.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1532.  
  1533.     /* The glyph coordinates must be representable in an int16_t.
  1534.      * When possible, they will be expressed as an offset from the
  1535.      * previous glyph, otherwise they will be an offset from the
  1536.      * surface origin. If we can't guarantee this to be possible,
  1537.      * fallback.
  1538.      */
  1539.     if (extents->bounded.x + extents->bounded.width > INT16_MAX ||
  1540.         extents->bounded.y + extents->bounded.height> INT16_MAX ||
  1541.         extents->bounded.x < INT16_MIN ||
  1542.         extents->bounded.y < INT16_MIN)
  1543.     {
  1544.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1545.     }
  1546.  
  1547.     /* Approximate the size of the largest glyph and fallback if we can not
  1548.      * upload it to the xserver.
  1549.      */
  1550.     size = ceil (font->max_scale);
  1551.     size = 4 * size * size;
  1552.     max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
  1553.                         : XMaxRequestSize (display->display)) * 4 -
  1554.         sz_xRenderAddGlyphsReq -
  1555.         sz_xGlyphInfo          -
  1556.         8;
  1557.     if (size >= max_request_size)
  1558.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1559.  
  1560.     return CAIRO_STATUS_SUCCESS;
  1561. }
  1562.  
  1563. /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
  1564.  * enough room for padding */
  1565. #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
  1566.  
  1567. static cairo_int_status_t
  1568. composite_glyphs (void                          *surface,
  1569.                   cairo_operator_t               op,
  1570.                   cairo_surface_t               *_src,
  1571.                   int                            src_x,
  1572.                   int                            src_y,
  1573.                   int                            dst_x,
  1574.                   int                            dst_y,
  1575.                   cairo_composite_glyphs_info_t *info)
  1576. {
  1577.     cairo_xlib_surface_t *dst = surface;
  1578.     cairo_xlib_glyph_t *glyphs = (cairo_xlib_glyph_t *)info->glyphs;
  1579.     cairo_xlib_source_t *src = (cairo_xlib_source_t *)_src;
  1580.     cairo_xlib_display_t *display = dst->display;
  1581.     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
  1582.     cairo_scaled_glyph_t *glyph;
  1583.     cairo_fixed_t x = dst_x, y = dst_y;
  1584.     cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
  1585.  
  1586.     unsigned long max_index = 0;
  1587.     int width = 1;
  1588.     int num_elts = 0;
  1589.     int num_out_glyphs = 0;
  1590.     int num_glyphs = info->num_glyphs;
  1591.  
  1592.     int max_request_size = XMaxRequestSize (display->display) * 4
  1593.                          - MAX (sz_xRenderCompositeGlyphs8Req,
  1594.                                 MAX(sz_xRenderCompositeGlyphs16Req,
  1595.                                     sz_xRenderCompositeGlyphs32Req));
  1596.     int request_size = 0;
  1597.     int i;
  1598.  
  1599.     op = _render_operator (op),
  1600.     _cairo_xlib_surface_ensure_picture (dst);
  1601.     for (i = 0; i < num_glyphs; i++) {
  1602.         int this_x, this_y;
  1603.         int old_width;
  1604.  
  1605.         status = _cairo_scaled_glyph_lookup (info->font,
  1606.                                              glyphs[i].index,
  1607.                                              CAIRO_SCALED_GLYPH_INFO_METRICS,
  1608.                                              &glyph);
  1609.         if (unlikely (status))
  1610.             return status;
  1611.  
  1612.         this_x = _cairo_lround (glyphs[i].d.x);
  1613.         this_y = _cairo_lround (glyphs[i].d.y);
  1614.  
  1615.         /* Send unsent glyphs to the server */
  1616.         if (glyph->dev_private_key != display) {
  1617.             status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph);
  1618.             if (unlikely (status))
  1619.                 return status;
  1620.         }
  1621.  
  1622.         this_glyphset_info = glyph->dev_private;
  1623.         if (!glyphset)
  1624.             glyphset = this_glyphset_info;
  1625.  
  1626.         /* The invariant here is that we can always flush the glyphs
  1627.          * accumulated before this one, using old_width, and they
  1628.          * would fit in the request.
  1629.          */
  1630.         old_width = width;
  1631.  
  1632.         /* Update max glyph index */
  1633.         if (glyphs[i].index > max_index) {
  1634.             max_index = glyphs[i].index;
  1635.             if (max_index >= 65536)
  1636.               width = 4;
  1637.             else if (max_index >= 256)
  1638.               width = 2;
  1639.             if (width != old_width)
  1640.               request_size += (width - old_width) * num_out_glyphs;
  1641.         }
  1642.  
  1643.         /* If we will pass the max request size by adding this glyph,
  1644.          * flush current glyphs.  Note that we account for a
  1645.          * possible element being added below.
  1646.          *
  1647.          * Also flush if changing glyphsets, as Xrender limits one mask
  1648.          * format per request, so we can either break up, or use a
  1649.          * wide-enough mask format.  We do the former.  One reason to
  1650.          * prefer the latter is the fact that Xserver ADDs all glyphs
  1651.          * to the mask first, and then composes that to final surface,
  1652.          * though it's not a big deal.
  1653.          *
  1654.          * If the glyph has a coordinate which cannot be represented
  1655.          * as a 16-bit offset from the previous glyph, flush the
  1656.          * current chunk. The current glyph will be the first one in
  1657.          * the next chunk, thus its coordinates will be an offset from
  1658.          * the destination origin. This offset is guaranteed to be
  1659.          * representable as 16-bit offset (otherwise we would have
  1660.          * fallen back).
  1661.          */
  1662.         if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
  1663.             this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
  1664.             this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
  1665.             (this_glyphset_info != glyphset)) {
  1666.             status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
  1667.                                          glyphs, i, info->font, info->use_mask,
  1668.                                          op, src, src_x, src_y,
  1669.                                          num_elts, old_width, glyphset);
  1670.             if (unlikely (status))
  1671.                 return status;
  1672.  
  1673.             glyphs += i;
  1674.             num_glyphs -= i;
  1675.             i = 0;
  1676.             max_index = glyphs[i].index;
  1677.             width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
  1678.             request_size = 0;
  1679.             num_elts = 0;
  1680.             num_out_glyphs = 0;
  1681.             x = y = 0;
  1682.             glyphset = this_glyphset_info;
  1683.         }
  1684.  
  1685.         /* Convert absolute glyph position to relative-to-current-point
  1686.          * position */
  1687.         glyphs[i].i.x = this_x - x;
  1688.         glyphs[i].i.y = this_y - y;
  1689.  
  1690.         /* Start a new element for the first glyph,
  1691.          * or for any glyph that has unexpected position,
  1692.          * or if current element has too many glyphs.
  1693.          *
  1694.          * These same conditions are mirrored in _emit_glyphs_chunk().
  1695.          */
  1696.       if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
  1697.             num_elts++;
  1698.             request_size += _cairo_sz_xGlyphElt;
  1699.         }
  1700.  
  1701.         /* adjust current-position */
  1702.         x = this_x + glyph->x_advance;
  1703.         y = this_y + glyph->y_advance;
  1704.  
  1705.         num_out_glyphs++;
  1706.         request_size += width;
  1707.     }
  1708.  
  1709.     if (num_elts) {
  1710.         status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
  1711.                                      glyphs, i, info->font, info->use_mask,
  1712.                                      op, src, src_x, src_y,
  1713.                                      num_elts, width, glyphset);
  1714.     }
  1715.  
  1716.     return status;
  1717. }
  1718.  
  1719. const cairo_compositor_t *
  1720. _cairo_xlib_mask_compositor_get (void)
  1721. {
  1722.     static cairo_mask_compositor_t compositor;
  1723.  
  1724.     if (compositor.base.delegate == NULL) {
  1725.         _cairo_mask_compositor_init (&compositor,
  1726.                                      _cairo_xlib_fallback_compositor_get ());
  1727.  
  1728.         compositor.acquire = acquire;
  1729.         compositor.release = release;
  1730.         compositor.set_clip_region = set_clip_region;
  1731.         compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
  1732.         compositor.draw_image_boxes = draw_image_boxes;
  1733.         compositor.fill_rectangles = fill_rectangles;
  1734.         compositor.fill_boxes = fill_boxes;
  1735.         compositor.copy_boxes = copy_boxes;
  1736.         compositor.check_composite = check_composite;
  1737.         compositor.composite = composite;
  1738.         //compositor.check_composite_boxes = check_composite_boxes;
  1739.         compositor.composite_boxes = composite_boxes;
  1740.         compositor.check_composite_glyphs = check_composite_glyphs;
  1741.         compositor.composite_glyphs = composite_glyphs;
  1742.     }
  1743.  
  1744.     return &compositor.base;
  1745. }
  1746.  
  1747. #define CAIRO_FIXED_16_16_MIN -32768
  1748. #define CAIRO_FIXED_16_16_MAX 32767
  1749.  
  1750. static cairo_bool_t
  1751. line_exceeds_16_16 (const cairo_line_t *line)
  1752. {
  1753.     return
  1754.         line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
  1755.         line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
  1756.         line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
  1757.         line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
  1758.         line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
  1759.         line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
  1760.         line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
  1761.         line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
  1762. }
  1763.  
  1764. static void
  1765. project_line_x_onto_16_16 (const cairo_line_t *line,
  1766.                             cairo_fixed_t top,
  1767.                             cairo_fixed_t bottom,
  1768.                             XLineFixed *out)
  1769. {
  1770.     cairo_point_double_t p1, p2;
  1771.     double m;
  1772.  
  1773.     p1.x = _cairo_fixed_to_double (line->p1.x);
  1774.     p1.y = _cairo_fixed_to_double (line->p1.y);
  1775.  
  1776.     p2.x = _cairo_fixed_to_double (line->p2.x);
  1777.     p2.y = _cairo_fixed_to_double (line->p2.y);
  1778.  
  1779.     m = (p2.x - p1.x) / (p2.y - p1.y);
  1780.     out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
  1781.     out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
  1782. }
  1783. #if 0
  1784. static cairo_int_status_T
  1785. check_composite_trapezoids ()
  1786. {
  1787.     operation = _categorize_composite_operation (dst, op, pattern, TRUE);
  1788.     if (operation == DO_UNSUPPORTED)
  1789.         return UNSUPPORTED ("unsupported operation");
  1790.  
  1791.     operation = _recategorize_composite_operation (dst, op, src,
  1792.                                                    &attributes, TRUE);
  1793.     if (operation == DO_UNSUPPORTED) {
  1794.         status = UNSUPPORTED ("unsupported operation");
  1795.         goto BAIL;
  1796.     }
  1797.  
  1798. }
  1799. #endif
  1800.  
  1801. static cairo_int_status_t
  1802. composite_traps (void                   *abstract_dst,
  1803.                  cairo_operator_t       op,
  1804.                  cairo_surface_t        *abstract_src,
  1805.                  int                    src_x,
  1806.                  int                    src_y,
  1807.                  int                    dst_x,
  1808.                  int                    dst_y,
  1809.                  const cairo_rectangle_int_t *extents,
  1810.                  cairo_antialias_t      antialias,
  1811.                  cairo_traps_t          *traps)
  1812. {
  1813.     cairo_xlib_surface_t        *dst = abstract_dst;
  1814.     cairo_xlib_display_t        *display = dst->display;
  1815.     cairo_xlib_source_t         *src = (cairo_xlib_source_t *)abstract_src;
  1816.     XRenderPictFormat           *pict_format;
  1817.     XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
  1818.     XTrapezoid *xtraps = xtraps_stack;
  1819.     int dx, dy;
  1820.     int i;
  1821.  
  1822.     //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
  1823.  
  1824.     if (dst->base.is_clear &&
  1825.         (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))
  1826.     {
  1827.         op = CAIRO_OPERATOR_SOURCE;
  1828.     }
  1829.  
  1830.     pict_format =
  1831.         _cairo_xlib_display_get_xrender_format (display,
  1832.                                                 antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
  1833.  
  1834.     if (traps->num_traps > ARRAY_LENGTH (xtraps_stack)) {
  1835.         xtraps = _cairo_malloc_ab (traps->num_traps, sizeof (XTrapezoid));
  1836.         if (unlikely (xtraps == NULL))
  1837.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1838.     }
  1839.  
  1840.     dx = -dst_x << 16;
  1841.     dy = -dst_y << 16;
  1842.     for (i = 0; i < traps->num_traps; i++) {
  1843.         cairo_trapezoid_t *t = &traps->traps[i];
  1844.  
  1845.         /* top/bottom will be clamped to surface bounds */
  1846.         xtraps[i].top = _cairo_fixed_to_16_16(t->top) + dy;
  1847.         xtraps[i].bottom = _cairo_fixed_to_16_16(t->bottom) + dy;
  1848.  
  1849.         /* However, all the other coordinates will have been left untouched so
  1850.          * as not to introduce numerical error. Recompute them if they
  1851.          * exceed the 16.16 limits.
  1852.          */
  1853.         if (unlikely (line_exceeds_16_16 (&t->left))) {
  1854.             project_line_x_onto_16_16 (&t->left, t->top, t->bottom,
  1855.                                         &xtraps[i].left);
  1856.             xtraps[i].left.p1.x += dx;
  1857.             xtraps[i].left.p2.x += dx;
  1858.             xtraps[i].left.p1.y = xtraps[i].top;
  1859.             xtraps[i].left.p2.y = xtraps[i].bottom;
  1860.         } else {
  1861.             xtraps[i].left.p1.x = _cairo_fixed_to_16_16(t->left.p1.x) + dx;
  1862.             xtraps[i].left.p1.y = _cairo_fixed_to_16_16(t->left.p1.y) + dy;
  1863.             xtraps[i].left.p2.x = _cairo_fixed_to_16_16(t->left.p2.x) + dx;
  1864.             xtraps[i].left.p2.y = _cairo_fixed_to_16_16(t->left.p2.y) + dy;
  1865.         }
  1866.  
  1867.         if (unlikely (line_exceeds_16_16 (&t->right))) {
  1868.             project_line_x_onto_16_16 (&t->right, t->top, t->bottom,
  1869.                                        &xtraps[i].right);
  1870.             xtraps[i].right.p1.x += dx;
  1871.             xtraps[i].right.p2.x += dx;
  1872.             xtraps[i].right.p1.y = xtraps[i].top;
  1873.             xtraps[i].right.p2.y = xtraps[i].bottom;
  1874.         } else {
  1875.             xtraps[i].right.p1.x = _cairo_fixed_to_16_16(t->right.p1.x) + dx;
  1876.             xtraps[i].right.p1.y = _cairo_fixed_to_16_16(t->right.p1.y) + dy;
  1877.             xtraps[i].right.p2.x = _cairo_fixed_to_16_16(t->right.p2.x) + dx;
  1878.             xtraps[i].right.p2.y = _cairo_fixed_to_16_16(t->right.p2.y) + dy;
  1879.         }
  1880.     }
  1881.  
  1882.     if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
  1883.         src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
  1884.         src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
  1885.     } else {
  1886.         src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
  1887.         src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
  1888.     }
  1889.     src_x += dst_x;
  1890.     src_y += dst_y;
  1891.  
  1892.     _cairo_xlib_surface_ensure_picture (dst);
  1893.     _cairo_xlib_surface_set_precision (dst, antialias);
  1894.     XRenderCompositeTrapezoids (dst->dpy,
  1895.                                 _render_operator (op),
  1896.                                 src->picture, dst->picture,
  1897.                                 pict_format,
  1898.                                 src_x, src_y,
  1899.                                 xtraps, traps->num_traps);
  1900.  
  1901.     if (xtraps != xtraps_stack)
  1902.         free (xtraps);
  1903.  
  1904.     return CAIRO_STATUS_SUCCESS;
  1905. }
  1906.  
  1907. static cairo_int_status_t
  1908. composite_tristrip (void                *abstract_dst,
  1909.                     cairo_operator_t    op,
  1910.                     cairo_surface_t     *abstract_src,
  1911.                     int                 src_x,
  1912.                     int                 src_y,
  1913.                     int                 dst_x,
  1914.                     int                 dst_y,
  1915.                     const cairo_rectangle_int_t *extents,
  1916.                     cairo_antialias_t   antialias,
  1917.                     cairo_tristrip_t    *strip)
  1918. {
  1919.     cairo_xlib_surface_t        *dst = abstract_dst;
  1920.     cairo_xlib_display_t        *display = dst->display;
  1921.     cairo_xlib_source_t         *src = (cairo_xlib_source_t *)abstract_src;
  1922.     XRenderPictFormat           *pict_format;
  1923.     XPointFixed points_stack[CAIRO_STACK_ARRAY_LENGTH (XPointFixed)];
  1924.     XPointFixed *points = points_stack;
  1925.     int dx, dy;
  1926.     int i;
  1927.  
  1928.     //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
  1929.  
  1930.     pict_format =
  1931.         _cairo_xlib_display_get_xrender_format (display,
  1932.                                                 antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
  1933.  
  1934.     if (strip->num_points > ARRAY_LENGTH (points_stack)) {
  1935.         points = _cairo_malloc_ab (strip->num_points, sizeof (XPointFixed));
  1936.         if (unlikely (points == NULL))
  1937.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1938.     }
  1939.  
  1940.     dx = -dst_x << 16;
  1941.     dy = -dst_y << 16;
  1942.     for (i = 0; i < strip->num_points; i++) {
  1943.         cairo_point_t *p = &strip->points[i];
  1944.  
  1945.         points[i].x = _cairo_fixed_to_16_16(p->x) + dx;
  1946.         points[i].y = _cairo_fixed_to_16_16(p->y) + dy;
  1947.     }
  1948.  
  1949.     src_x += _cairo_fixed_16_16_floor (points[0].x) + dst_x;
  1950.     src_y += _cairo_fixed_16_16_floor (points[0].y) + dst_y;
  1951.  
  1952.     _cairo_xlib_surface_ensure_picture (dst);
  1953.     _cairo_xlib_surface_set_precision (dst, antialias);
  1954.     XRenderCompositeTriStrip (dst->dpy,
  1955.                               _render_operator (op),
  1956.                               src->picture, dst->picture,
  1957.                               pict_format,
  1958.                               src_x, src_y,
  1959.                               points, strip->num_points);
  1960.  
  1961.     if (points != points_stack)
  1962.         free (points);
  1963.  
  1964.     return CAIRO_STATUS_SUCCESS;
  1965. }
  1966.  
  1967. const cairo_compositor_t *
  1968. _cairo_xlib_traps_compositor_get (void)
  1969. {
  1970.     static cairo_traps_compositor_t compositor;
  1971.  
  1972.     if (compositor.base.delegate == NULL) {
  1973.         _cairo_traps_compositor_init (&compositor,
  1974.                                       _cairo_xlib_mask_compositor_get ());
  1975.  
  1976.         compositor.acquire = acquire;
  1977.         compositor.release = release;
  1978.         compositor.set_clip_region = set_clip_region;
  1979.         compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
  1980.         compositor.draw_image_boxes = draw_image_boxes;
  1981.         compositor.copy_boxes = copy_boxes;
  1982.         compositor.fill_boxes = fill_boxes;
  1983.         compositor.check_composite = check_composite;
  1984.         compositor.composite = composite;
  1985.         compositor.lerp = lerp;
  1986.         //compositor.check_composite_boxes = check_composite_boxes;
  1987.         compositor.composite_boxes = composite_boxes;
  1988.         //compositor.check_composite_traps = check_composite_traps;
  1989.         compositor.composite_traps = composite_traps;
  1990.         //compositor.check_composite_tristrip = check_composite_tristrip;
  1991.         compositor.composite_tristrip = composite_tristrip;
  1992.         compositor.check_composite_glyphs = check_composite_glyphs;
  1993.         compositor.composite_glyphs = composite_glyphs;
  1994.     }
  1995.  
  1996.     return &compositor.base;
  1997. }
  1998.  
  1999. #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
  2000.