Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
  2. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright © 2003 University of Southern California
  5.  * Copyright © 2009,2010,2011 Intel Corporation
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it either under the terms of the GNU Lesser General Public
  9.  * License version 2.1 as published by the Free Software Foundation
  10.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  11.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  12.  * notice, a recipient may use your version of this file under either
  13.  * the MPL or the LGPL.
  14.  *
  15.  * You should have received a copy of the LGPL along with this library
  16.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  18.  * You should have received a copy of the MPL along with this library
  19.  * in the file COPYING-MPL-1.1
  20.  *
  21.  * The contents of this file are subject to the Mozilla Public License
  22.  * Version 1.1 (the "License"); you may not use this file except in
  23.  * compliance with the License. You may obtain a copy of the License at
  24.  * http://www.mozilla.org/MPL/
  25.  *
  26.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  27.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  28.  * the specific language governing rights and limitations.
  29.  *
  30.  * The Original Code is the cairo graphics library.
  31.  *
  32.  * The Initial Developer of the Original Code is University of Southern
  33.  * California.
  34.  *
  35.  * Contributor(s):
  36.  *      Carl D. Worth <cworth@cworth.org>
  37.  *      Chris Wilson <chris@chris-wilson.co.uk>
  38.  */
  39.  
  40. /* The primarily reason for keeping a traps-compositor around is
  41.  * for validating cairo-xlib (which currently also uses traps).
  42.  */
  43.  
  44. #include "cairoint.h"
  45.  
  46. #include "cairo-image-surface-private.h"
  47.  
  48. #include "cairo-compositor-private.h"
  49. #include "cairo-spans-compositor-private.h"
  50.  
  51. #include "cairo-region-private.h"
  52. #include "cairo-traps-private.h"
  53. #include "cairo-tristrip-private.h"
  54.  
  55. #include "cairo-pixman-private.h"
  56.  
  57. static pixman_image_t *
  58. to_pixman_image (cairo_surface_t *s)
  59. {
  60.     return ((cairo_image_surface_t *)s)->pixman_image;
  61. }
  62.  
  63. static cairo_int_status_t
  64. acquire (void *abstract_dst)
  65. {
  66.     return CAIRO_STATUS_SUCCESS;
  67. }
  68.  
  69. static cairo_int_status_t
  70. release (void *abstract_dst)
  71. {
  72.     return CAIRO_STATUS_SUCCESS;
  73. }
  74.  
  75. static cairo_int_status_t
  76. set_clip_region (void *_surface,
  77.                  cairo_region_t *region)
  78. {
  79.     cairo_image_surface_t *surface = _surface;
  80.     pixman_region32_t *rgn = region ? &region->rgn : NULL;
  81.  
  82.     if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
  83.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  84.  
  85.     return CAIRO_STATUS_SUCCESS;
  86. }
  87.  
  88. static cairo_int_status_t
  89. draw_image_boxes (void *_dst,
  90.                   cairo_image_surface_t *image,
  91.                   cairo_boxes_t *boxes,
  92.                   int dx, int dy)
  93. {
  94.     cairo_image_surface_t *dst = _dst;
  95.     struct _cairo_boxes_chunk *chunk;
  96.     int i;
  97.  
  98.     TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
  99.  
  100.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  101.         for (i = 0; i < chunk->count; i++) {
  102.             cairo_box_t *b = &chunk->base[i];
  103.             int x = _cairo_fixed_integer_part (b->p1.x);
  104.             int y = _cairo_fixed_integer_part (b->p1.y);
  105.             int w = _cairo_fixed_integer_part (b->p2.x) - x;
  106.             int h = _cairo_fixed_integer_part (b->p2.y) - y;
  107.             if (dst->pixman_format != image->pixman_format ||
  108.                 ! pixman_blt ((uint32_t *)image->data, (uint32_t *)dst->data,
  109.                               image->stride / sizeof (uint32_t),
  110.                               dst->stride / sizeof (uint32_t),
  111.                               PIXMAN_FORMAT_BPP (image->pixman_format),
  112.                               PIXMAN_FORMAT_BPP (dst->pixman_format),
  113.                               x + dx, y + dy,
  114.                               x, y,
  115.                               w, h))
  116.             {
  117.                 pixman_image_composite32 (PIXMAN_OP_SRC,
  118.                                           image->pixman_image, NULL, dst->pixman_image,
  119.                                           x + dx, y + dy,
  120.                                           0, 0,
  121.                                           x, y,
  122.                                           w, h);
  123.             }
  124.         }
  125.     }
  126.     return CAIRO_STATUS_SUCCESS;
  127. }
  128.  
  129. static inline uint32_t
  130. color_to_uint32 (const cairo_color_t *color)
  131. {
  132.     return
  133.         (color->alpha_short >> 8 << 24) |
  134.         (color->red_short >> 8 << 16)   |
  135.         (color->green_short & 0xff00)   |
  136.         (color->blue_short >> 8);
  137. }
  138.  
  139. static inline cairo_bool_t
  140. color_to_pixel (const cairo_color_t     *color,
  141.                 pixman_format_code_t     format,
  142.                 uint32_t                *pixel)
  143. {
  144.     uint32_t c;
  145.  
  146.     if (!(format == PIXMAN_a8r8g8b8     ||
  147.           format == PIXMAN_x8r8g8b8     ||
  148.           format == PIXMAN_a8b8g8r8     ||
  149.           format == PIXMAN_x8b8g8r8     ||
  150.           format == PIXMAN_b8g8r8a8     ||
  151.           format == PIXMAN_b8g8r8x8     ||
  152.           format == PIXMAN_r5g6b5       ||
  153.           format == PIXMAN_b5g6r5       ||
  154.           format == PIXMAN_a8))
  155.     {
  156.         return FALSE;
  157.     }
  158.  
  159.     c = color_to_uint32 (color);
  160.  
  161.     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
  162.         c = ((c & 0xff000000) >>  0) |
  163.             ((c & 0x00ff0000) >> 16) |
  164.             ((c & 0x0000ff00) >>  0) |
  165.             ((c & 0x000000ff) << 16);
  166.     }
  167.  
  168.     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
  169.         c = ((c & 0xff000000) >> 24) |
  170.             ((c & 0x00ff0000) >>  8) |
  171.             ((c & 0x0000ff00) <<  8) |
  172.             ((c & 0x000000ff) << 24);
  173.     }
  174.  
  175.     if (format == PIXMAN_a8) {
  176.         c = c >> 24;
  177.     } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
  178.         c = ((((c) >> 3) & 0x001f) |
  179.              (((c) >> 5) & 0x07e0) |
  180.              (((c) >> 8) & 0xf800));
  181.     }
  182.  
  183.     *pixel = c;
  184.     return TRUE;
  185. }
  186.  
  187. static pixman_op_t
  188. _pixman_operator (cairo_operator_t op)
  189. {
  190.     switch ((int) op) {
  191.     case CAIRO_OPERATOR_CLEAR:
  192.         return PIXMAN_OP_CLEAR;
  193.  
  194.     case CAIRO_OPERATOR_SOURCE:
  195.         return PIXMAN_OP_SRC;
  196.     case CAIRO_OPERATOR_OVER:
  197.         return PIXMAN_OP_OVER;
  198.     case CAIRO_OPERATOR_IN:
  199.         return PIXMAN_OP_IN;
  200.     case CAIRO_OPERATOR_OUT:
  201.         return PIXMAN_OP_OUT;
  202.     case CAIRO_OPERATOR_ATOP:
  203.         return PIXMAN_OP_ATOP;
  204.  
  205.     case CAIRO_OPERATOR_DEST:
  206.         return PIXMAN_OP_DST;
  207.     case CAIRO_OPERATOR_DEST_OVER:
  208.         return PIXMAN_OP_OVER_REVERSE;
  209.     case CAIRO_OPERATOR_DEST_IN:
  210.         return PIXMAN_OP_IN_REVERSE;
  211.     case CAIRO_OPERATOR_DEST_OUT:
  212.         return PIXMAN_OP_OUT_REVERSE;
  213.     case CAIRO_OPERATOR_DEST_ATOP:
  214.         return PIXMAN_OP_ATOP_REVERSE;
  215.  
  216.     case CAIRO_OPERATOR_XOR:
  217.         return PIXMAN_OP_XOR;
  218.     case CAIRO_OPERATOR_ADD:
  219.         return PIXMAN_OP_ADD;
  220.     case CAIRO_OPERATOR_SATURATE:
  221.         return PIXMAN_OP_SATURATE;
  222.  
  223.     case CAIRO_OPERATOR_MULTIPLY:
  224.         return PIXMAN_OP_MULTIPLY;
  225.     case CAIRO_OPERATOR_SCREEN:
  226.         return PIXMAN_OP_SCREEN;
  227.     case CAIRO_OPERATOR_OVERLAY:
  228.         return PIXMAN_OP_OVERLAY;
  229.     case CAIRO_OPERATOR_DARKEN:
  230.         return PIXMAN_OP_DARKEN;
  231.     case CAIRO_OPERATOR_LIGHTEN:
  232.         return PIXMAN_OP_LIGHTEN;
  233.     case CAIRO_OPERATOR_COLOR_DODGE:
  234.         return PIXMAN_OP_COLOR_DODGE;
  235.     case CAIRO_OPERATOR_COLOR_BURN:
  236.         return PIXMAN_OP_COLOR_BURN;
  237.     case CAIRO_OPERATOR_HARD_LIGHT:
  238.         return PIXMAN_OP_HARD_LIGHT;
  239.     case CAIRO_OPERATOR_SOFT_LIGHT:
  240.         return PIXMAN_OP_SOFT_LIGHT;
  241.     case CAIRO_OPERATOR_DIFFERENCE:
  242.         return PIXMAN_OP_DIFFERENCE;
  243.     case CAIRO_OPERATOR_EXCLUSION:
  244.         return PIXMAN_OP_EXCLUSION;
  245.     case CAIRO_OPERATOR_HSL_HUE:
  246.         return PIXMAN_OP_HSL_HUE;
  247.     case CAIRO_OPERATOR_HSL_SATURATION:
  248.         return PIXMAN_OP_HSL_SATURATION;
  249.     case CAIRO_OPERATOR_HSL_COLOR:
  250.         return PIXMAN_OP_HSL_COLOR;
  251.     case CAIRO_OPERATOR_HSL_LUMINOSITY:
  252.         return PIXMAN_OP_HSL_LUMINOSITY;
  253.  
  254.     default:
  255.         ASSERT_NOT_REACHED;
  256.         return PIXMAN_OP_OVER;
  257.     }
  258. }
  259.  
  260. static cairo_bool_t
  261. __fill_reduces_to_source (cairo_operator_t op,
  262.                           const cairo_color_t *color,
  263.                           const cairo_image_surface_t *dst)
  264. {
  265.     if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR)
  266.         return TRUE;
  267.     if (op == CAIRO_OPERATOR_OVER && CAIRO_COLOR_IS_OPAQUE (color))
  268.         return TRUE;
  269.     if (dst->base.is_clear)
  270.         return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
  271.  
  272.     return FALSE;
  273. }
  274.  
  275. static cairo_bool_t
  276. fill_reduces_to_source (cairo_operator_t op,
  277.                         const cairo_color_t *color,
  278.                         const cairo_image_surface_t *dst,
  279.                         uint32_t *pixel)
  280. {
  281.     if (__fill_reduces_to_source (op, color, dst)) {
  282.         color_to_pixel (color, dst->pixman_format, pixel);
  283.         return TRUE;
  284.     }
  285.  
  286.     return FALSE;
  287. }
  288.  
  289. static cairo_int_status_t
  290. fill_rectangles (void                   *_dst,
  291.                  cairo_operator_t        op,
  292.                  const cairo_color_t    *color,
  293.                  cairo_rectangle_int_t  *rects,
  294.                  int                     num_rects)
  295. {
  296.     cairo_image_surface_t *dst = _dst;
  297.     uint32_t pixel;
  298.     int i;
  299.  
  300.     TRACE ((stderr, "%s\n", __FUNCTION__));
  301.  
  302.     if (fill_reduces_to_source (op, color, dst, &pixel)) {
  303.         for (i = 0; i < num_rects; i++) {
  304.             pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
  305.                          PIXMAN_FORMAT_BPP (dst->pixman_format),
  306.                          rects[i].x, rects[i].y,
  307.                          rects[i].width, rects[i].height,
  308.                          pixel);
  309.         }
  310.     } else {
  311.         pixman_image_t *src = _pixman_image_for_color (color);
  312.  
  313.         op = _pixman_operator (op);
  314.         for (i = 0; i < num_rects; i++) {
  315.             pixman_image_composite32 (op,
  316.                                       src, NULL, dst->pixman_image,
  317.                                       0, 0,
  318.                                       0, 0,
  319.                                       rects[i].x, rects[i].y,
  320.                                       rects[i].width, rects[i].height);
  321.         }
  322.  
  323.         pixman_image_unref (src);
  324.     }
  325.  
  326.     return CAIRO_STATUS_SUCCESS;
  327. }
  328.  
  329. static cairo_int_status_t
  330. fill_boxes (void                *_dst,
  331.             cairo_operator_t     op,
  332.             const cairo_color_t *color,
  333.             cairo_boxes_t       *boxes)
  334. {
  335.     cairo_image_surface_t *dst = _dst;
  336.     struct _cairo_boxes_chunk *chunk;
  337.     uint32_t pixel;
  338.     int i;
  339.  
  340.     TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
  341.  
  342.     if (fill_reduces_to_source (op, color, dst, &pixel)) {
  343.         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  344.             for (i = 0; i < chunk->count; i++) {
  345.                 int x = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  346.                 int y = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  347.                 int w = _cairo_fixed_integer_part (chunk->base[i].p2.x) - x;
  348.                 int h = _cairo_fixed_integer_part (chunk->base[i].p2.y) - y;
  349.                 pixman_fill ((uint32_t *) dst->data,
  350.                              dst->stride / sizeof (uint32_t),
  351.                              PIXMAN_FORMAT_BPP (dst->pixman_format),
  352.                              x, y, w, h, pixel);
  353.             }
  354.         }
  355.     }
  356.     else
  357.     {
  358.         pixman_image_t *src = _pixman_image_for_color (color);
  359.  
  360.         op = _pixman_operator (op);
  361.         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  362.             for (i = 0; i < chunk->count; i++) {
  363.                 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  364.                 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  365.                 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  366.                 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  367.                 pixman_image_composite32 (op,
  368.                                           src, NULL, dst->pixman_image,
  369.                                           0, 0,
  370.                                           0, 0,
  371.                                           x1, y1,
  372.                                           x2-x1, y2-y1);
  373.             }
  374.         }
  375.  
  376.         pixman_image_unref (src);
  377.     }
  378.  
  379.     return CAIRO_STATUS_SUCCESS;
  380. }
  381.  
  382. static cairo_int_status_t
  383. composite (void                 *_dst,
  384.            cairo_operator_t     op,
  385.            cairo_surface_t      *abstract_src,
  386.            cairo_surface_t      *abstract_mask,
  387.            int                  src_x,
  388.            int                  src_y,
  389.            int                  mask_x,
  390.            int                  mask_y,
  391.            int                  dst_x,
  392.            int                  dst_y,
  393.            unsigned int         width,
  394.            unsigned int         height)
  395. {
  396.     cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
  397.     cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
  398.  
  399.     TRACE ((stderr, "%s\n", __FUNCTION__));
  400.  
  401.     if (mask) {
  402.         pixman_image_composite32 (_pixman_operator (op),
  403.                                   src->pixman_image, mask->pixman_image, to_pixman_image (_dst),
  404.                                   src_x, src_y,
  405.                                   mask_x, mask_y,
  406.                                   dst_x, dst_y,
  407.                                   width, height);
  408.     } else {
  409.         pixman_image_composite32 (_pixman_operator (op),
  410.                                   src->pixman_image, NULL, to_pixman_image (_dst),
  411.                                   src_x, src_y,
  412.                                   0, 0,
  413.                                   dst_x, dst_y,
  414.                                   width, height);
  415.     }
  416.  
  417.     return CAIRO_STATUS_SUCCESS;
  418. }
  419.  
  420. static cairo_int_status_t
  421. lerp (void                      *_dst,
  422.       cairo_surface_t           *abstract_src,
  423.       cairo_surface_t           *abstract_mask,
  424.       int                       src_x,
  425.       int                       src_y,
  426.       int                       mask_x,
  427.       int                       mask_y,
  428.       int                       dst_x,
  429.       int                       dst_y,
  430.       unsigned int              width,
  431.       unsigned int              height)
  432. {
  433.     cairo_image_surface_t *dst = _dst;
  434.     cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
  435.     cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
  436.  
  437.     TRACE ((stderr, "%s\n", __FUNCTION__));
  438.  
  439. #if PIXMAN_HAS_OP_LERP
  440.     pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
  441.                               src->pixman_image, mask->pixman_image, dst->pixman_image,
  442.                               src_x,  src_y,
  443.                               mask_x, mask_y,
  444.                               dst_x,  dst_y,
  445.                               width,  height);
  446. #else
  447.     /* Punch the clip out of the destination */
  448.     TRACE ((stderr, "%s - OUT_REVERSE (mask=%d/%p, dst=%d/%p)\n",
  449.             __FUNCTION__,
  450.             mask->base.unique_id, mask->pixman_image,
  451.             dst->base.unique_id, dst->pixman_image));
  452.     pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  453.                               mask->pixman_image, NULL, dst->pixman_image,
  454.                               mask_x, mask_y,
  455.                               0,      0,
  456.                               dst_x,  dst_y,
  457.                               width,  height);
  458.  
  459.     /* Now add the two results together */
  460.     TRACE ((stderr, "%s - ADD (src=%d/%p, mask=%d/%p, dst=%d/%p)\n",
  461.             __FUNCTION__,
  462.             src->base.unique_id, src->pixman_image,
  463.             mask->base.unique_id, mask->pixman_image,
  464.             dst->base.unique_id, dst->pixman_image));
  465.     pixman_image_composite32 (PIXMAN_OP_ADD,
  466.                               src->pixman_image, mask->pixman_image, dst->pixman_image,
  467.                               src_x,  src_y,
  468.                               mask_x, mask_y,
  469.                               dst_x,  dst_y,
  470.                               width,  height);
  471. #endif
  472.  
  473.     return CAIRO_STATUS_SUCCESS;
  474. }
  475.  
  476. static cairo_int_status_t
  477. composite_boxes (void                   *_dst,
  478.                  cairo_operator_t       op,
  479.                  cairo_surface_t        *abstract_src,
  480.                  cairo_surface_t        *abstract_mask,
  481.                  int                    src_x,
  482.                  int                    src_y,
  483.                  int                    mask_x,
  484.                  int                    mask_y,
  485.                  int                    dst_x,
  486.                  int                    dst_y,
  487.                  cairo_boxes_t          *boxes,
  488.                  const cairo_rectangle_int_t  *extents)
  489. {
  490.     pixman_image_t *dst = to_pixman_image (_dst);
  491.     pixman_image_t *src = ((cairo_image_source_t *)abstract_src)->pixman_image;
  492.     pixman_image_t *mask = abstract_mask ? ((cairo_image_source_t *)abstract_mask)->pixman_image : NULL;
  493.     pixman_image_t *free_src = NULL;
  494.     struct _cairo_boxes_chunk *chunk;
  495.     int i;
  496.  
  497.     /* XXX consider using a region? saves multiple prepare-composite */
  498.     TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
  499.  
  500.     if (((cairo_surface_t *)_dst)->is_clear &&
  501.         (op == CAIRO_OPERATOR_SOURCE ||
  502.          op == CAIRO_OPERATOR_OVER ||
  503.          op == CAIRO_OPERATOR_ADD)) {
  504.         op = PIXMAN_OP_SRC;
  505.     } else if (mask) {
  506.         if (op == CAIRO_OPERATOR_CLEAR) {
  507. #if PIXMAN_HAS_OP_LERP
  508.             op = PIXMAN_OP_LERP_CLEAR;
  509. #else
  510.             free_src = src = _pixman_image_for_color (CAIRO_COLOR_WHITE);
  511.             op = PIXMAN_OP_OUT_REVERSE;
  512. #endif
  513.         } else if (op == CAIRO_OPERATOR_SOURCE) {
  514. #if PIXMAN_HAS_OP_LERP
  515.             op = PIXMAN_OP_LERP_SRC;
  516. #else
  517.             return CAIRO_INT_STATUS_UNSUPPORTED;
  518. #endif
  519.         } else {
  520.             op = _pixman_operator (op);
  521.         }
  522.     } else {
  523.         op = _pixman_operator (op);
  524.     }
  525.  
  526.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  527.         for (i = 0; i < chunk->count; i++) {
  528.             int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
  529.             int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
  530.             int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
  531.             int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
  532.  
  533.             pixman_image_composite32 (op, src, mask, dst,
  534.                                       x1 + src_x, y1 + src_y,
  535.                                       x1 + mask_x, y1 + mask_y,
  536.                                       x1 + dst_x, y1 + dst_y,
  537.                                       x2 - x1, y2 - y1);
  538.         }
  539.     }
  540.  
  541.     if (free_src)
  542.         pixman_image_unref (free_src);
  543.  
  544.     return CAIRO_STATUS_SUCCESS;
  545. }
  546.  
  547. #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
  548. #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
  549.  
  550. static cairo_bool_t
  551. line_exceeds_16_16 (const cairo_line_t *line)
  552. {
  553.     return
  554.         line->p1.x <= CAIRO_FIXED_16_16_MIN ||
  555.         line->p1.x >= CAIRO_FIXED_16_16_MAX ||
  556.  
  557.         line->p2.x <= CAIRO_FIXED_16_16_MIN ||
  558.         line->p2.x >= CAIRO_FIXED_16_16_MAX ||
  559.  
  560.         line->p1.y <= CAIRO_FIXED_16_16_MIN ||
  561.         line->p1.y >= CAIRO_FIXED_16_16_MAX ||
  562.  
  563.         line->p2.y <= CAIRO_FIXED_16_16_MIN ||
  564.         line->p2.y >= CAIRO_FIXED_16_16_MAX;
  565. }
  566.  
  567. static void
  568. project_line_x_onto_16_16 (const cairo_line_t *line,
  569.                            cairo_fixed_t top,
  570.                            cairo_fixed_t bottom,
  571.                            pixman_line_fixed_t *out)
  572. {
  573.     /* XXX use fixed-point arithmetic? */
  574.     cairo_point_double_t p1, p2;
  575.     double m;
  576.  
  577.     p1.x = _cairo_fixed_to_double (line->p1.x);
  578.     p1.y = _cairo_fixed_to_double (line->p1.y);
  579.  
  580.     p2.x = _cairo_fixed_to_double (line->p2.x);
  581.     p2.y = _cairo_fixed_to_double (line->p2.y);
  582.  
  583.     m = (p2.x - p1.x) / (p2.y - p1.y);
  584.     out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
  585.     out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
  586. }
  587.  
  588. void
  589. _pixman_image_add_traps (pixman_image_t *image,
  590.                          int dst_x, int dst_y,
  591.                          cairo_traps_t *traps)
  592. {
  593.     cairo_trapezoid_t *t = traps->traps;
  594.     int num_traps = traps->num_traps;
  595.     while (num_traps--) {
  596.         pixman_trapezoid_t trap;
  597.  
  598.         /* top/bottom will be clamped to surface bounds */
  599.         trap.top = _cairo_fixed_to_16_16 (t->top);
  600.         trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
  601.  
  602.         /* However, all the other coordinates will have been left untouched so
  603.          * as not to introduce numerical error. Recompute them if they
  604.          * exceed the 16.16 limits.
  605.          */
  606.         if (unlikely (line_exceeds_16_16 (&t->left))) {
  607.             project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
  608.             trap.left.p1.y = trap.top;
  609.             trap.left.p2.y = trap.bottom;
  610.         } else {
  611.             trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
  612.             trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
  613.             trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
  614.             trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
  615.         }
  616.  
  617.         if (unlikely (line_exceeds_16_16 (&t->right))) {
  618.             project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
  619.             trap.right.p1.y = trap.top;
  620.             trap.right.p2.y = trap.bottom;
  621.         } else {
  622.             trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
  623.             trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
  624.             trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
  625.             trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
  626.         }
  627.  
  628.         pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
  629.         t++;
  630.     }
  631. }
  632.  
  633. static cairo_int_status_t
  634. composite_traps (void                   *_dst,
  635.                  cairo_operator_t       op,
  636.                  cairo_surface_t        *abstract_src,
  637.                  int                    src_x,
  638.                  int                    src_y,
  639.                  int                    dst_x,
  640.                  int                    dst_y,
  641.                  const cairo_rectangle_int_t *extents,
  642.                  cairo_antialias_t      antialias,
  643.                  cairo_traps_t          *traps)
  644. {
  645.     cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
  646.     cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
  647.     pixman_image_t *mask;
  648.     pixman_format_code_t format;
  649.  
  650.     TRACE ((stderr, "%s\n", __FUNCTION__));
  651.  
  652.     /* Special case adding trapezoids onto a mask surface; we want to avoid
  653.      * creating an intermediate temporary mask unnecessarily.
  654.      *
  655.      * We make the assumption here that the portion of the trapezoids
  656.      * contained within the surface is bounded by [dst_x,dst_y,width,height];
  657.      * the Cairo core code passes bounds based on the trapezoid extents.
  658.      */
  659.     format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
  660.     if (dst->pixman_format == format &&
  661.         (abstract_src == NULL ||
  662.          (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
  663.     {
  664.         _pixman_image_add_traps (dst->pixman_image, dst_x, dst_y, traps);
  665.         return CAIRO_STATUS_SUCCESS;
  666.     }
  667.  
  668.     mask = pixman_image_create_bits (format,
  669.                                      extents->width, extents->height,
  670.                                      NULL, 0);
  671.     if (unlikely (mask == NULL))
  672.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  673.  
  674.     _pixman_image_add_traps (mask, extents->x, extents->y, traps);
  675.     pixman_image_composite32 (_pixman_operator (op),
  676.                               src->pixman_image, mask, dst->pixman_image,
  677.                               extents->x + src_x, extents->y + src_y,
  678.                               0, 0,
  679.                               extents->x - dst_x, extents->y - dst_y,
  680.                               extents->width, extents->height);
  681.  
  682.     pixman_image_unref (mask);
  683.  
  684.     return  CAIRO_STATUS_SUCCESS;
  685. }
  686.  
  687. #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0)
  688. static void
  689. set_point (pixman_point_fixed_t *p, cairo_point_t *c)
  690. {
  691.     p->x = _cairo_fixed_to_16_16 (c->x);
  692.     p->y = _cairo_fixed_to_16_16 (c->y);
  693. }
  694.  
  695. void
  696. _pixman_image_add_tristrip (pixman_image_t *image,
  697.                             int dst_x, int dst_y,
  698.                             cairo_tristrip_t *strip)
  699. {
  700.     pixman_triangle_t tri;
  701.     pixman_point_fixed_t *p[3] = {&tri.p1, &tri.p2, &tri.p3 };
  702.     int n;
  703.  
  704.     set_point (p[0], &strip->points[0]);
  705.     set_point (p[1], &strip->points[1]);
  706.     set_point (p[2], &strip->points[2]);
  707.     pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
  708.     for (n = 3; n < strip->num_points; n++) {
  709.         set_point (p[n%3], &strip->points[n]);
  710.         pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
  711.     }
  712. }
  713.  
  714. static cairo_int_status_t
  715. composite_tristrip (void                        *_dst,
  716.                     cairo_operator_t    op,
  717.                     cairo_surface_t     *abstract_src,
  718.                     int                 src_x,
  719.                     int                 src_y,
  720.                     int                 dst_x,
  721.                     int                 dst_y,
  722.                     const cairo_rectangle_int_t *extents,
  723.                     cairo_antialias_t   antialias,
  724.                     cairo_tristrip_t    *strip)
  725. {
  726.     cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
  727.     cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
  728.     pixman_image_t *mask;
  729.     pixman_format_code_t format;
  730.  
  731.     TRACE ((stderr, "%s\n", __FUNCTION__));
  732.  
  733.     if (strip->num_points < 3)
  734.         return CAIRO_STATUS_SUCCESS;
  735.  
  736.     format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
  737.     if (dst->pixman_format == format &&
  738.         (abstract_src == NULL ||
  739.          (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
  740.     {
  741.         _pixman_image_add_tristrip (dst->pixman_image, dst_x, dst_y, strip);
  742.         return CAIRO_STATUS_SUCCESS;
  743.     }
  744.  
  745.     mask = pixman_image_create_bits (format,
  746.                                      extents->width, extents->height,
  747.                                      NULL, 0);
  748.     if (unlikely (mask == NULL))
  749.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  750.  
  751.     _pixman_image_add_tristrip (mask, extents->x, extents->y, strip);
  752.     pixman_image_composite32 (_pixman_operator (op),
  753.                               src->pixman_image, mask, dst->pixman_image,
  754.                               extents->x + src_x, extents->y + src_y,
  755.                               0, 0,
  756.                               extents->x - dst_x, extents->y - dst_y,
  757.                               extents->width, extents->height);
  758.  
  759.     pixman_image_unref (mask);
  760.  
  761.     return  CAIRO_STATUS_SUCCESS;
  762. }
  763. #endif
  764.  
  765. static cairo_int_status_t
  766. check_composite_glyphs (const cairo_composite_rectangles_t *extents,
  767.                         cairo_scaled_font_t *scaled_font,
  768.                         cairo_glyph_t *glyphs,
  769.                         int *num_glyphs)
  770. {
  771.     return CAIRO_STATUS_SUCCESS;
  772. }
  773.  
  774. #if HAS_PIXMAN_GLYPHS
  775. static pixman_glyph_cache_t *global_glyph_cache;
  776.  
  777. static inline pixman_glyph_cache_t *
  778. get_glyph_cache (void)
  779. {
  780.     if (!global_glyph_cache)
  781.         global_glyph_cache = pixman_glyph_cache_create ();
  782.  
  783.     return global_glyph_cache;
  784. }
  785.  
  786. void
  787. _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
  788.                                 cairo_scaled_glyph_t *scaled_glyph)
  789. {
  790.     CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
  791.  
  792.     if (global_glyph_cache) {
  793.         pixman_glyph_cache_remove (
  794.             global_glyph_cache, scaled_font,
  795.             (void *)_cairo_scaled_glyph_index (scaled_glyph));
  796.     }
  797.  
  798.     CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
  799. }
  800.  
  801. static cairo_int_status_t
  802. composite_glyphs (void                          *_dst,
  803.                   cairo_operator_t               op,
  804.                   cairo_surface_t               *_src,
  805.                   int                            src_x,
  806.                   int                            src_y,
  807.                   int                            dst_x,
  808.                   int                            dst_y,
  809.                   cairo_composite_glyphs_info_t *info)
  810. {
  811.     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
  812.     pixman_glyph_cache_t *glyph_cache;
  813.     pixman_glyph_t pglyphs_stack[CAIRO_STACK_ARRAY_LENGTH (pixman_glyph_t)];
  814.     pixman_glyph_t *pglyphs = pglyphs_stack;
  815.     pixman_glyph_t *pg;
  816.     int i;
  817.  
  818.     TRACE ((stderr, "%s\n", __FUNCTION__));
  819.  
  820.     CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
  821.  
  822.     glyph_cache = get_glyph_cache();
  823.     if (unlikely (glyph_cache == NULL)) {
  824.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  825.         goto out_unlock;
  826.     }
  827.  
  828.     pixman_glyph_cache_freeze (glyph_cache);
  829.  
  830.     if (info->num_glyphs > ARRAY_LENGTH (pglyphs_stack)) {
  831.         pglyphs = _cairo_malloc_ab (info->num_glyphs, sizeof (pixman_glyph_t));
  832.         if (unlikely (pglyphs == NULL)) {
  833.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  834.             goto out_thaw;
  835.         }
  836.     }
  837.  
  838.     pg = pglyphs;
  839.     for (i = 0; i < info->num_glyphs; i++) {
  840.         unsigned long index = info->glyphs[i].index;
  841.         const void *glyph;
  842.  
  843.         glyph = pixman_glyph_cache_lookup (glyph_cache, info->font, (void *)index);
  844.         if (!glyph) {
  845.             cairo_scaled_glyph_t *scaled_glyph;
  846.             cairo_image_surface_t *glyph_surface;
  847.  
  848.             /* This call can actually end up recursing, so we have to
  849.              * drop the mutex around it.
  850.              */
  851.             CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
  852.             status = _cairo_scaled_glyph_lookup (info->font, index,
  853.                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
  854.                                                  &scaled_glyph);
  855.             CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
  856.  
  857.             if (unlikely (status))
  858.                 goto out_thaw;
  859.  
  860.             glyph_surface = scaled_glyph->surface;
  861.             glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)index,
  862.                                                glyph_surface->base.device_transform.x0,
  863.                                                glyph_surface->base.device_transform.y0,
  864.                                                glyph_surface->pixman_image);
  865.             if (unlikely (!glyph)) {
  866.                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  867.                 goto out_thaw;
  868.             }
  869.         }
  870.  
  871.         pg->x = _cairo_lround (info->glyphs[i].x);
  872.         pg->y = _cairo_lround (info->glyphs[i].y);
  873.         pg->glyph = glyph;
  874.         pg++;
  875.     }
  876.  
  877.     if (info->use_mask) {
  878.         pixman_format_code_t mask_format;
  879.  
  880.         mask_format = pixman_glyph_get_mask_format (glyph_cache, pg - pglyphs, pglyphs);
  881.  
  882.         pixman_composite_glyphs (_pixman_operator (op),
  883.                                  ((cairo_image_source_t *)_src)->pixman_image,
  884.                                  to_pixman_image (_dst),
  885.                                  mask_format,
  886.                                  info->extents.x + src_x, info->extents.y + src_y,
  887.                                  info->extents.x, info->extents.y,
  888.                                  info->extents.x - dst_x, info->extents.y - dst_y,
  889.                                  info->extents.width, info->extents.height,
  890.                                  glyph_cache, pg - pglyphs, pglyphs);
  891.     } else {
  892.         pixman_composite_glyphs_no_mask (_pixman_operator (op),
  893.                                          ((cairo_image_source_t *)_src)->pixman_image,
  894.                                          to_pixman_image (_dst),
  895.                                          src_x, src_y,
  896.                                          - dst_x, - dst_y,
  897.                                          glyph_cache, pg - pglyphs, pglyphs);
  898.     }
  899.  
  900. out_thaw:
  901.     pixman_glyph_cache_thaw (glyph_cache);
  902.  
  903.     if (pglyphs != pglyphs_stack)
  904.         free(pglyphs);
  905.  
  906. out_unlock:
  907.     CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
  908.     return status;
  909. }
  910. #else
  911. void
  912. _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
  913.                                 cairo_scaled_glyph_t *scaled_glyph)
  914. {
  915. }
  916.  
  917. static cairo_int_status_t
  918. composite_one_glyph (void                               *_dst,
  919.                      cairo_operator_t                    op,
  920.                      cairo_surface_t                    *_src,
  921.                      int                                 src_x,
  922.                      int                                 src_y,
  923.                      int                                 dst_x,
  924.                      int                                 dst_y,
  925.                      cairo_composite_glyphs_info_t       *info)
  926. {
  927.     cairo_image_surface_t *glyph_surface;
  928.     cairo_scaled_glyph_t *scaled_glyph;
  929.     cairo_status_t status;
  930.     int x, y;
  931.  
  932.     TRACE ((stderr, "%s\n", __FUNCTION__));
  933.  
  934.     status = _cairo_scaled_glyph_lookup (info->font,
  935.                                          info->glyphs[0].index,
  936.                                          CAIRO_SCALED_GLYPH_INFO_SURFACE,
  937.                                          &scaled_glyph);
  938.  
  939.     if (unlikely (status))
  940.         return status;
  941.  
  942.     glyph_surface = scaled_glyph->surface;
  943.     if (glyph_surface->width == 0 || glyph_surface->height == 0)
  944.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  945.  
  946.     /* round glyph locations to the nearest pixel */
  947.     /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
  948.     x = _cairo_lround (info->glyphs[0].x -
  949.                        glyph_surface->base.device_transform.x0);
  950.     y = _cairo_lround (info->glyphs[0].y -
  951.                        glyph_surface->base.device_transform.y0);
  952.  
  953.     pixman_image_composite32 (_pixman_operator (op),
  954.                               ((cairo_image_source_t *)_src)->pixman_image,
  955.                               glyph_surface->pixman_image,
  956.                               to_pixman_image (_dst),
  957.                               x + src_x,  y + src_y,
  958.                               0, 0,
  959.                               x - dst_x, y - dst_y,
  960.                               glyph_surface->width,
  961.                               glyph_surface->height);
  962.  
  963.     return CAIRO_INT_STATUS_SUCCESS;
  964. }
  965.  
  966. static cairo_int_status_t
  967. composite_glyphs_via_mask (void                         *_dst,
  968.                            cairo_operator_t              op,
  969.                            cairo_surface_t              *_src,
  970.                            int                           src_x,
  971.                            int                           src_y,
  972.                            int                           dst_x,
  973.                            int                           dst_y,
  974.                            cairo_composite_glyphs_info_t *info)
  975. {
  976.     cairo_scaled_glyph_t *glyph_cache[64];
  977.     pixman_image_t *white = _pixman_image_for_color (CAIRO_COLOR_WHITE);
  978.     cairo_scaled_glyph_t *scaled_glyph;
  979.     uint8_t buf[2048];
  980.     pixman_image_t *mask;
  981.     pixman_format_code_t format;
  982.     cairo_status_t status;
  983.     int i;
  984.  
  985.     TRACE ((stderr, "%s\n", __FUNCTION__));
  986.  
  987.     if (unlikely (white == NULL))
  988.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  989.  
  990.     /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
  991.      * optimised paths through pixman. Should we increase the bit
  992.      * depth of the target surface, we should reconsider the appropriate
  993.      * mask formats.
  994.      */
  995.  
  996.     status = _cairo_scaled_glyph_lookup (info->font,
  997.                                          info->glyphs[0].index,
  998.                                          CAIRO_SCALED_GLYPH_INFO_SURFACE,
  999.                                          &scaled_glyph);
  1000.     if (unlikely (status)) {
  1001.         pixman_image_unref (white);
  1002.         return status;
  1003.     }
  1004.  
  1005.     memset (glyph_cache, 0, sizeof (glyph_cache));
  1006.     glyph_cache[info->glyphs[0].index % ARRAY_LENGTH (glyph_cache)] = scaled_glyph;
  1007.  
  1008.     format = PIXMAN_a8;
  1009.     i = (info->extents.width + 3) & ~3;
  1010.     if (scaled_glyph->surface->base.content & CAIRO_CONTENT_COLOR) {
  1011.         format = PIXMAN_a8r8g8b8;
  1012.         i = info->extents.width * 4;
  1013.     }
  1014.  
  1015.     if (i * info->extents.height > (int) sizeof (buf)) {
  1016.         mask = pixman_image_create_bits (format,
  1017.                                         info->extents.width,
  1018.                                         info->extents.height,
  1019.                                         NULL, 0);
  1020.     } else {
  1021.         memset (buf, 0, i * info->extents.height);
  1022.         mask = pixman_image_create_bits (format,
  1023.                                         info->extents.width,
  1024.                                         info->extents.height,
  1025.                                         (uint32_t *)buf, i);
  1026.     }
  1027.     if (unlikely (mask == NULL)) {
  1028.         pixman_image_unref (white);
  1029.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1030.     }
  1031.  
  1032.     status = CAIRO_STATUS_SUCCESS;
  1033.     for (i = 0; i < info->num_glyphs; i++) {
  1034.         unsigned long glyph_index = info->glyphs[i].index;
  1035.         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
  1036.         cairo_image_surface_t *glyph_surface;
  1037.         int x, y;
  1038.  
  1039.         scaled_glyph = glyph_cache[cache_index];
  1040.         if (scaled_glyph == NULL ||
  1041.             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
  1042.         {
  1043.             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
  1044.                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
  1045.                                                  &scaled_glyph);
  1046.  
  1047.             if (unlikely (status)) {
  1048.                 pixman_image_unref (mask);
  1049.                 pixman_image_unref (white);
  1050.                 return status;
  1051.             }
  1052.  
  1053.             glyph_cache[cache_index] = scaled_glyph;
  1054.         }
  1055.  
  1056.         glyph_surface = scaled_glyph->surface;
  1057.         if (glyph_surface->width && glyph_surface->height) {
  1058.             if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
  1059.                 format == PIXMAN_a8) {
  1060.                 pixman_image_t *ca_mask;
  1061.  
  1062.                 format = PIXMAN_a8r8g8b8;
  1063.                 ca_mask = pixman_image_create_bits (format,
  1064.                                                     info->extents.width,
  1065.                                                     info->extents.height,
  1066.                                                     NULL, 0);
  1067.                 if (unlikely (ca_mask == NULL)) {
  1068.                     pixman_image_unref (mask);
  1069.                     pixman_image_unref (white);
  1070.                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1071.                 }
  1072.  
  1073.                 pixman_image_composite32 (PIXMAN_OP_SRC,
  1074.                                           white, mask, ca_mask,
  1075.                                           0, 0,
  1076.                                           0, 0,
  1077.                                           0, 0,
  1078.                                           info->extents.width,
  1079.                                           info->extents.height);
  1080.                 pixman_image_unref (mask);
  1081.                 mask = ca_mask;
  1082.             }
  1083.  
  1084.             /* round glyph locations to the nearest pixel */
  1085.             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
  1086.             x = _cairo_lround (info->glyphs[i].x -
  1087.                                glyph_surface->base.device_transform.x0);
  1088.             y = _cairo_lround (info->glyphs[i].y -
  1089.                                glyph_surface->base.device_transform.y0);
  1090.  
  1091.             if (glyph_surface->pixman_format == format) {
  1092.                 pixman_image_composite32 (PIXMAN_OP_ADD,
  1093.                                           glyph_surface->pixman_image, NULL, mask,
  1094.                                           0, 0,
  1095.                                           0, 0,
  1096.                                           x - info->extents.x, y - info->extents.y,
  1097.                                           glyph_surface->width,
  1098.                                           glyph_surface->height);
  1099.             } else {
  1100.                 pixman_image_composite32 (PIXMAN_OP_ADD,
  1101.                                           white, glyph_surface->pixman_image, mask,
  1102.                                           0, 0,
  1103.                                           0, 0,
  1104.                                           x - info->extents.x, y - info->extents.y,
  1105.                                           glyph_surface->width,
  1106.                                           glyph_surface->height);
  1107.             }
  1108.         }
  1109.     }
  1110.  
  1111.     if (format == PIXMAN_a8r8g8b8)
  1112.         pixman_image_set_component_alpha (mask, TRUE);
  1113.  
  1114.     pixman_image_composite32 (_pixman_operator (op),
  1115.                               ((cairo_image_source_t *)_src)->pixman_image,
  1116.                               mask,
  1117.                               to_pixman_image (_dst),
  1118.                               info->extents.x + src_x, info->extents.y + src_y,
  1119.                               0, 0,
  1120.                               info->extents.x - dst_x, info->extents.y - dst_y,
  1121.                               info->extents.width, info->extents.height);
  1122.     pixman_image_unref (mask);
  1123.     pixman_image_unref (white);
  1124.  
  1125.     return CAIRO_STATUS_SUCCESS;
  1126. }
  1127.  
  1128. static cairo_int_status_t
  1129. composite_glyphs (void                          *_dst,
  1130.                   cairo_operator_t               op,
  1131.                   cairo_surface_t               *_src,
  1132.                   int                            src_x,
  1133.                   int                            src_y,
  1134.                   int                            dst_x,
  1135.                   int                            dst_y,
  1136.                   cairo_composite_glyphs_info_t *info)
  1137. {
  1138.     cairo_scaled_glyph_t *glyph_cache[64];
  1139.     pixman_image_t *dst, *src;
  1140.     cairo_status_t status;
  1141.     int i;
  1142.  
  1143.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1144.  
  1145.     if (info->num_glyphs == 1)
  1146.         return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
  1147.  
  1148.     if (info->use_mask)
  1149.         return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
  1150.  
  1151.     op = _pixman_operator (op);
  1152.     dst = to_pixman_image (_dst);
  1153.     src = ((cairo_image_source_t *)_src)->pixman_image;
  1154.  
  1155.     memset (glyph_cache, 0, sizeof (glyph_cache));
  1156.     status = CAIRO_STATUS_SUCCESS;
  1157.  
  1158.     for (i = 0; i < info->num_glyphs; i++) {
  1159.         int x, y;
  1160.         cairo_image_surface_t *glyph_surface;
  1161.         cairo_scaled_glyph_t *scaled_glyph;
  1162.         unsigned long glyph_index = info->glyphs[i].index;
  1163.         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
  1164.  
  1165.         scaled_glyph = glyph_cache[cache_index];
  1166.         if (scaled_glyph == NULL ||
  1167.             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
  1168.         {
  1169.             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
  1170.                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
  1171.                                                  &scaled_glyph);
  1172.  
  1173.             if (unlikely (status))
  1174.                 break;
  1175.  
  1176.             glyph_cache[cache_index] = scaled_glyph;
  1177.         }
  1178.  
  1179.         glyph_surface = scaled_glyph->surface;
  1180.         if (glyph_surface->width && glyph_surface->height) {
  1181.             /* round glyph locations to the nearest pixel */
  1182.             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
  1183.             x = _cairo_lround (info->glyphs[i].x -
  1184.                                glyph_surface->base.device_transform.x0);
  1185.             y = _cairo_lround (info->glyphs[i].y -
  1186.                                glyph_surface->base.device_transform.y0);
  1187.  
  1188.             pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
  1189.                                       x + src_x,  y + src_y,
  1190.                                       0, 0,
  1191.                                       x - dst_x, y - dst_y,
  1192.                                       glyph_surface->width,
  1193.                                       glyph_surface->height);
  1194.         }
  1195.     }
  1196.  
  1197.     return status;
  1198. }
  1199. #endif
  1200.  
  1201. static cairo_int_status_t
  1202. check_composite (const cairo_composite_rectangles_t *extents)
  1203. {
  1204.     return CAIRO_STATUS_SUCCESS;
  1205. }
  1206.  
  1207. const cairo_compositor_t *
  1208. _cairo_image_traps_compositor_get (void)
  1209. {
  1210.     static cairo_traps_compositor_t compositor;
  1211.  
  1212.     if (compositor.base.delegate == NULL) {
  1213.         _cairo_traps_compositor_init (&compositor,
  1214.                                       &__cairo_no_compositor);
  1215.         compositor.acquire = acquire;
  1216.         compositor.release = release;
  1217.         compositor.set_clip_region = set_clip_region;
  1218.         compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
  1219.         compositor.draw_image_boxes = draw_image_boxes;
  1220.         //compositor.copy_boxes = copy_boxes;
  1221.         compositor.fill_boxes = fill_boxes;
  1222.         compositor.check_composite = check_composite;
  1223.         compositor.composite = composite;
  1224.         compositor.lerp = lerp;
  1225.         //compositor.check_composite_boxes = check_composite_boxes;
  1226.         compositor.composite_boxes = composite_boxes;
  1227.         //compositor.check_composite_traps = check_composite_traps;
  1228.         compositor.composite_traps = composite_traps;
  1229.         //compositor.check_composite_tristrip = check_composite_traps;
  1230. #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,22,0)
  1231.         compositor.composite_tristrip = composite_tristrip;
  1232. #endif
  1233.         compositor.check_composite_glyphs = check_composite_glyphs;
  1234.         compositor.composite_glyphs = composite_glyphs;
  1235.     }
  1236.  
  1237.     return &compositor.base;
  1238. }
  1239.  
  1240. const cairo_compositor_t *
  1241. _cairo_image_mask_compositor_get (void)
  1242. {
  1243.     static cairo_mask_compositor_t compositor;
  1244.  
  1245.     if (compositor.base.delegate == NULL) {
  1246.         _cairo_mask_compositor_init (&compositor,
  1247.                                      _cairo_image_traps_compositor_get ());
  1248.         compositor.acquire = acquire;
  1249.         compositor.release = release;
  1250.         compositor.set_clip_region = set_clip_region;
  1251.         compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
  1252.         compositor.draw_image_boxes = draw_image_boxes;
  1253.         compositor.fill_rectangles = fill_rectangles;
  1254.         compositor.fill_boxes = fill_boxes;
  1255.         //compositor.check_composite = check_composite;
  1256.         compositor.composite = composite;
  1257.         //compositor.lerp = lerp;
  1258.         //compositor.check_composite_boxes = check_composite_boxes;
  1259.         compositor.composite_boxes = composite_boxes;
  1260.         compositor.check_composite_glyphs = check_composite_glyphs;
  1261.         compositor.composite_glyphs = composite_glyphs;
  1262.     }
  1263.  
  1264.     return &compositor.base;
  1265. }
  1266.  
  1267. #if PIXMAN_HAS_COMPOSITOR
  1268. typedef struct _cairo_image_span_renderer {
  1269.     cairo_span_renderer_t base;
  1270.  
  1271.     pixman_image_compositor_t *compositor;
  1272.     pixman_image_t *src, *mask;
  1273.     float opacity;
  1274.     cairo_rectangle_int_t extents;
  1275. } cairo_image_span_renderer_t;
  1276. COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
  1277.  
  1278. static cairo_status_t
  1279. _cairo_image_bounded_opaque_spans (void *abstract_renderer,
  1280.                                    int y, int height,
  1281.                                    const cairo_half_open_span_t *spans,
  1282.                                    unsigned num_spans)
  1283. {
  1284.     cairo_image_span_renderer_t *r = abstract_renderer;
  1285.  
  1286.     if (num_spans == 0)
  1287.         return CAIRO_STATUS_SUCCESS;
  1288.  
  1289.     do {
  1290.         if (spans[0].coverage)
  1291.             pixman_image_compositor_blt (r->compositor,
  1292.                                          spans[0].x, y,
  1293.                                          spans[1].x - spans[0].x, height,
  1294.                                          spans[0].coverage);
  1295.         spans++;
  1296.     } while (--num_spans > 1);
  1297.  
  1298.     return CAIRO_STATUS_SUCCESS;
  1299. }
  1300.  
  1301. static cairo_status_t
  1302. _cairo_image_bounded_spans (void *abstract_renderer,
  1303.                             int y, int height,
  1304.                             const cairo_half_open_span_t *spans,
  1305.                             unsigned num_spans)
  1306. {
  1307.     cairo_image_span_renderer_t *r = abstract_renderer;
  1308.  
  1309.     if (num_spans == 0)
  1310.         return CAIRO_STATUS_SUCCESS;
  1311.  
  1312.     do {
  1313.         if (spans[0].coverage) {
  1314.             pixman_image_compositor_blt (r->compositor,
  1315.                                          spans[0].x, y,
  1316.                                          spans[1].x - spans[0].x, height,
  1317.                                          r->opacity * spans[0].coverage);
  1318.         }
  1319.         spans++;
  1320.     } while (--num_spans > 1);
  1321.  
  1322.     return CAIRO_STATUS_SUCCESS;
  1323. }
  1324.  
  1325. static cairo_status_t
  1326. _cairo_image_unbounded_spans (void *abstract_renderer,
  1327.                               int y, int height,
  1328.                               const cairo_half_open_span_t *spans,
  1329.                               unsigned num_spans)
  1330. {
  1331.     cairo_image_span_renderer_t *r = abstract_renderer;
  1332.  
  1333.     assert (y + height <= r->extents.height);
  1334.     if (y > r->extents.y) {
  1335.         pixman_image_compositor_blt (r->compositor,
  1336.                                      r->extents.x, r->extents.y,
  1337.                                      r->extents.width, y - r->extents.y,
  1338.                                      0);
  1339.     }
  1340.  
  1341.     if (num_spans == 0) {
  1342.         pixman_image_compositor_blt (r->compositor,
  1343.                                      r->extents.x, y,
  1344.                                      r->extents.width,  height,
  1345.                                      0);
  1346.     } else {
  1347.         if (spans[0].x != r->extents.x) {
  1348.             pixman_image_compositor_blt (r->compositor,
  1349.                                          r->extents.x, y,
  1350.                                          spans[0].x - r->extents.x,
  1351.                                          height,
  1352.                                          0);
  1353.         }
  1354.  
  1355.         do {
  1356.             assert (spans[0].x < r->extents.x + r->extents.width);
  1357.             pixman_image_compositor_blt (r->compositor,
  1358.                                          spans[0].x, y,
  1359.                                          spans[1].x - spans[0].x, height,
  1360.                                          r->opacity * spans[0].coverage);
  1361.             spans++;
  1362.         } while (--num_spans > 1);
  1363.  
  1364.         if (spans[0].x != r->extents.x + r->extents.width) {
  1365.             assert (spans[0].x < r->extents.x + r->extents.width);
  1366.             pixman_image_compositor_blt (r->compositor,
  1367.                                          spans[0].x,     y,
  1368.                                          r->extents.x + r->extents.width - spans[0].x, height,
  1369.                                          0);
  1370.         }
  1371.     }
  1372.  
  1373.     r->extents.y = y + height;
  1374.     return CAIRO_STATUS_SUCCESS;
  1375. }
  1376.  
  1377. static cairo_status_t
  1378. _cairo_image_clipped_spans (void *abstract_renderer,
  1379.                             int y, int height,
  1380.                             const cairo_half_open_span_t *spans,
  1381.                             unsigned num_spans)
  1382. {
  1383.     cairo_image_span_renderer_t *r = abstract_renderer;
  1384.  
  1385.     assert (num_spans);
  1386.  
  1387.     do {
  1388.         if (! spans[0].inverse)
  1389.             pixman_image_compositor_blt (r->compositor,
  1390.                                          spans[0].x, y,
  1391.                                          spans[1].x - spans[0].x, height,
  1392.                                          r->opacity * spans[0].coverage);
  1393.         spans++;
  1394.     } while (--num_spans > 1);
  1395.  
  1396.     r->extents.y = y + height;
  1397.     return CAIRO_STATUS_SUCCESS;
  1398. }
  1399.  
  1400. static cairo_status_t
  1401. _cairo_image_finish_unbounded_spans (void *abstract_renderer)
  1402. {
  1403.     cairo_image_span_renderer_t *r = abstract_renderer;
  1404.  
  1405.     if (r->extents.y < r->extents.height) {
  1406.         pixman_image_compositor_blt (r->compositor,
  1407.                                      r->extents.x, r->extents.y,
  1408.                                      r->extents.width,
  1409.                                      r->extents.height - r->extents.y,
  1410.                                      0);
  1411.     }
  1412.  
  1413.     return CAIRO_STATUS_SUCCESS;
  1414. }
  1415.  
  1416. static cairo_int_status_t
  1417. span_renderer_init (cairo_abstract_span_renderer_t      *_r,
  1418.                     const cairo_composite_rectangles_t *composite,
  1419.                     cairo_bool_t                         needs_clip)
  1420. {
  1421.     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
  1422.     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
  1423.     const cairo_pattern_t *source = &composite->source_pattern.base;
  1424.     cairo_operator_t op = composite->op;
  1425.     int src_x, src_y;
  1426.     int mask_x, mask_y;
  1427.  
  1428.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1429.  
  1430.     if (op == CAIRO_OPERATOR_CLEAR) {
  1431.         op = PIXMAN_OP_LERP_CLEAR;
  1432.     } else if (dst->base.is_clear &&
  1433.                (op == CAIRO_OPERATOR_SOURCE ||
  1434.                 op == CAIRO_OPERATOR_OVER ||
  1435.                 op == CAIRO_OPERATOR_ADD)) {
  1436.         op = PIXMAN_OP_SRC;
  1437.     } else if (op == CAIRO_OPERATOR_SOURCE) {
  1438.         op = PIXMAN_OP_LERP_SRC;
  1439.     } else {
  1440.         op = _pixman_operator (op);
  1441.     }
  1442.  
  1443.     r->compositor = NULL;
  1444.     r->mask = NULL;
  1445.     r->src = _pixman_image_for_pattern (dst, source, FALSE,
  1446.                                         &composite->unbounded,
  1447.                                         &composite->source_sample_area,
  1448.                                         &src_x, &src_y);
  1449.     if (unlikely (r->src == NULL))
  1450.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1451.  
  1452.     r->opacity = 1.0;
  1453.     if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
  1454.         r->opacity = composite->mask_pattern.solid.color.alpha;
  1455.     } else {
  1456.         r->mask = _pixman_image_for_pattern (dst,
  1457.                                              &composite->mask_pattern.base,
  1458.                                              TRUE,
  1459.                                              &composite->unbounded,
  1460.                                              &composite->mask_sample_area,
  1461.                                              &mask_x, &mask_y);
  1462.         if (unlikely (r->mask == NULL))
  1463.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1464.  
  1465.         /* XXX Component-alpha? */
  1466.         if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
  1467.             _cairo_pattern_is_opaque (source, &composite->source_sample_area))
  1468.         {
  1469.             pixman_image_unref (r->src);
  1470.             r->src = r->mask;
  1471.             src_x = mask_x;
  1472.             src_y = mask_y;
  1473.             r->mask = NULL;
  1474.         }
  1475.     }
  1476.  
  1477.     if (composite->is_bounded) {
  1478.         if (r->opacity == 1.)
  1479.             r->base.render_rows = _cairo_image_bounded_opaque_spans;
  1480.         else
  1481.             r->base.render_rows = _cairo_image_bounded_spans;
  1482.         r->base.finish = NULL;
  1483.     } else {
  1484.         if (needs_clip)
  1485.             r->base.render_rows = _cairo_image_clipped_spans;
  1486.         else
  1487.             r->base.render_rows = _cairo_image_unbounded_spans;
  1488.         r->base.finish = _cairo_image_finish_unbounded_spans;
  1489.         r->extents = composite->unbounded;
  1490.         r->extents.height += r->extents.y;
  1491.     }
  1492.  
  1493.     r->compositor =
  1494.         pixman_image_create_compositor (op, r->src, r->mask, dst->pixman_image,
  1495.                                         composite->unbounded.x + src_x,
  1496.                                         composite->unbounded.y + src_y,
  1497.                                         composite->unbounded.x + mask_x,
  1498.                                         composite->unbounded.y + mask_y,
  1499.                                         composite->unbounded.x,
  1500.                                         composite->unbounded.y,
  1501.                                         composite->unbounded.width,
  1502.                                         composite->unbounded.height);
  1503.     if (unlikely (r->compositor == NULL))
  1504.         return CAIRO_INT_STATUS_NOTHING_TO_DO;
  1505.  
  1506.     return CAIRO_STATUS_SUCCESS;
  1507. }
  1508.  
  1509. static void
  1510. span_renderer_fini (cairo_abstract_span_renderer_t *_r,
  1511.                     cairo_int_status_t status)
  1512. {
  1513.     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
  1514.  
  1515.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1516.  
  1517.     if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish)
  1518.         r->base.finish (r);
  1519.  
  1520.     if (r->compositor)
  1521.         pixman_image_compositor_destroy (r->compositor);
  1522.  
  1523.     if (r->src)
  1524.         pixman_image_unref (r->src);
  1525.     if (r->mask)
  1526.         pixman_image_unref (r->mask);
  1527. }
  1528. #else
  1529. typedef struct _cairo_image_span_renderer {
  1530.     cairo_span_renderer_t base;
  1531.  
  1532.     const cairo_composite_rectangles_t *composite;
  1533.  
  1534.     float opacity;
  1535.     uint8_t op;
  1536.     int bpp;
  1537.  
  1538.     pixman_image_t *src, *mask;
  1539.     union {
  1540.         struct fill {
  1541.             int stride;
  1542.             uint8_t *data;
  1543.             uint32_t pixel;
  1544.         } fill;
  1545.         struct blit {
  1546.             int stride;
  1547.             uint8_t *data;
  1548.             int src_stride;
  1549.             uint8_t *src_data;
  1550.         } blit;
  1551.         struct composite {
  1552.             pixman_image_t *dst;
  1553.             int src_x, src_y;
  1554.             int mask_x, mask_y;
  1555.             int run_length;
  1556.         } composite;
  1557.         struct finish {
  1558.             cairo_rectangle_int_t extents;
  1559.             int src_x, src_y;
  1560.             int stride;
  1561.             uint8_t *data;
  1562.         } mask;
  1563.     } u;
  1564.     uint8_t _buf[0];
  1565. #define SZ_BUF (int)(sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t))
  1566. } cairo_image_span_renderer_t;
  1567. COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
  1568.  
  1569. static cairo_status_t
  1570. _cairo_image_spans (void *abstract_renderer,
  1571.                     int y, int height,
  1572.                     const cairo_half_open_span_t *spans,
  1573.                     unsigned num_spans)
  1574. {
  1575.     cairo_image_span_renderer_t *r = abstract_renderer;
  1576.     uint8_t *mask, *row;
  1577.     int len;
  1578.  
  1579.     if (num_spans == 0)
  1580.         return CAIRO_STATUS_SUCCESS;
  1581.  
  1582.     mask = r->u.mask.data + (y - r->u.mask.extents.y) * r->u.mask.stride;
  1583.     mask += spans[0].x - r->u.mask.extents.x;
  1584.     row = mask;
  1585.  
  1586.     do {
  1587.         len = spans[1].x - spans[0].x;
  1588.         if (spans[0].coverage) {
  1589.             *row++ = r->opacity * spans[0].coverage;
  1590.             if (--len)
  1591.                 memset (row, row[-1], len);
  1592.         }
  1593.         row += len;
  1594.         spans++;
  1595.     } while (--num_spans > 1);
  1596.  
  1597.     len = row - mask;
  1598.     row = mask;
  1599.     while (--height) {
  1600.         mask += r->u.mask.stride;
  1601.         memcpy (mask, row, len);
  1602.     }
  1603.  
  1604.     return CAIRO_STATUS_SUCCESS;
  1605. }
  1606.  
  1607. static cairo_status_t
  1608. _cairo_image_spans_and_zero (void *abstract_renderer,
  1609.                              int y, int height,
  1610.                              const cairo_half_open_span_t *spans,
  1611.                              unsigned num_spans)
  1612. {
  1613.     cairo_image_span_renderer_t *r = abstract_renderer;
  1614.     uint8_t *mask;
  1615.     int len;
  1616.  
  1617.     mask = r->u.mask.data;
  1618.     if (y > r->u.mask.extents.y) {
  1619.         len = (y - r->u.mask.extents.y) * r->u.mask.stride;
  1620.         memset (mask, 0, len);
  1621.         mask += len;
  1622.     }
  1623.  
  1624.     r->u.mask.extents.y = y + height;
  1625.     r->u.mask.data = mask + height * r->u.mask.stride;
  1626.     if (num_spans == 0) {
  1627.         memset (mask, 0, height * r->u.mask.stride);
  1628.     } else {
  1629.         uint8_t *row = mask;
  1630.  
  1631.         if (spans[0].x != r->u.mask.extents.x) {
  1632.             len = spans[0].x - r->u.mask.extents.x;
  1633.             memset (row, 0, len);
  1634.             row += len;
  1635.         }
  1636.  
  1637.         do {
  1638.             len = spans[1].x - spans[0].x;
  1639.             *row++ = r->opacity * spans[0].coverage;
  1640.             if (len > 1) {
  1641.                 memset (row, row[-1], --len);
  1642.                 row += len;
  1643.             }
  1644.             spans++;
  1645.         } while (--num_spans > 1);
  1646.  
  1647.         if (spans[0].x != r->u.mask.extents.x + r->u.mask.extents.width) {
  1648.             len = r->u.mask.extents.x + r->u.mask.extents.width - spans[0].x;
  1649.             memset (row, 0, len);
  1650.         }
  1651.  
  1652.         row = mask;
  1653.         while (--height) {
  1654.             mask += r->u.mask.stride;
  1655.             memcpy (mask, row, r->u.mask.extents.width);
  1656.         }
  1657.     }
  1658.  
  1659.     return CAIRO_STATUS_SUCCESS;
  1660. }
  1661.  
  1662. static cairo_status_t
  1663. _cairo_image_finish_spans_and_zero (void *abstract_renderer)
  1664. {
  1665.     cairo_image_span_renderer_t *r = abstract_renderer;
  1666.  
  1667.     if (r->u.mask.extents.y < r->u.mask.extents.height)
  1668.         memset (r->u.mask.data, 0, (r->u.mask.extents.height - r->u.mask.extents.y) * r->u.mask.stride);
  1669.  
  1670.     return CAIRO_STATUS_SUCCESS;
  1671. }
  1672.  
  1673. static cairo_status_t
  1674. _fill8_spans (void *abstract_renderer, int y, int h,
  1675.                const cairo_half_open_span_t *spans, unsigned num_spans)
  1676. {
  1677.     cairo_image_span_renderer_t *r = abstract_renderer;
  1678.  
  1679.     if (num_spans == 0)
  1680.         return CAIRO_STATUS_SUCCESS;
  1681.  
  1682.     if (likely(h == 1)) {
  1683.         do {
  1684.             if (spans[0].coverage) {
  1685.                 int len = spans[1].x - spans[0].x;
  1686.                 uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
  1687.                 if (len == 1)
  1688.                     *d = r->u.fill.pixel;
  1689.                 else
  1690.                     memset(d, r->u.fill.pixel, len);
  1691.             }
  1692.             spans++;
  1693.         } while (--num_spans > 1);
  1694.     } else {
  1695.         do {
  1696.             if (spans[0].coverage) {
  1697.                 int yy = y, hh = h;
  1698.                 do {
  1699.                     int len = spans[1].x - spans[0].x;
  1700.                     uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
  1701.                     if (len == 1)
  1702.                         *d = r->u.fill.pixel;
  1703.                     else
  1704.                         memset(d, r->u.fill.pixel, len);
  1705.                     yy++;
  1706.                 } while (--hh);
  1707.             }
  1708.             spans++;
  1709.         } while (--num_spans > 1);
  1710.     }
  1711.  
  1712.     return CAIRO_STATUS_SUCCESS;
  1713. }
  1714.  
  1715. static cairo_status_t
  1716. _fill16_spans (void *abstract_renderer, int y, int h,
  1717.                const cairo_half_open_span_t *spans, unsigned num_spans)
  1718. {
  1719.     cairo_image_span_renderer_t *r = abstract_renderer;
  1720.  
  1721.     if (num_spans == 0)
  1722.         return CAIRO_STATUS_SUCCESS;
  1723.  
  1724.     if (likely(h == 1)) {
  1725.         do {
  1726.             if (spans[0].coverage) {
  1727.                 int len = spans[1].x - spans[0].x;
  1728.                 uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*2);
  1729.                 while (len--)
  1730.                     *d++ = r->u.fill.pixel;
  1731.             }
  1732.             spans++;
  1733.         } while (--num_spans > 1);
  1734.     } else {
  1735.         do {
  1736.             if (spans[0].coverage) {
  1737.                 int yy = y, hh = h;
  1738.                 do {
  1739.                     int len = spans[1].x - spans[0].x;
  1740.                     uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*2);
  1741.                     while (len--)
  1742.                         *d++ = r->u.fill.pixel;
  1743.                     yy++;
  1744.                 } while (--hh);
  1745.             }
  1746.             spans++;
  1747.         } while (--num_spans > 1);
  1748.     }
  1749.  
  1750.     return CAIRO_STATUS_SUCCESS;
  1751. }
  1752.  
  1753. static cairo_status_t
  1754. _fill32_spans (void *abstract_renderer, int y, int h,
  1755.                const cairo_half_open_span_t *spans, unsigned num_spans)
  1756. {
  1757.     cairo_image_span_renderer_t *r = abstract_renderer;
  1758.  
  1759.     if (num_spans == 0)
  1760.         return CAIRO_STATUS_SUCCESS;
  1761.  
  1762.     if (likely(h == 1)) {
  1763.         do {
  1764.             if (spans[0].coverage) {
  1765.                 int len = spans[1].x - spans[0].x;
  1766.                 if (len > 32) {
  1767.                     pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
  1768.                                  spans[0].x, y, len, 1, r->u.fill.pixel);
  1769.                 } else {
  1770.                     uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
  1771.                     while (len--)
  1772.                         *d++ = r->u.fill.pixel;
  1773.                 }
  1774.             }
  1775.             spans++;
  1776.         } while (--num_spans > 1);
  1777.     } else {
  1778.         do {
  1779.             if (spans[0].coverage) {
  1780.                 if (spans[1].x - spans[0].x > 16) {
  1781.                     pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
  1782.                                  spans[0].x, y, spans[1].x - spans[0].x, h,
  1783.                                  r->u.fill.pixel);
  1784.                 } else {
  1785.                     int yy = y, hh = h;
  1786.                     do {
  1787.                         int len = spans[1].x - spans[0].x;
  1788.                         uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
  1789.                         while (len--)
  1790.                             *d++ = r->u.fill.pixel;
  1791.                         yy++;
  1792.                     } while (--hh);
  1793.                 }
  1794.             }
  1795.             spans++;
  1796.         } while (--num_spans > 1);
  1797.     }
  1798.  
  1799.     return CAIRO_STATUS_SUCCESS;
  1800. }
  1801.  
  1802. #if 0
  1803. static cairo_status_t
  1804. _fill_spans (void *abstract_renderer, int y, int h,
  1805.              const cairo_half_open_span_t *spans, unsigned num_spans)
  1806. {
  1807.     cairo_image_span_renderer_t *r = abstract_renderer;
  1808.  
  1809.     if (num_spans == 0)
  1810.         return CAIRO_STATUS_SUCCESS;
  1811.  
  1812.     do {
  1813.         if (spans[0].coverage) {
  1814.                 pixman_fill ((uint32_t *) r->data, r->stride, r->bpp,
  1815.                              spans[0].x, y,
  1816.                              spans[1].x - spans[0].x, h,
  1817.                              r->pixel);
  1818.         }
  1819.         spans++;
  1820.     } while (--num_spans > 1);
  1821.  
  1822.     return CAIRO_STATUS_SUCCESS;
  1823. }
  1824. #endif
  1825.  
  1826. static cairo_status_t
  1827. _blit_spans (void *abstract_renderer, int y, int h,
  1828.              const cairo_half_open_span_t *spans, unsigned num_spans)
  1829. {
  1830.     cairo_image_span_renderer_t *r = abstract_renderer;
  1831.     int cpp;
  1832.  
  1833.     if (num_spans == 0)
  1834.         return CAIRO_STATUS_SUCCESS;
  1835.  
  1836.     cpp = r->bpp/8;
  1837.     if (likely (h == 1)) {
  1838.         uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
  1839.         uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
  1840.         do {
  1841.             if (spans[0].coverage) {
  1842.                 void *s = src + spans[0].x*cpp;
  1843.                 void *d = dst + spans[0].x*cpp;
  1844.                 int len = (spans[1].x - spans[0].x) * cpp;
  1845.                 switch (len) {
  1846.                 case 1:
  1847.                     *(uint8_t *)d = *(uint8_t *)s;
  1848.                     break;
  1849.                 case 2:
  1850.                     *(uint16_t *)d = *(uint16_t *)s;
  1851.                     break;
  1852.                 case 4:
  1853.                     *(uint32_t *)d = *(uint32_t *)s;
  1854.                     break;
  1855. #if HAVE_UINT64_T
  1856.                 case 8:
  1857.                     *(uint64_t *)d = *(uint64_t *)s;
  1858.                     break;
  1859. #endif
  1860.                 default:
  1861.                     memcpy(d, s, len);
  1862.                     break;
  1863.                 }
  1864.             }
  1865.             spans++;
  1866.         } while (--num_spans > 1);
  1867.     } else {
  1868.         do {
  1869.             if (spans[0].coverage) {
  1870.                 int yy = y, hh = h;
  1871.                 do {
  1872.                     void *src = r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x*cpp;
  1873.                     void *dst = r->u.blit.data + yy*r->u.blit.stride + spans[0].x*cpp;
  1874.                     int len = (spans[1].x - spans[0].x) * cpp;
  1875.                     switch (len) {
  1876.                     case 1:
  1877.                         *(uint8_t *)dst = *(uint8_t *)src;
  1878.                         break;
  1879.                     case 2:
  1880.                         *(uint16_t *)dst = *(uint16_t *)src;
  1881.                         break;
  1882.                     case 4:
  1883.                         *(uint32_t *)dst = *(uint32_t *)src;
  1884.                         break;
  1885. #if HAVE_UINT64_T
  1886.                     case 8:
  1887.                         *(uint64_t *)dst = *(uint64_t *)src;
  1888.                         break;
  1889. #endif
  1890.                     default:
  1891.                         memcpy(dst, src, len);
  1892.                         break;
  1893.                     }
  1894.                     yy++;
  1895.                 } while (--hh);
  1896.             }
  1897.             spans++;
  1898.         } while (--num_spans > 1);
  1899.     }
  1900.  
  1901.     return CAIRO_STATUS_SUCCESS;
  1902. }
  1903.  
  1904. static cairo_status_t
  1905. _mono_spans (void *abstract_renderer, int y, int h,
  1906.              const cairo_half_open_span_t *spans, unsigned num_spans)
  1907. {
  1908.     cairo_image_span_renderer_t *r = abstract_renderer;
  1909.  
  1910.     if (num_spans == 0)
  1911.         return CAIRO_STATUS_SUCCESS;
  1912.  
  1913.     do {
  1914.         if (spans[0].coverage) {
  1915.             pixman_image_composite32 (r->op,
  1916.                                       r->src, NULL, r->u.composite.dst,
  1917.                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
  1918.                                       0, 0,
  1919.                                       spans[0].x, y,
  1920.                                       spans[1].x - spans[0].x, h);
  1921.         }
  1922.         spans++;
  1923.     } while (--num_spans > 1);
  1924.  
  1925.     return CAIRO_STATUS_SUCCESS;
  1926. }
  1927.  
  1928. static cairo_status_t
  1929. _mono_unbounded_spans (void *abstract_renderer, int y, int h,
  1930.                        const cairo_half_open_span_t *spans, unsigned num_spans)
  1931. {
  1932.     cairo_image_span_renderer_t *r = abstract_renderer;
  1933.  
  1934.     if (num_spans == 0) {
  1935.         pixman_image_composite32 (PIXMAN_OP_CLEAR,
  1936.                                   r->src, NULL, r->u.composite.dst,
  1937.                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
  1938.                                   0, 0,
  1939.                                   r->composite->unbounded.x, y,
  1940.                                   r->composite->unbounded.width, h);
  1941.         r->u.composite.mask_y = y + h;
  1942.         return CAIRO_STATUS_SUCCESS;
  1943.     }
  1944.  
  1945.     if (y != r->u.composite.mask_y) {
  1946.         pixman_image_composite32 (PIXMAN_OP_CLEAR,
  1947.                                   r->src, NULL, r->u.composite.dst,
  1948.                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
  1949.                                   0, 0,
  1950.                                   r->composite->unbounded.x, r->u.composite.mask_y,
  1951.                                   r->composite->unbounded.width, y - r->u.composite.mask_y);
  1952.     }
  1953.  
  1954.     if (spans[0].x != r->composite->unbounded.x) {
  1955.             pixman_image_composite32 (PIXMAN_OP_CLEAR,
  1956.                                       r->src, NULL, r->u.composite.dst,
  1957.                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
  1958.                                       0, 0,
  1959.                                       r->composite->unbounded.x, y,
  1960.                                       spans[0].x - r->composite->unbounded.x, h);
  1961.     }
  1962.  
  1963.     do {
  1964.         int op = spans[0].coverage ? r->op : PIXMAN_OP_CLEAR;
  1965.         pixman_image_composite32 (op,
  1966.                                   r->src, NULL, r->u.composite.dst,
  1967.                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
  1968.                                   0, 0,
  1969.                                   spans[0].x, y,
  1970.                                   spans[1].x - spans[0].x, h);
  1971.         spans++;
  1972.     } while (--num_spans > 1);
  1973.  
  1974.     if (spans[0].x != r->composite->unbounded.x + r->composite->unbounded.width) {
  1975.             pixman_image_composite32 (PIXMAN_OP_CLEAR,
  1976.                                       r->src, NULL, r->u.composite.dst,
  1977.                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
  1978.                                       0, 0,
  1979.                                       spans[0].x, y,
  1980.                                       r->composite->unbounded.x + r->composite->unbounded.width - spans[0].x, h);
  1981.     }
  1982.  
  1983.     r->u.composite.mask_y = y + h;
  1984.     return CAIRO_STATUS_SUCCESS;
  1985. }
  1986.  
  1987. static cairo_status_t
  1988. _mono_finish_unbounded_spans (void *abstract_renderer)
  1989. {
  1990.     cairo_image_span_renderer_t *r = abstract_renderer;
  1991.  
  1992.     if (r->u.composite.mask_y < r->composite->unbounded.y + r->composite->unbounded.height) {
  1993.         pixman_image_composite32 (PIXMAN_OP_CLEAR,
  1994.                                   r->src, NULL, r->u.composite.dst,
  1995.                                   r->composite->unbounded.x + r->u.composite.src_x,  r->u.composite.mask_y + r->u.composite.src_y,
  1996.                                   0, 0,
  1997.                                   r->composite->unbounded.x, r->u.composite.mask_y,
  1998.                                   r->composite->unbounded.width,
  1999.                                   r->composite->unbounded.y + r->composite->unbounded.height - r->u.composite.mask_y);
  2000.     }
  2001.  
  2002.     return CAIRO_STATUS_SUCCESS;
  2003. }
  2004.  
  2005. static cairo_int_status_t
  2006. mono_renderer_init (cairo_image_span_renderer_t *r,
  2007.                     const cairo_composite_rectangles_t *composite,
  2008.                     cairo_antialias_t                    antialias,
  2009.                     cairo_bool_t                         needs_clip)
  2010. {
  2011.     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
  2012.  
  2013.     if (antialias != CAIRO_ANTIALIAS_NONE)
  2014.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2015.  
  2016.     if (!_cairo_pattern_is_opaque_solid (&composite->mask_pattern.base))
  2017.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2018.  
  2019.     r->base.render_rows = NULL;
  2020.     if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
  2021.         const cairo_color_t *color;
  2022.  
  2023.         color = &composite->source_pattern.solid.color;
  2024.         if (composite->op == CAIRO_OPERATOR_CLEAR)
  2025.             color = CAIRO_COLOR_TRANSPARENT;
  2026.  
  2027.         if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) {
  2028.             /* Use plain C for the fill operations as the span length is
  2029.              * typically small, too small to payback the startup overheads of
  2030.              * using SSE2 etc.
  2031.              */
  2032.             switch (PIXMAN_FORMAT_BPP(dst->pixman_format)) {
  2033.             case 8: r->base.render_rows = _fill8_spans; break;
  2034.             case 16: r->base.render_rows = _fill16_spans; break;
  2035.             case 32: r->base.render_rows = _fill32_spans; break;
  2036.             default: break;
  2037.             }
  2038.             r->u.fill.data = dst->data;
  2039.             r->u.fill.stride = dst->stride;
  2040.         }
  2041.     } else if ((composite->op == CAIRO_OPERATOR_SOURCE ||
  2042.                 (composite->op == CAIRO_OPERATOR_OVER &&
  2043.                  (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
  2044.                composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
  2045.                composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
  2046.                to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
  2047.     {
  2048.        cairo_image_surface_t *src =
  2049.            to_image_surface(composite->source_pattern.surface.surface);
  2050.        int tx, ty;
  2051.  
  2052.         if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
  2053.                                                  &tx, &ty) &&
  2054.             composite->bounded.x + tx >= 0 &&
  2055.             composite->bounded.y + ty >= 0 &&
  2056.             composite->bounded.x + composite->bounded.width +  tx <= src->width &&
  2057.             composite->bounded.y + composite->bounded.height + ty <= src->height) {
  2058.  
  2059.             r->u.blit.stride = dst->stride;
  2060.             r->u.blit.data = dst->data;
  2061.             r->u.blit.src_stride = src->stride;
  2062.             r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
  2063.             r->base.render_rows = _blit_spans;
  2064.         }
  2065.     }
  2066.  
  2067.     if (r->base.render_rows == NULL) {
  2068.         r->src = _pixman_image_for_pattern (dst, &composite->source_pattern.base, FALSE,
  2069.                                             &composite->unbounded,
  2070.                                             &composite->source_sample_area,
  2071.                                             &r->u.composite.src_x, &r->u.composite.src_y);
  2072.         if (unlikely (r->src == NULL))
  2073.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  2074.  
  2075.         r->u.composite.dst = to_pixman_image (composite->surface);
  2076.         r->op = _pixman_operator (composite->op);
  2077.         if (composite->is_bounded == 0) {
  2078.             r->base.render_rows = _mono_unbounded_spans;
  2079.             r->base.finish = _mono_finish_unbounded_spans;
  2080.             r->u.composite.mask_y = composite->unbounded.y;
  2081.         } else
  2082.             r->base.render_rows = _mono_spans;
  2083.     }
  2084.     r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
  2085.  
  2086.     return CAIRO_INT_STATUS_SUCCESS;
  2087. }
  2088.  
  2089. #define ONE_HALF 0x7f
  2090. #define RB_MASK 0x00ff00ff
  2091. #define RB_ONE_HALF 0x007f007f
  2092. #define RB_MASK_PLUS_ONE 0x01000100
  2093. #define G_SHIFT 8
  2094. static inline uint32_t
  2095. mul8x2_8 (uint32_t a, uint8_t b)
  2096. {
  2097.     uint32_t t = (a & RB_MASK) * b + RB_ONE_HALF;
  2098.     return ((t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT) & RB_MASK;
  2099. }
  2100.  
  2101. static inline uint32_t
  2102. add8x2_8x2 (uint32_t a, uint32_t b)
  2103. {
  2104.     uint32_t t = a + b;
  2105.     t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK);
  2106.     return t & RB_MASK;
  2107. }
  2108.  
  2109. static inline uint8_t
  2110. mul8_8 (uint8_t a, uint8_t b)
  2111. {
  2112.     uint16_t t = a * (uint16_t)b + ONE_HALF;
  2113.     return ((t >> G_SHIFT) + t) >> G_SHIFT;
  2114. }
  2115.  
  2116. static inline uint32_t
  2117. lerp8x4 (uint32_t src, uint8_t a, uint32_t dst)
  2118. {
  2119.     return (add8x2_8x2 (mul8x2_8 (src, a),
  2120.                         mul8x2_8 (dst, ~a)) |
  2121.             add8x2_8x2 (mul8x2_8 (src >> G_SHIFT, a),
  2122.                         mul8x2_8 (dst >> G_SHIFT, ~a)) << G_SHIFT);
  2123. }
  2124.  
  2125. static cairo_status_t
  2126. _fill_a8_lerp_opaque_spans (void *abstract_renderer, int y, int h,
  2127.                             const cairo_half_open_span_t *spans, unsigned num_spans)
  2128. {
  2129.     cairo_image_span_renderer_t *r = abstract_renderer;
  2130.  
  2131.     if (num_spans == 0)
  2132.         return CAIRO_STATUS_SUCCESS;
  2133.  
  2134.     if (likely(h == 1)) {
  2135.         uint8_t *d = r->u.fill.data + r->u.fill.stride*y;
  2136.         do {
  2137.             uint8_t a = spans[0].coverage;
  2138.             if (a) {
  2139.                 int len = spans[1].x - spans[0].x;
  2140.                 if (a == 0xff) {
  2141.                     memset(d + spans[0].x, r->u.fill.pixel, len);
  2142.                 } else {
  2143.                     uint8_t s = mul8_8(a, r->u.fill.pixel);
  2144.                     uint8_t *dst = d + spans[0].x;
  2145.                     a = ~a;
  2146.                     while (len--) {
  2147.                         uint8_t t = mul8_8(*dst, a);
  2148.                         *dst++ = t + s;
  2149.                     }
  2150.                 }
  2151.             }
  2152.             spans++;
  2153.         } while (--num_spans > 1);
  2154.     } else {
  2155.         do {
  2156.             uint8_t a = spans[0].coverage;
  2157.             if (a) {
  2158.                 int yy = y, hh = h;
  2159.                 if (a == 0xff) {
  2160.                     do {
  2161.                         int len = spans[1].x - spans[0].x;
  2162.                         uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
  2163.                         memset(d, r->u.fill.pixel, len);
  2164.                         yy++;
  2165.                     } while (--hh);
  2166.                 } else {
  2167.                     uint8_t s = mul8_8(a, r->u.fill.pixel);
  2168.                     a = ~a;
  2169.                     do {
  2170.                         int len = spans[1].x - spans[0].x;
  2171.                         uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
  2172.                         while (len--) {
  2173.                             uint8_t t = mul8_8(*d, a);
  2174.                             *d++ = t + s;
  2175.                         }
  2176.                         yy++;
  2177.                     } while (--hh);
  2178.                 }
  2179.             }
  2180.             spans++;
  2181.         } while (--num_spans > 1);
  2182.     }
  2183.  
  2184.     return CAIRO_STATUS_SUCCESS;
  2185. }
  2186.  
  2187. static cairo_status_t
  2188. _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
  2189.                                 const cairo_half_open_span_t *spans, unsigned num_spans)
  2190. {
  2191.     cairo_image_span_renderer_t *r = abstract_renderer;
  2192.  
  2193.     if (num_spans == 0)
  2194.         return CAIRO_STATUS_SUCCESS;
  2195.  
  2196.     if (likely(h == 1)) {
  2197.         do {
  2198.             uint8_t a = spans[0].coverage;
  2199.             if (a) {
  2200.                 int len = spans[1].x - spans[0].x;
  2201.                 uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
  2202.                 if (a == 0xff) {
  2203.                     if (len > 31) {
  2204.                         pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
  2205.                                      spans[0].x, y, len, 1, r->u.fill.pixel);
  2206.                     } else {
  2207.                         uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
  2208.                         while (len--)
  2209.                             *d++ = r->u.fill.pixel;
  2210.                     }
  2211.                 } else while (len--) {
  2212.                     *d = lerp8x4 (r->u.fill.pixel, a, *d);
  2213.                     d++;
  2214.                 }
  2215.             }
  2216.             spans++;
  2217.         } while (--num_spans > 1);
  2218.     } else {
  2219.         do {
  2220.             uint8_t a = spans[0].coverage;
  2221.             if (a) {
  2222.                 if (a == 0xff) {
  2223.                     if (spans[1].x - spans[0].x > 16) {
  2224.                         pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
  2225.                                      spans[0].x, y, spans[1].x - spans[0].x, h,
  2226.                                      r->u.fill.pixel);
  2227.                     } else {
  2228.                         int yy = y, hh = h;
  2229.                         do {
  2230.                             int len = spans[1].x - spans[0].x;
  2231.                             uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
  2232.                             while (len--)
  2233.                                 *d++ = r->u.fill.pixel;
  2234.                             yy++;
  2235.                         } while (--hh);
  2236.                     }
  2237.                 } else {
  2238.                     int yy = y, hh = h;
  2239.                     do {
  2240.                         int len = spans[1].x - spans[0].x;
  2241.                         uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
  2242.                         while (len--) {
  2243.                             *d = lerp8x4 (r->u.fill.pixel, a, *d);
  2244.                             d++;
  2245.                         }
  2246.                         yy++;
  2247.                     } while (--hh);
  2248.                 }
  2249.             }
  2250.             spans++;
  2251.         } while (--num_spans > 1);
  2252.     }
  2253.  
  2254.     return CAIRO_STATUS_SUCCESS;
  2255. }
  2256.  
  2257. static cairo_status_t
  2258. _fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
  2259.                      const cairo_half_open_span_t *spans, unsigned num_spans)
  2260. {
  2261.     cairo_image_span_renderer_t *r = abstract_renderer;
  2262.  
  2263.     if (num_spans == 0)
  2264.         return CAIRO_STATUS_SUCCESS;
  2265.  
  2266.     if (likely(h == 1)) {
  2267.         do {
  2268.             uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
  2269.             if (a) {
  2270.                 int len = spans[1].x - spans[0].x;
  2271.                 uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
  2272.                 uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
  2273.                 uint16_t ia = ~a;
  2274.                 while (len--) {
  2275.                     uint16_t t = *d*ia + p;
  2276.                     *d++ = (t + (t>>8)) >> 8;
  2277.                 }
  2278.             }
  2279.             spans++;
  2280.         } while (--num_spans > 1);
  2281.     } else {
  2282.         do {
  2283.             uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
  2284.             if (a) {
  2285.                 int yy = y, hh = h;
  2286.                 uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
  2287.                 uint16_t ia = ~a;
  2288.                 do {
  2289.                     int len = spans[1].x - spans[0].x;
  2290.                     uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
  2291.                     while (len--) {
  2292.                         uint16_t t = *d*ia + p;
  2293.                         *d++ = (t + (t>>8)) >> 8;
  2294.                     }
  2295.                     yy++;
  2296.                 } while (--hh);
  2297.             }
  2298.             spans++;
  2299.         } while (--num_spans > 1);
  2300.     }
  2301.  
  2302.     return CAIRO_STATUS_SUCCESS;
  2303. }
  2304.  
  2305. static cairo_status_t
  2306. _fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
  2307.                          const cairo_half_open_span_t *spans, unsigned num_spans)
  2308. {
  2309.     cairo_image_span_renderer_t *r = abstract_renderer;
  2310.  
  2311.     if (num_spans == 0)
  2312.         return CAIRO_STATUS_SUCCESS;
  2313.  
  2314.     if (likely(h == 1)) {
  2315.         do {
  2316.             uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
  2317.             if (a) {
  2318.                 int len = spans[1].x - spans[0].x;
  2319.                 uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
  2320.                 while (len--) {
  2321.                     *d = lerp8x4 (r->u.fill.pixel, a, *d);
  2322.                     d++;
  2323.                 }
  2324.             }
  2325.             spans++;
  2326.         } while (--num_spans > 1);
  2327.     } else {
  2328.         do {
  2329.             uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
  2330.             if (a) {
  2331.                 int yy = y, hh = h;
  2332.                 do {
  2333.                     int len = spans[1].x - spans[0].x;
  2334.                     uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
  2335.                     while (len--) {
  2336.                         *d = lerp8x4 (r->u.fill.pixel, a, *d);
  2337.                         d++;
  2338.                     }
  2339.                     yy++;
  2340.                 } while (--hh);
  2341.             }
  2342.             spans++;
  2343.         } while (--num_spans > 1);
  2344.     }
  2345.  
  2346.     return CAIRO_STATUS_SUCCESS;
  2347. }
  2348.  
  2349. static cairo_status_t
  2350. _blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
  2351.                          const cairo_half_open_span_t *spans, unsigned num_spans)
  2352. {
  2353.     cairo_image_span_renderer_t *r = abstract_renderer;
  2354.  
  2355.     if (num_spans == 0)
  2356.         return CAIRO_STATUS_SUCCESS;
  2357.  
  2358.     if (likely(h == 1)) {
  2359.         uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
  2360.         uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
  2361.         do {
  2362.             uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
  2363.             if (a) {
  2364.                 uint32_t *s = (uint32_t*)src + spans[0].x;
  2365.                 uint32_t *d = (uint32_t*)dst + spans[0].x;
  2366.                 int len = spans[1].x - spans[0].x;
  2367.                 if (a == 0xff) {
  2368.                     if (len == 1)
  2369.                         *d = *s;
  2370.                     else
  2371.                         memcpy(d, s, len*4);
  2372.                 } else {
  2373.                     while (len--) {
  2374.                         *d = lerp8x4 (*s, a, *d);
  2375.                         s++, d++;
  2376.                     }
  2377.                 }
  2378.             }
  2379.             spans++;
  2380.         } while (--num_spans > 1);
  2381.     } else {
  2382.         do {
  2383.             uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
  2384.             if (a) {
  2385.                 int yy = y, hh = h;
  2386.                 do {
  2387.                     uint32_t *s = (uint32_t *)(r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x * 4);
  2388.                     uint32_t *d = (uint32_t *)(r->u.blit.data + yy*r->u.blit.stride + spans[0].x * 4);
  2389.                     int len = spans[1].x - spans[0].x;
  2390.                     if (a == 0xff) {
  2391.                         if (len == 1)
  2392.                             *d = *s;
  2393.                         else
  2394.                             memcpy(d, s, len * 4);
  2395.                     } else {
  2396.                         while (len--) {
  2397.                             *d = lerp8x4 (*s, a, *d);
  2398.                             s++, d++;
  2399.                         }
  2400.                     }
  2401.                     yy++;
  2402.                 } while (--hh);
  2403.             }
  2404.             spans++;
  2405.         } while (--num_spans > 1);
  2406.     }
  2407.  
  2408.     return CAIRO_STATUS_SUCCESS;
  2409. }
  2410.  
  2411. static cairo_status_t
  2412. _inplace_spans (void *abstract_renderer,
  2413.                 int y, int h,
  2414.                 const cairo_half_open_span_t *spans,
  2415.                 unsigned num_spans)
  2416. {
  2417.     cairo_image_span_renderer_t *r = abstract_renderer;
  2418.     uint8_t *mask;
  2419.     int x0, x1;
  2420.  
  2421.     if (num_spans == 0)
  2422.         return CAIRO_STATUS_SUCCESS;
  2423.  
  2424.     if (num_spans == 2 && spans[0].coverage == 0xff) {
  2425.         pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
  2426.                                   spans[0].x + r->u.composite.src_x,
  2427.                                   y + r->u.composite.src_y,
  2428.                                   0, 0,
  2429.                                   spans[0].x, y,
  2430.                                   spans[1].x - spans[0].x, h);
  2431.         return CAIRO_STATUS_SUCCESS;
  2432.     }
  2433.  
  2434.     mask = (uint8_t *)pixman_image_get_data (r->mask);
  2435.     x1 = x0 = spans[0].x;
  2436.     do {
  2437.         int len = spans[1].x - spans[0].x;
  2438.         *mask++ = spans[0].coverage;
  2439.         if (len > 1) {
  2440.             if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
  2441.                 if (x1 != x0) {
  2442.                     pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
  2443.                                               x0 + r->u.composite.src_x,
  2444.                                               y + r->u.composite.src_y,
  2445.                                               0, 0,
  2446.                                               x0, y,
  2447.                                               x1 - x0, h);
  2448.                 }
  2449.                 pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
  2450.                                           spans[0].x + r->u.composite.src_x,
  2451.                                           y + r->u.composite.src_y,
  2452.                                           0, 0,
  2453.                                           spans[0].x, y,
  2454.                                           len, h);
  2455.                 mask = (uint8_t *)pixman_image_get_data (r->mask);
  2456.                 x0 = spans[1].x;
  2457.             } else if (spans[0].coverage == 0x0 &&
  2458.                        x1 - x0 > r->u.composite.run_length) {
  2459.                 pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
  2460.                                           x0 + r->u.composite.src_x,
  2461.                                           y + r->u.composite.src_y,
  2462.                                           0, 0,
  2463.                                           x0, y,
  2464.                                           x1 - x0, h);
  2465.                 mask = (uint8_t *)pixman_image_get_data (r->mask);
  2466.                 x0 = spans[1].x;
  2467.             }else {
  2468.                 memset (mask, spans[0].coverage, --len);
  2469.                 mask += len;
  2470.             }
  2471.         }
  2472.         x1 = spans[1].x;
  2473.         spans++;
  2474.     } while (--num_spans > 1);
  2475.  
  2476.     if (x1 != x0) {
  2477.         pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
  2478.                                   x0 + r->u.composite.src_x,
  2479.                                   y + r->u.composite.src_y,
  2480.                                   0, 0,
  2481.                                   x0, y,
  2482.                                   x1 - x0, h);
  2483.     }
  2484.  
  2485.     return CAIRO_STATUS_SUCCESS;
  2486. }
  2487.  
  2488. static cairo_status_t
  2489. _inplace_opacity_spans (void *abstract_renderer, int y, int h,
  2490.                         const cairo_half_open_span_t *spans,
  2491.                         unsigned num_spans)
  2492. {
  2493.     cairo_image_span_renderer_t *r = abstract_renderer;
  2494.     uint8_t *mask;
  2495.     int x0, x1;
  2496.  
  2497.     if (num_spans == 0)
  2498.         return CAIRO_STATUS_SUCCESS;
  2499.  
  2500.     mask = (uint8_t *)pixman_image_get_data (r->mask);
  2501.     x1 = x0 = spans[0].x;
  2502.     do {
  2503.         int len = spans[1].x - spans[0].x;
  2504.         uint8_t m = mul8_8(spans[0].coverage, r->bpp);
  2505.         *mask++ = m;
  2506.         if (len > 1) {
  2507.             if (m == 0 &&
  2508.                 x1 - x0 > r->u.composite.run_length) {
  2509.                 pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
  2510.                                           x0 + r->u.composite.src_x,
  2511.                                           y + r->u.composite.src_y,
  2512.                                           0, 0,
  2513.                                           x0, y,
  2514.                                           x1 - x0, h);
  2515.                 mask = (uint8_t *)pixman_image_get_data (r->mask);
  2516.                 x0 = spans[1].x;
  2517.             }else {
  2518.                 memset (mask, m, --len);
  2519.                 mask += len;
  2520.             }
  2521.         }
  2522.         x1 = spans[1].x;
  2523.         spans++;
  2524.     } while (--num_spans > 1);
  2525.  
  2526.     if (x1 != x0) {
  2527.         pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
  2528.                                   x0 + r->u.composite.src_x,
  2529.                                   y + r->u.composite.src_y,
  2530.                                   0, 0,
  2531.                                   x0, y,
  2532.                                   x1 - x0, h);
  2533.     }
  2534.  
  2535.     return CAIRO_STATUS_SUCCESS;
  2536. }
  2537.  
  2538. static cairo_status_t
  2539. _inplace_src_spans (void *abstract_renderer, int y, int h,
  2540.                     const cairo_half_open_span_t *spans,
  2541.                     unsigned num_spans)
  2542. {
  2543.     cairo_image_span_renderer_t *r = abstract_renderer;
  2544.     uint8_t *m;
  2545.     int x0;
  2546.  
  2547.     if (num_spans == 0)
  2548.         return CAIRO_STATUS_SUCCESS;
  2549.  
  2550.     x0 = spans[0].x;
  2551.     m = r->_buf;
  2552.     do {
  2553.         int len = spans[1].x - spans[0].x;
  2554.         if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
  2555.             if (spans[0].x != x0) {
  2556. #if PIXMAN_HAS_OP_LERP
  2557.                 pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
  2558.                                           r->src, r->mask, r->u.composite.dst,
  2559.                                           x0 + r->u.composite.src_x,
  2560.                                           y + r->u.composite.src_y,
  2561.                                           0, 0,
  2562.                                           x0, y,
  2563.                                           spans[0].x - x0, h);
  2564. #else
  2565.                 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  2566.                                           r->mask, NULL, r->u.composite.dst,
  2567.                                           0, 0,
  2568.                                           0, 0,
  2569.                                           x0, y,
  2570.                                           spans[0].x - x0, h);
  2571.                 pixman_image_composite32 (PIXMAN_OP_ADD,
  2572.                                           r->src, r->mask, r->u.composite.dst,
  2573.                                           x0 + r->u.composite.src_x,
  2574.                                           y + r->u.composite.src_y,
  2575.                                           0, 0,
  2576.                                           x0, y,
  2577.                                           spans[0].x - x0, h);
  2578. #endif
  2579.             }
  2580.  
  2581.             pixman_image_composite32 (PIXMAN_OP_SRC,
  2582.                                       r->src, NULL, r->u.composite.dst,
  2583.                                       spans[0].x + r->u.composite.src_x,
  2584.                                       y + r->u.composite.src_y,
  2585.                                       0, 0,
  2586.                                       spans[0].x, y,
  2587.                                       spans[1].x - spans[0].x, h);
  2588.  
  2589.             m = r->_buf;
  2590.             x0 = spans[1].x;
  2591.         } else if (spans[0].coverage == 0x0) {
  2592.             if (spans[0].x != x0) {
  2593. #if PIXMAN_HAS_OP_LERP
  2594.                 pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
  2595.                                           r->src, r->mask, r->u.composite.dst,
  2596.                                           x0 + r->u.composite.src_x,
  2597.                                           y + r->u.composite.src_y,
  2598.                                           0, 0,
  2599.                                           x0, y,
  2600.                                           spans[0].x - x0, h);
  2601. #else
  2602.                 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  2603.                                           r->mask, NULL, r->u.composite.dst,
  2604.                                           0, 0,
  2605.                                           0, 0,
  2606.                                           x0, y,
  2607.                                           spans[0].x - x0, h);
  2608.                 pixman_image_composite32 (PIXMAN_OP_ADD,
  2609.                                           r->src, r->mask, r->u.composite.dst,
  2610.                                           x0 + r->u.composite.src_x,
  2611.                                           y + r->u.composite.src_y,
  2612.                                           0, 0,
  2613.                                           x0, y,
  2614.                                           spans[0].x - x0, h);
  2615. #endif
  2616.             }
  2617.  
  2618.             m = r->_buf;
  2619.             x0 = spans[1].x;
  2620.         } else {
  2621.             *m++ = spans[0].coverage;
  2622.             if (len > 1) {
  2623.                 memset (m, spans[0].coverage, --len);
  2624.                 m += len;
  2625.             }
  2626.         }
  2627.         spans++;
  2628.     } while (--num_spans > 1);
  2629.  
  2630.     if (spans[0].x != x0) {
  2631. #if PIXMAN_HAS_OP_LERP
  2632.         pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
  2633.                                   r->src, r->mask, r->u.composite.dst,
  2634.                                   x0 + r->u.composite.src_x,
  2635.                                   y + r->u.composite.src_y,
  2636.                                   0, 0,
  2637.                                   x0, y,
  2638.                                   spans[0].x - x0, h);
  2639. #else
  2640.         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  2641.                                   r->mask, NULL, r->u.composite.dst,
  2642.                                   0, 0,
  2643.                                   0, 0,
  2644.                                   x0, y,
  2645.                                   spans[0].x - x0, h);
  2646.         pixman_image_composite32 (PIXMAN_OP_ADD,
  2647.                                   r->src, r->mask, r->u.composite.dst,
  2648.                                   x0 + r->u.composite.src_x,
  2649.                                   y + r->u.composite.src_y,
  2650.                                   0, 0,
  2651.                                   x0, y,
  2652.                                   spans[0].x - x0, h);
  2653. #endif
  2654.     }
  2655.  
  2656.     return CAIRO_STATUS_SUCCESS;
  2657. }
  2658.  
  2659. static cairo_status_t
  2660. _inplace_src_opacity_spans (void *abstract_renderer, int y, int h,
  2661.                             const cairo_half_open_span_t *spans,
  2662.                             unsigned num_spans)
  2663. {
  2664.     cairo_image_span_renderer_t *r = abstract_renderer;
  2665.     uint8_t *mask;
  2666.     int x0;
  2667.  
  2668.     if (num_spans == 0)
  2669.         return CAIRO_STATUS_SUCCESS;
  2670.  
  2671.     x0 = spans[0].x;
  2672.     mask = (uint8_t *)pixman_image_get_data (r->mask);
  2673.     do {
  2674.         int len = spans[1].x - spans[0].x;
  2675.         uint8_t m = mul8_8(spans[0].coverage, r->bpp);
  2676.         if (m == 0) {
  2677.             if (spans[0].x != x0) {
  2678. #if PIXMAN_HAS_OP_LERP
  2679.                 pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
  2680.                                           r->src, r->mask, r->u.composite.dst,
  2681.                                           x0 + r->u.composite.src_x,
  2682.                                           y + r->u.composite.src_y,
  2683.                                           0, 0,
  2684.                                           x0, y,
  2685.                                           spans[0].x - x0, h);
  2686. #else
  2687.                 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  2688.                                           r->mask, NULL, r->u.composite.dst,
  2689.                                           0, 0,
  2690.                                           0, 0,
  2691.                                           x0, y,
  2692.                                           spans[0].x - x0, h);
  2693.                 pixman_image_composite32 (PIXMAN_OP_ADD,
  2694.                                           r->src, r->mask, r->u.composite.dst,
  2695.                                           x0 + r->u.composite.src_x,
  2696.                                           y + r->u.composite.src_y,
  2697.                                           0, 0,
  2698.                                           x0, y,
  2699.                                           spans[0].x - x0, h);
  2700. #endif
  2701.             }
  2702.  
  2703.             mask = (uint8_t *)pixman_image_get_data (r->mask);
  2704.             x0 = spans[1].x;
  2705.         } else {
  2706.             *mask++ = m;
  2707.             if (len > 1) {
  2708.                 memset (mask, m, --len);
  2709.                 mask += len;
  2710.             }
  2711.         }
  2712.         spans++;
  2713.     } while (--num_spans > 1);
  2714.  
  2715.     if (spans[0].x != x0) {
  2716. #if PIXMAN_HAS_OP_LERP
  2717.         pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
  2718.                                   r->src, r->mask, r->u.composite.dst,
  2719.                                   x0 + r->u.composite.src_x,
  2720.                                   y + r->u.composite.src_y,
  2721.                                   0, 0,
  2722.                                   x0, y,
  2723.                                   spans[0].x - x0, h);
  2724. #else
  2725.         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  2726.                                   r->mask, NULL, r->u.composite.dst,
  2727.                                   0, 0,
  2728.                                   0, 0,
  2729.                                   x0, y,
  2730.                                   spans[0].x - x0, h);
  2731.         pixman_image_composite32 (PIXMAN_OP_ADD,
  2732.                                   r->src, r->mask, r->u.composite.dst,
  2733.                                   x0 + r->u.composite.src_x,
  2734.                                   y + r->u.composite.src_y,
  2735.                                   0, 0,
  2736.                                   x0, y,
  2737.                                   spans[0].x - x0, h);
  2738. #endif
  2739.     }
  2740.  
  2741.     return CAIRO_STATUS_SUCCESS;
  2742. }
  2743.  
  2744. static void free_pixels (pixman_image_t *image, void *data)
  2745. {
  2746.         free (data);
  2747. }
  2748.  
  2749. static cairo_int_status_t
  2750. inplace_renderer_init (cairo_image_span_renderer_t      *r,
  2751.                        const cairo_composite_rectangles_t *composite,
  2752.                        cairo_antialias_t                 antialias,
  2753.                        cairo_bool_t                      needs_clip)
  2754. {
  2755.     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
  2756.     uint8_t *buf;
  2757.  
  2758.     if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
  2759.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2760.  
  2761.     r->base.render_rows = NULL;
  2762.     r->bpp = composite->mask_pattern.solid.color.alpha_short >> 8;
  2763.  
  2764.     if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
  2765.         const cairo_color_t *color;
  2766.  
  2767.         color = &composite->source_pattern.solid.color;
  2768.         if (composite->op == CAIRO_OPERATOR_CLEAR)
  2769.             color = CAIRO_COLOR_TRANSPARENT;
  2770.  
  2771.         if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) {
  2772.             /* Use plain C for the fill operations as the span length is
  2773.              * typically small, too small to payback the startup overheads of
  2774.              * using SSE2 etc.
  2775.              */
  2776.             if (r->bpp == 0xff) {
  2777.                 switch (dst->format) {
  2778.                 case CAIRO_FORMAT_A8:
  2779.                     r->base.render_rows = _fill_a8_lerp_opaque_spans;
  2780.                     break;
  2781.                 case CAIRO_FORMAT_RGB24:
  2782.                 case CAIRO_FORMAT_ARGB32:
  2783.                     r->base.render_rows = _fill_xrgb32_lerp_opaque_spans;
  2784.                     break;
  2785.                 case CAIRO_FORMAT_A1:
  2786.                 case CAIRO_FORMAT_RGB16_565:
  2787.                 case CAIRO_FORMAT_RGB30:
  2788.                 case CAIRO_FORMAT_INVALID:
  2789.                 default: break;
  2790.                 }
  2791.             } else {
  2792.                 switch (dst->format) {
  2793.                 case CAIRO_FORMAT_A8:
  2794.                     r->base.render_rows = _fill_a8_lerp_spans;
  2795.                     break;
  2796.                 case CAIRO_FORMAT_RGB24:
  2797.                 case CAIRO_FORMAT_ARGB32:
  2798.                     r->base.render_rows = _fill_xrgb32_lerp_spans;
  2799.                     break;
  2800.                 case CAIRO_FORMAT_A1:
  2801.                 case CAIRO_FORMAT_RGB16_565:
  2802.                 case CAIRO_FORMAT_RGB30:
  2803.                 case CAIRO_FORMAT_INVALID:
  2804.                 default: break;
  2805.                 }
  2806.             }
  2807.             r->u.fill.data = dst->data;
  2808.             r->u.fill.stride = dst->stride;
  2809.         }
  2810.     } else if ((dst->format == CAIRO_FORMAT_ARGB32 || dst->format == CAIRO_FORMAT_RGB24) &&
  2811.                (composite->op == CAIRO_OPERATOR_SOURCE ||
  2812.                 (composite->op == CAIRO_OPERATOR_OVER &&
  2813.                  (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
  2814.                composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
  2815.                composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
  2816.                to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
  2817.     {
  2818.        cairo_image_surface_t *src =
  2819.            to_image_surface(composite->source_pattern.surface.surface);
  2820.        int tx, ty;
  2821.  
  2822.         if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
  2823.                                                  &tx, &ty) &&
  2824.             composite->bounded.x + tx >= 0 &&
  2825.             composite->bounded.y + ty >= 0 &&
  2826.             composite->bounded.x + composite->bounded.width + tx <= src->width &&
  2827.             composite->bounded.y + composite->bounded.height + ty <= src->height) {
  2828.  
  2829.             assert(PIXMAN_FORMAT_BPP(dst->pixman_format) == 32);
  2830.             r->u.blit.stride = dst->stride;
  2831.             r->u.blit.data = dst->data;
  2832.             r->u.blit.src_stride = src->stride;
  2833.             r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
  2834.             r->base.render_rows = _blit_xrgb32_lerp_spans;
  2835.         }
  2836.     }
  2837.     if (r->base.render_rows == NULL) {
  2838.         const cairo_pattern_t *src = &composite->source_pattern.base;
  2839.         unsigned int width;
  2840.  
  2841.         if (composite->is_bounded == 0)
  2842.             return CAIRO_INT_STATUS_UNSUPPORTED;
  2843.  
  2844.         r->base.render_rows = r->bpp == 0xff ? _inplace_spans : _inplace_opacity_spans;
  2845.         width = (composite->bounded.width + 3) & ~3;
  2846.  
  2847.         r->u.composite.run_length = 8;
  2848.         if (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
  2849.             src->type == CAIRO_PATTERN_TYPE_RADIAL)
  2850.                 r->u.composite.run_length = 256;
  2851.         if (dst->base.is_clear &&
  2852.             (composite->op == CAIRO_OPERATOR_SOURCE ||
  2853.              composite->op == CAIRO_OPERATOR_OVER ||
  2854.              composite->op == CAIRO_OPERATOR_ADD)) {
  2855.             r->op = PIXMAN_OP_SRC;
  2856.         } else if (composite->op == CAIRO_OPERATOR_SOURCE) {
  2857.             r->base.render_rows = r->bpp == 0xff ? _inplace_src_spans : _inplace_src_opacity_spans;
  2858.             r->u.composite.mask_y = r->composite->unbounded.y;
  2859.             width = (composite->unbounded.width + 3) & ~3;
  2860.         } else if (composite->op == CAIRO_OPERATOR_CLEAR) {
  2861.             r->op = PIXMAN_OP_OUT_REVERSE;
  2862.             src = NULL;
  2863.         } else {
  2864.             r->op = _pixman_operator (composite->op);
  2865.         }
  2866.  
  2867.         r->src = _pixman_image_for_pattern (dst, src, FALSE,
  2868.                                             &composite->bounded,
  2869.                                             &composite->source_sample_area,
  2870.                                             &r->u.composite.src_x, &r->u.composite.src_y);
  2871.         if (unlikely (r->src == NULL))
  2872.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  2873.  
  2874.         /* Create an effectively unbounded mask by repeating the single line */
  2875.         buf = r->_buf;
  2876.         if (width > SZ_BUF) {
  2877.             buf = malloc (width);
  2878.             if (unlikely (buf == NULL)) {
  2879.                 pixman_image_unref (r->src);
  2880.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  2881.             }
  2882.         }
  2883.         r->mask = pixman_image_create_bits (PIXMAN_a8,
  2884.                                             width, composite->unbounded.height,
  2885.                                             (uint32_t *)buf, 0);
  2886.         if (unlikely (r->mask == NULL)) {
  2887.             pixman_image_unref (r->src);
  2888.             if (buf != r->_buf)
  2889.                 free (buf);
  2890.             return _cairo_error(CAIRO_STATUS_NO_MEMORY);
  2891.         }
  2892.  
  2893.         if (buf != r->_buf)
  2894.             pixman_image_set_destroy_function (r->mask, free_pixels, buf);
  2895.  
  2896.         r->u.composite.dst = dst->pixman_image;
  2897.     }
  2898.  
  2899.     return CAIRO_INT_STATUS_SUCCESS;
  2900. }
  2901.  
  2902. static cairo_int_status_t
  2903. span_renderer_init (cairo_abstract_span_renderer_t      *_r,
  2904.                     const cairo_composite_rectangles_t *composite,
  2905.                     cairo_antialias_t                    antialias,
  2906.                     cairo_bool_t                         needs_clip)
  2907. {
  2908.     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
  2909.     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
  2910.     const cairo_pattern_t *source = &composite->source_pattern.base;
  2911.     cairo_operator_t op = composite->op;
  2912.     cairo_int_status_t status;
  2913.  
  2914.     TRACE ((stderr, "%s: antialias=%d, needs_clip=%d\n", __FUNCTION__,
  2915.             antialias, needs_clip));
  2916.  
  2917.     if (needs_clip)
  2918.         return CAIRO_INT_STATUS_UNSUPPORTED;
  2919.  
  2920.     r->composite = composite;
  2921.     r->mask = NULL;
  2922.     r->src = NULL;
  2923.     r->base.finish = NULL;
  2924.  
  2925.     status = mono_renderer_init (r, composite, antialias, needs_clip);
  2926.     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  2927.         return status;
  2928.  
  2929.     status = inplace_renderer_init (r, composite, antialias, needs_clip);
  2930.     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  2931.         return status;
  2932.  
  2933.     r->bpp = 0;
  2934.  
  2935.     if (op == CAIRO_OPERATOR_CLEAR) {
  2936. #if PIXMAN_HAS_OP_LERP
  2937.         op = PIXMAN_OP_LERP_CLEAR;
  2938. #else
  2939.         source = &_cairo_pattern_white.base;
  2940.         op = PIXMAN_OP_OUT_REVERSE;
  2941. #endif
  2942.     } else if (dst->base.is_clear &&
  2943.                (op == CAIRO_OPERATOR_SOURCE ||
  2944.                 op == CAIRO_OPERATOR_OVER ||
  2945.                 op == CAIRO_OPERATOR_ADD)) {
  2946.         op = PIXMAN_OP_SRC;
  2947.     } else if (op == CAIRO_OPERATOR_SOURCE) {
  2948.         if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
  2949.                                       &composite->source_sample_area))
  2950.         {
  2951.             op = PIXMAN_OP_OVER;
  2952.         }
  2953.         else
  2954.         {
  2955. #if PIXMAN_HAS_OP_LERP
  2956.             op = PIXMAN_OP_LERP_SRC;
  2957. #else
  2958.             return CAIRO_INT_STATUS_UNSUPPORTED;
  2959. #endif
  2960.         }
  2961.     } else {
  2962.         op = _pixman_operator (op);
  2963.     }
  2964.     r->op = op;
  2965.  
  2966.     r->src = _pixman_image_for_pattern (dst, source, FALSE,
  2967.                                         &composite->unbounded,
  2968.                                         &composite->source_sample_area,
  2969.                                         &r->u.mask.src_x, &r->u.mask.src_y);
  2970.     if (unlikely (r->src == NULL))
  2971.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  2972.  
  2973.     r->opacity = 1.0;
  2974.     if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
  2975.         r->opacity = composite->mask_pattern.solid.color.alpha;
  2976.     } else {
  2977.         pixman_image_t *mask;
  2978.         int mask_x, mask_y;
  2979.  
  2980.         mask = _pixman_image_for_pattern (dst,
  2981.                                           &composite->mask_pattern.base,
  2982.                                           TRUE,
  2983.                                           &composite->unbounded,
  2984.                                           &composite->mask_sample_area,
  2985.                                           &mask_x, &mask_y);
  2986.         if (unlikely (mask == NULL))
  2987.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  2988.  
  2989.         /* XXX Component-alpha? */
  2990.         if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
  2991.             _cairo_pattern_is_opaque (source, &composite->source_sample_area))
  2992.         {
  2993.             pixman_image_unref (r->src);
  2994.             r->src = mask;
  2995.             r->u.mask.src_x = mask_x;
  2996.             r->u.mask.src_y = mask_y;
  2997.             mask = NULL;
  2998.         }
  2999.  
  3000.         if (mask) {
  3001.             pixman_image_unref (mask);
  3002.             return CAIRO_INT_STATUS_UNSUPPORTED;
  3003.         }
  3004.     }
  3005.  
  3006.     r->u.mask.extents = composite->unbounded;
  3007.     r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3;
  3008.     if (r->u.mask.extents.height * r->u.mask.stride > SZ_BUF) {
  3009.         r->mask = pixman_image_create_bits (PIXMAN_a8,
  3010.                                             r->u.mask.extents.width,
  3011.                                             r->u.mask.extents.height,
  3012.                                             NULL, 0);
  3013.  
  3014.         r->base.render_rows = _cairo_image_spans;
  3015.         r->base.finish = NULL;
  3016.     } else {
  3017.         r->mask = pixman_image_create_bits (PIXMAN_a8,
  3018.                                             r->u.mask.extents.width,
  3019.                                             r->u.mask.extents.height,
  3020.                                             (uint32_t *)r->_buf, r->u.mask.stride);
  3021.  
  3022.         r->base.render_rows = _cairo_image_spans_and_zero;
  3023.         r->base.finish = _cairo_image_finish_spans_and_zero;
  3024.     }
  3025.     if (unlikely (r->mask == NULL))
  3026.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  3027.  
  3028.     r->u.mask.data = (uint8_t *) pixman_image_get_data (r->mask);
  3029.     r->u.mask.stride = pixman_image_get_stride (r->mask);
  3030.  
  3031.     r->u.mask.extents.height += r->u.mask.extents.y;
  3032.     return CAIRO_STATUS_SUCCESS;
  3033. }
  3034.  
  3035. static void
  3036. span_renderer_fini (cairo_abstract_span_renderer_t *_r,
  3037.                     cairo_int_status_t status)
  3038. {
  3039.     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
  3040.  
  3041.     TRACE ((stderr, "%s\n", __FUNCTION__));
  3042.  
  3043.     if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  3044.         if (r->base.finish)
  3045.             r->base.finish (r);
  3046.     }
  3047.     if (likely (status == CAIRO_INT_STATUS_SUCCESS && r->bpp == 0)) {
  3048.         const cairo_composite_rectangles_t *composite = r->composite;
  3049.  
  3050.         pixman_image_composite32 (r->op, r->src, r->mask,
  3051.                                   to_pixman_image (composite->surface),
  3052.                                   composite->unbounded.x + r->u.mask.src_x,
  3053.                                   composite->unbounded.y + r->u.mask.src_y,
  3054.                                   0, 0,
  3055.                                   composite->unbounded.x,
  3056.                                   composite->unbounded.y,
  3057.                                   composite->unbounded.width,
  3058.                                   composite->unbounded.height);
  3059.     }
  3060.  
  3061.     if (r->src)
  3062.         pixman_image_unref (r->src);
  3063.     if (r->mask)
  3064.         pixman_image_unref (r->mask);
  3065. }
  3066. #endif
  3067.  
  3068. const cairo_compositor_t *
  3069. _cairo_image_spans_compositor_get (void)
  3070. {
  3071.     static cairo_spans_compositor_t spans;
  3072.     static cairo_compositor_t shape;
  3073.  
  3074.     if (spans.base.delegate == NULL) {
  3075.         _cairo_shape_mask_compositor_init (&shape,
  3076.                                            _cairo_image_traps_compositor_get());
  3077.         shape.glyphs = NULL;
  3078.  
  3079.         _cairo_spans_compositor_init (&spans, &shape);
  3080.  
  3081.         spans.flags = 0;
  3082. #if PIXMAN_HAS_OP_LERP
  3083.         spans.flags |= CAIRO_SPANS_COMPOSITOR_HAS_LERP;
  3084. #endif
  3085.  
  3086.         //spans.acquire = acquire;
  3087.         //spans.release = release;
  3088.         spans.fill_boxes = fill_boxes;
  3089.         spans.draw_image_boxes = draw_image_boxes;
  3090.         //spans.copy_boxes = copy_boxes;
  3091.         spans.pattern_to_surface = _cairo_image_source_create_for_pattern;
  3092.         //spans.check_composite_boxes = check_composite_boxes;
  3093.         spans.composite_boxes = composite_boxes;
  3094.         //spans.check_span_renderer = check_span_renderer;
  3095.         spans.renderer_init = span_renderer_init;
  3096.         spans.renderer_fini = span_renderer_fini;
  3097.     }
  3098.  
  3099.     return &spans.base;
  3100. }
  3101.