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 © 2002 University of Southern California
  5.  * Copyright © 2005 Red Hat, Inc.
  6.  * Copyright © 2011 Intel Corporation
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it either under the terms of the GNU Lesser General Public
  10.  * License version 2.1 as published by the Free Software Foundation
  11.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  12.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  13.  * notice, a recipient may use your version of this file under either
  14.  * the MPL or the LGPL.
  15.  *
  16.  * You should have received a copy of the LGPL along with this library
  17.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  19.  * You should have received a copy of the MPL along with this library
  20.  * in the file COPYING-MPL-1.1
  21.  *
  22.  * The contents of this file are subject to the Mozilla Public License
  23.  * Version 1.1 (the "License"); you may not use this file except in
  24.  * compliance with the License. You may obtain a copy of the License at
  25.  * http://www.mozilla.org/MPL/
  26.  *
  27.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  28.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  29.  * the specific language governing rights and limitations.
  30.  *
  31.  * The Original Code is the cairo graphics library.
  32.  *
  33.  * The Initial Developer of the Original Code is University of Southern
  34.  * California.
  35.  *
  36.  * Contributor(s):
  37.  *      Carl D. Worth <cworth@cworth.org>
  38.  *      Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
  39.  *      Chris Wilson <chris@chris-wilson.co.uk>
  40.  */
  41.  
  42. #include "cairoint.h"
  43.  
  44. #include "cairo-box-inline.h"
  45. #include "cairo-boxes-private.h"
  46. #include "cairo-clip-inline.h"
  47. #include "cairo-clip-private.h"
  48. #include "cairo-composite-rectangles-private.h"
  49. #include "cairo-compositor-private.h"
  50. #include "cairo-error-private.h"
  51. #include "cairo-image-surface-private.h"
  52. #include "cairo-pattern-inline.h"
  53. #include "cairo-paginated-private.h"
  54. #include "cairo-recording-surface-inline.h"
  55. #include "cairo-surface-subsurface-private.h"
  56. #include "cairo-surface-snapshot-inline.h"
  57. #include "cairo-surface-observer-private.h"
  58. #include "cairo-region-private.h"
  59. #include "cairo-spans-private.h"
  60. #include "cairo-traps-private.h"
  61. #include "cairo-tristrip-private.h"
  62.  
  63. typedef cairo_int_status_t
  64. (*draw_func_t) (const cairo_traps_compositor_t *compositor,
  65.                 cairo_surface_t                 *dst,
  66.                 void                            *closure,
  67.                 cairo_operator_t                 op,
  68.                 cairo_surface_t         *src,
  69.                 int                              src_x,
  70.                 int                              src_y,
  71.                 int                              dst_x,
  72.                 int                              dst_y,
  73.                 const cairo_rectangle_int_t     *extents,
  74.                 cairo_clip_t                    *clip);
  75.  
  76. static void do_unaligned_row(void (*blt)(void *closure,
  77.                                          int16_t x, int16_t y,
  78.                                          int16_t w, int16_t h,
  79.                                          uint16_t coverage),
  80.                              void *closure,
  81.                              const cairo_box_t *b,
  82.                              int tx, int y, int h,
  83.                              uint16_t coverage)
  84. {
  85.     int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
  86.     int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
  87.     if (x2 > x1) {
  88.         if (! _cairo_fixed_is_integer (b->p1.x)) {
  89.             blt(closure, x1, y, 1, h,
  90.                 coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
  91.             x1++;
  92.         }
  93.  
  94.         if (x2 > x1)
  95.             blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
  96.  
  97.         if (! _cairo_fixed_is_integer (b->p2.x))
  98.             blt(closure, x2, y, 1, h,
  99.                 coverage * _cairo_fixed_fractional_part (b->p2.x));
  100.     } else
  101.         blt(closure, x1, y, 1, h,
  102.             coverage * (b->p2.x - b->p1.x));
  103. }
  104.  
  105. static void do_unaligned_box(void (*blt)(void *closure,
  106.                                          int16_t x, int16_t y,
  107.                                          int16_t w, int16_t h,
  108.                                          uint16_t coverage),
  109.                              void *closure,
  110.                              const cairo_box_t *b, int tx, int ty)
  111. {
  112.     int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
  113.     int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
  114.     if (y2 > y1) {
  115.         if (! _cairo_fixed_is_integer (b->p1.y)) {
  116.             do_unaligned_row(blt, closure, b, tx, y1, 1,
  117.                              256 - _cairo_fixed_fractional_part (b->p1.y));
  118.             y1++;
  119.         }
  120.  
  121.         if (y2 > y1)
  122.             do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
  123.  
  124.         if (! _cairo_fixed_is_integer (b->p2.y))
  125.             do_unaligned_row(blt, closure, b, tx, y2, 1,
  126.                              _cairo_fixed_fractional_part (b->p2.y));
  127.     } else
  128.         do_unaligned_row(blt, closure, b, tx, y1, 1,
  129.                          b->p2.y - b->p1.y);
  130. }
  131.  
  132. struct blt_in {
  133.     const cairo_traps_compositor_t *compositor;
  134.     cairo_surface_t *dst;
  135.     cairo_boxes_t boxes;
  136. };
  137.  
  138. static void blt_in(void *closure,
  139.                    int16_t x, int16_t y,
  140.                    int16_t w, int16_t h,
  141.                    uint16_t coverage)
  142. {
  143.     struct blt_in *info = closure;
  144.     cairo_color_t color;
  145.  
  146.     if (CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage))
  147.         return;
  148.  
  149.     _cairo_box_from_integers (&info->boxes.chunks.base[0], x, y, w, h);
  150.  
  151.     _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
  152.     info->compositor->fill_boxes (info->dst,
  153.                                   CAIRO_OPERATOR_IN, &color,
  154.                                   &info->boxes);
  155. }
  156.  
  157. static void
  158. add_rect_with_offset (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2, int dx, int dy)
  159. {
  160.     cairo_box_t box;
  161.     cairo_int_status_t status;
  162.  
  163.     box.p1.x = _cairo_fixed_from_int (x1 - dx);
  164.     box.p1.y = _cairo_fixed_from_int (y1 - dy);
  165.     box.p2.x = _cairo_fixed_from_int (x2 - dx);
  166.     box.p2.y = _cairo_fixed_from_int (y2 - dy);
  167.  
  168.     status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
  169.     assert (status == CAIRO_INT_STATUS_SUCCESS);
  170. }
  171.  
  172. static cairo_int_status_t
  173. combine_clip_as_traps (const cairo_traps_compositor_t *compositor,
  174.                        cairo_surface_t *mask,
  175.                        const cairo_clip_t *clip,
  176.                        const cairo_rectangle_int_t *extents)
  177. {
  178.     cairo_polygon_t polygon;
  179.     cairo_fill_rule_t fill_rule;
  180.     cairo_antialias_t antialias;
  181.     cairo_traps_t traps;
  182.     cairo_surface_t *src;
  183.     cairo_box_t box;
  184.     cairo_rectangle_int_t fixup;
  185.     int src_x, src_y;
  186.     cairo_int_status_t status;
  187.  
  188.     TRACE ((stderr, "%s\n", __FUNCTION__));
  189.  
  190.     status = _cairo_clip_get_polygon (clip, &polygon,
  191.                                       &fill_rule, &antialias);
  192.     if (status)
  193.         return status;
  194.  
  195.     _cairo_traps_init (&traps);
  196.     status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
  197.                                                         &polygon,
  198.                                                         fill_rule);
  199.     _cairo_polygon_fini (&polygon);
  200.     if (unlikely (status))
  201.         return status;
  202.  
  203.     src = compositor->pattern_to_surface (mask, NULL, FALSE,
  204.                                           extents, NULL,
  205.                                           &src_x, &src_y);
  206.     if (unlikely (src->status)) {
  207.         _cairo_traps_fini (&traps);
  208.         return src->status;
  209.     }
  210.  
  211.     status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, src,
  212.                                           src_x, src_y,
  213.                                           extents->x, extents->y,
  214.                                           extents,
  215.                                           antialias, &traps);
  216.  
  217.     _cairo_traps_extents (&traps, &box);
  218.     _cairo_box_round_to_rectangle (&box, &fixup);
  219.     _cairo_traps_fini (&traps);
  220.     cairo_surface_destroy (src);
  221.  
  222.     if (unlikely (status))
  223.         return status;
  224.  
  225.     if (! _cairo_rectangle_intersect (&fixup, extents))
  226.         return CAIRO_STATUS_SUCCESS;
  227.  
  228.     if (fixup.width < extents->width || fixup.height < extents->height) {
  229.         cairo_boxes_t clear;
  230.  
  231.         _cairo_boxes_init (&clear);
  232.  
  233.         /* top */
  234.         if (fixup.y != extents->y) {
  235.             add_rect_with_offset (&clear,
  236.                                   extents->x, extents->y,
  237.                                   extents->x + extents->width,
  238.                                   fixup.y,
  239.                                   extents->x, extents->y);
  240.         }
  241.         /* left */
  242.         if (fixup.x != extents->x) {
  243.             add_rect_with_offset (&clear,
  244.                                   extents->x, fixup.y,
  245.                                   fixup.x,
  246.                                   fixup.y + fixup.height,
  247.                                   extents->x, extents->y);
  248.         }
  249.         /* right */
  250.         if (fixup.x + fixup.width != extents->x + extents->width) {
  251.             add_rect_with_offset (&clear,
  252.                                   fixup.x + fixup.width,
  253.                                   fixup.y,
  254.                                   extents->x + extents->width,
  255.                                   fixup.y + fixup.height,
  256.                                   extents->x, extents->y);
  257.         }
  258.         /* bottom */
  259.         if (fixup.y + fixup.height != extents->y + extents->height) {
  260.             add_rect_with_offset (&clear,
  261.                                   extents->x,
  262.                                   fixup.y + fixup.height,
  263.                                   extents->x + extents->width,
  264.                                   extents->y + extents->height,
  265.                                   extents->x, extents->y);
  266.         }
  267.  
  268.         status = compositor->fill_boxes (mask,
  269.                                          CAIRO_OPERATOR_CLEAR,
  270.                                          CAIRO_COLOR_TRANSPARENT,
  271.                                          &clear);
  272.  
  273.         _cairo_boxes_fini (&clear);
  274.     }
  275.  
  276.     return status;
  277. }
  278.  
  279. static cairo_status_t
  280. __clip_to_surface (const cairo_traps_compositor_t *compositor,
  281.                    const cairo_composite_rectangles_t *composite,
  282.                    const cairo_rectangle_int_t *extents,
  283.                    cairo_surface_t **surface)
  284. {
  285.     cairo_surface_t *mask;
  286.     cairo_polygon_t polygon;
  287.     cairo_fill_rule_t fill_rule;
  288.     cairo_antialias_t antialias;
  289.     cairo_traps_t traps;
  290.     cairo_boxes_t clear;
  291.     cairo_surface_t *src;
  292.     int src_x, src_y;
  293.     cairo_int_status_t status;
  294.  
  295.     TRACE ((stderr, "%s\n", __FUNCTION__));
  296.  
  297.     status = _cairo_clip_get_polygon (composite->clip, &polygon,
  298.                                       &fill_rule, &antialias);
  299.     if (status)
  300.         return status;
  301.  
  302.     _cairo_traps_init (&traps);
  303.     status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
  304.                                                         &polygon,
  305.                                                         fill_rule);
  306.     _cairo_polygon_fini (&polygon);
  307.     if (unlikely (status))
  308.         return status;
  309.  
  310.     mask = _cairo_surface_create_similar_scratch (composite->surface,
  311.                                                   CAIRO_CONTENT_ALPHA,
  312.                                                   extents->width,
  313.                                                   extents->height);
  314.     if (unlikely (mask->status)) {
  315.         _cairo_traps_fini (&traps);
  316.         return status;
  317.     }
  318.  
  319.     src = compositor->pattern_to_surface (mask, NULL, FALSE,
  320.                                           extents, NULL,
  321.                                           &src_x, &src_y);
  322.     if (unlikely (status = src->status))
  323.         goto error;
  324.  
  325.     status = compositor->acquire (mask);
  326.     if (unlikely (status))
  327.         goto error;
  328.  
  329.     _cairo_boxes_init_from_rectangle (&clear,
  330.                                       0, 0,
  331.                                       extents->width,
  332.                                       extents->height);
  333.     status = compositor->fill_boxes (mask,
  334.                                      CAIRO_OPERATOR_CLEAR,
  335.                                      CAIRO_COLOR_TRANSPARENT,
  336.                                      &clear);
  337.     if (unlikely (status))
  338.         goto error_release;
  339.  
  340.     status = compositor->composite_traps (mask, CAIRO_OPERATOR_ADD, src,
  341.                                           src_x, src_y,
  342.                                           extents->x, extents->y,
  343.                                           extents,
  344.                                           antialias, &traps);
  345.     if (unlikely (status))
  346.         goto error_release;
  347.  
  348.     compositor->release (mask);
  349.     *surface = mask;
  350. out:
  351.     cairo_surface_destroy (src);
  352.     _cairo_traps_fini (&traps);
  353.     return status;
  354.  
  355. error_release:
  356.     compositor->release (mask);
  357. error:
  358.     cairo_surface_destroy (mask);
  359.     goto out;
  360. }
  361.  
  362. static cairo_surface_t *
  363. traps_get_clip_surface (const cairo_traps_compositor_t *compositor,
  364.                         const cairo_composite_rectangles_t *composite,
  365.                         const cairo_rectangle_int_t *extents)
  366. {
  367.     cairo_surface_t *surface = NULL;
  368.     cairo_int_status_t status;
  369.  
  370.     TRACE ((stderr, "%s\n", __FUNCTION__));
  371.  
  372.     status = __clip_to_surface (compositor, composite, extents, &surface);
  373.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  374.         surface = _cairo_surface_create_similar_solid (composite->surface,
  375.                                                        CAIRO_CONTENT_ALPHA,
  376.                                                        extents->width,
  377.                                                        extents->height,
  378.                                                        CAIRO_COLOR_WHITE);
  379.         if (unlikely (surface->status))
  380.             return surface;
  381.  
  382.         status = _cairo_clip_combine_with_surface (composite->clip, surface,
  383.                                                    extents->x, extents->y);
  384.     }
  385.     if (unlikely (status)) {
  386.         cairo_surface_destroy (surface);
  387.         surface = _cairo_surface_create_in_error (status);
  388.     }
  389.  
  390.     return surface;
  391. }
  392.  
  393. static void blt_unaligned_boxes(const cairo_traps_compositor_t *compositor,
  394.                                 cairo_surface_t *surface,
  395.                                 int dx, int dy,
  396.                                 cairo_box_t *boxes,
  397.                                 int num_boxes)
  398. {
  399.     struct blt_in info;
  400.     int i;
  401.  
  402.     info.compositor = compositor;
  403.     info.dst = surface;
  404.     _cairo_boxes_init (&info.boxes);
  405.     info.boxes.num_boxes = 1;
  406.     for (i = 0; i < num_boxes; i++) {
  407.         cairo_box_t *b = &boxes[i];
  408.  
  409.         if (! _cairo_fixed_is_integer (b->p1.x) ||
  410.             ! _cairo_fixed_is_integer (b->p1.y) ||
  411.             ! _cairo_fixed_is_integer (b->p2.x) ||
  412.             ! _cairo_fixed_is_integer (b->p2.y))
  413.         {
  414.             do_unaligned_box(blt_in, &info, b, dx, dy);
  415.         }
  416.     }
  417. }
  418.  
  419. static cairo_surface_t *
  420. create_composite_mask (const cairo_traps_compositor_t *compositor,
  421.                        cairo_surface_t          *dst,
  422.                        void                     *draw_closure,
  423.                        draw_func_t               draw_func,
  424.                        draw_func_t               mask_func,
  425.                        const cairo_composite_rectangles_t *extents)
  426. {
  427.     cairo_surface_t *surface, *src;
  428.     cairo_int_status_t status;
  429.     int src_x, src_y;
  430.  
  431.     TRACE ((stderr, "%s\n", __FUNCTION__));
  432.  
  433.     surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA,
  434.                                                      extents->bounded.width,
  435.                                                      extents->bounded.height);
  436.     if (unlikely (surface->status))
  437.         return surface;
  438.  
  439.     src = compositor->pattern_to_surface (surface,
  440.                                           &_cairo_pattern_white.base,
  441.                                           FALSE,
  442.                                           &extents->bounded,
  443.                                           &extents->bounded,
  444.                                           &src_x, &src_y);
  445.     if (unlikely (src->status)) {
  446.         cairo_surface_destroy (surface);
  447.         return src;
  448.     }
  449.  
  450.     status = compositor->acquire (surface);
  451.     if (unlikely (status)) {
  452.         cairo_surface_destroy (src);
  453.         cairo_surface_destroy (surface);
  454.         return _cairo_surface_create_in_error (status);
  455.     }
  456.  
  457.     if (!surface->is_clear) {
  458.         cairo_boxes_t clear;
  459.  
  460.         _cairo_boxes_init_from_rectangle (&clear,
  461.                                           0, 0,
  462.                                           extents->bounded.width,
  463.                                           extents->bounded.height);
  464.         status = compositor->fill_boxes (surface,
  465.                                          CAIRO_OPERATOR_CLEAR,
  466.                                          CAIRO_COLOR_TRANSPARENT,
  467.                                          &clear);
  468.         if (unlikely (status))
  469.             goto error;
  470.  
  471.         surface->is_clear = TRUE;
  472.     }
  473.  
  474.     if (mask_func) {
  475.         status = mask_func (compositor, surface, draw_closure,
  476.                             CAIRO_OPERATOR_SOURCE, src, src_x, src_y,
  477.                             extents->bounded.x, extents->bounded.y,
  478.                             &extents->bounded, extents->clip);
  479.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  480.             surface->is_clear = FALSE;
  481.             goto out;
  482.         }
  483.         if (unlikely (status != CAIRO_INT_STATUS_UNSUPPORTED))
  484.             goto error;
  485.     }
  486.  
  487.     /* Is it worth setting the clip region here? */
  488.     status = draw_func (compositor, surface, draw_closure,
  489.                         CAIRO_OPERATOR_ADD, src, src_x, src_y,
  490.                         extents->bounded.x, extents->bounded.y,
  491.                         &extents->bounded, NULL);
  492.     if (unlikely (status))
  493.         goto error;
  494.  
  495.     surface->is_clear = FALSE;
  496.     if (extents->clip->path != NULL) {
  497.         status = combine_clip_as_traps (compositor, surface,
  498.                                         extents->clip, &extents->bounded);
  499.         if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  500.             status = _cairo_clip_combine_with_surface (extents->clip, surface,
  501.                                                        extents->bounded.x,
  502.                                                        extents->bounded.y);
  503.         }
  504.         if (unlikely (status))
  505.             goto error;
  506.     } else if (extents->clip->boxes) {
  507.         blt_unaligned_boxes(compositor, surface,
  508.                             extents->bounded.x, extents->bounded.y,
  509.                             extents->clip->boxes, extents->clip->num_boxes);
  510.  
  511.     }
  512.  
  513. out:
  514.     compositor->release (surface);
  515.     cairo_surface_destroy (src);
  516.     return surface;
  517.  
  518. error:
  519.     compositor->release (surface);
  520.     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
  521.         cairo_surface_destroy (surface);
  522.         surface = _cairo_surface_create_in_error (status);
  523.     }
  524.     cairo_surface_destroy (src);
  525.     return surface;
  526. }
  527.  
  528. /* Handles compositing with a clip surface when the operator allows
  529.  * us to combine the clip with the mask
  530.  */
  531. static cairo_status_t
  532. clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor,
  533.                               const cairo_composite_rectangles_t*extents,
  534.                               draw_func_t                draw_func,
  535.                               draw_func_t                mask_func,
  536.                               void                      *draw_closure,
  537.                               cairo_operator_t           op,
  538.                               cairo_surface_t   *src,
  539.                               int src_x, int src_y)
  540. {
  541.     cairo_surface_t *dst = extents->surface;
  542.     cairo_surface_t *mask;
  543.  
  544.     TRACE ((stderr, "%s\n", __FUNCTION__));
  545.  
  546.     mask = create_composite_mask (compositor, dst, draw_closure,
  547.                                   draw_func, mask_func,
  548.                                   extents);
  549.     if (unlikely (mask->status))
  550.         return mask->status;
  551.  
  552.     if (mask->is_clear)
  553.         goto skip;
  554.  
  555.     if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
  556.         compositor->composite (dst, op, src, mask,
  557.                                extents->bounded.x + src_x,
  558.                                extents->bounded.y + src_y,
  559.                                0, 0,
  560.                                extents->bounded.x,      extents->bounded.y,
  561.                                extents->bounded.width,  extents->bounded.height);
  562.     } else {
  563.         compositor->composite (dst, op, mask, NULL,
  564.                                0, 0,
  565.                                0, 0,
  566.                                extents->bounded.x,      extents->bounded.y,
  567.                                extents->bounded.width,  extents->bounded.height);
  568.     }
  569.  
  570. skip:
  571.     cairo_surface_destroy (mask);
  572.     return CAIRO_STATUS_SUCCESS;
  573. }
  574.  
  575. /* Handles compositing with a clip surface when we have to do the operation
  576.  * in two pieces and combine them together.
  577.  */
  578. static cairo_status_t
  579. clip_and_composite_combine (const cairo_traps_compositor_t *compositor,
  580.                             const cairo_composite_rectangles_t*extents,
  581.                             draw_func_t          draw_func,
  582.                             void                        *draw_closure,
  583.                             cairo_operator_t             op,
  584.                             cairo_surface_t     *src,
  585.                             int src_x, int src_y)
  586. {
  587.     cairo_surface_t *dst = extents->surface;
  588.     cairo_surface_t *tmp, *clip;
  589.     cairo_status_t status;
  590.  
  591.     TRACE ((stderr, "%s\n", __FUNCTION__));
  592.  
  593.     tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
  594.                                                  extents->bounded.width,
  595.                                                  extents->bounded.height);
  596.     if (unlikely (tmp->status))
  597.         return tmp->status;
  598.  
  599.     status = compositor->acquire (tmp);
  600.     if (unlikely (status)) {
  601.         cairo_surface_destroy (tmp);
  602.         return status;
  603.     }
  604.  
  605.     compositor->composite (tmp,
  606.                            dst->is_clear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
  607.                            dst, NULL,
  608.                            extents->bounded.x,      extents->bounded.y,
  609.                            0, 0,
  610.                            0, 0,
  611.                            extents->bounded.width,  extents->bounded.height);
  612.  
  613.     status = draw_func (compositor, tmp, draw_closure, op,
  614.                         src, src_x, src_y,
  615.                         extents->bounded.x, extents->bounded.y,
  616.                         &extents->bounded, NULL);
  617.  
  618.     if (unlikely (status))
  619.         goto cleanup;
  620.  
  621.     clip = traps_get_clip_surface (compositor, extents, &extents->bounded);
  622.     if (unlikely ((status = clip->status)))
  623.         goto cleanup;
  624.  
  625.     if (dst->is_clear) {
  626.         compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
  627.                                0, 0,
  628.                                0, 0,
  629.                                extents->bounded.x,      extents->bounded.y,
  630.                                extents->bounded.width,  extents->bounded.height);
  631.     } else {
  632.         compositor->lerp (dst, tmp, clip,
  633.                           0, 0,
  634.                           0,0,
  635.                           extents->bounded.x,     extents->bounded.y,
  636.                           extents->bounded.width, extents->bounded.height);
  637.     }
  638.     cairo_surface_destroy (clip);
  639.  
  640. cleanup:
  641.     compositor->release (tmp);
  642.     cairo_surface_destroy (tmp);
  643.  
  644.     return status;
  645. }
  646.  
  647. /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
  648.  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
  649.  */
  650. static cairo_status_t
  651. clip_and_composite_source (const cairo_traps_compositor_t       *compositor,
  652.                            cairo_surface_t                      *dst,
  653.                            draw_func_t                           draw_func,
  654.                            draw_func_t                           mask_func,
  655.                            void                                 *draw_closure,
  656.                            cairo_surface_t              *src,
  657.                            int src_x,
  658.                            int src_y,
  659.                            const cairo_composite_rectangles_t   *extents)
  660. {
  661.     cairo_surface_t *mask;
  662.  
  663.     TRACE ((stderr, "%s\n", __FUNCTION__));
  664.  
  665.     /* Create a surface that is mask IN clip */
  666.     mask = create_composite_mask (compositor, dst, draw_closure,
  667.                                   draw_func, mask_func,
  668.                                   extents);
  669.     if (unlikely (mask->status))
  670.         return mask->status;
  671.  
  672.     if (mask->is_clear)
  673.         goto skip;
  674.  
  675.     if (dst->is_clear) {
  676.         compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
  677.                                extents->bounded.x + src_x, extents->bounded.y + src_y,
  678.                                0, 0,
  679.                                extents->bounded.x,      extents->bounded.y,
  680.                                extents->bounded.width,  extents->bounded.height);
  681.     } else {
  682.         compositor->lerp (dst, src, mask,
  683.                           extents->bounded.x + src_x, extents->bounded.y + src_y,
  684.                           0, 0,
  685.                           extents->bounded.x,     extents->bounded.y,
  686.                           extents->bounded.width, extents->bounded.height);
  687.     }
  688.  
  689. skip:
  690.     cairo_surface_destroy (mask);
  691.  
  692.     return CAIRO_STATUS_SUCCESS;
  693. }
  694.  
  695. static cairo_bool_t
  696. can_reduce_alpha_op (cairo_operator_t op)
  697. {
  698.     int iop = op;
  699.     switch (iop) {
  700.     case CAIRO_OPERATOR_OVER:
  701.     case CAIRO_OPERATOR_SOURCE:
  702.     case CAIRO_OPERATOR_ADD:
  703.         return TRUE;
  704.     default:
  705.         return FALSE;
  706.     }
  707. }
  708.  
  709. static cairo_bool_t
  710. reduce_alpha_op (cairo_composite_rectangles_t *extents)
  711. {
  712.     cairo_surface_t *dst = extents->surface;
  713.     cairo_operator_t op = extents->op;
  714.     const cairo_pattern_t *pattern = &extents->source_pattern.base;
  715.     return dst->is_clear &&
  716.            dst->content == CAIRO_CONTENT_ALPHA &&
  717.            _cairo_pattern_is_opaque_solid (pattern) &&
  718.            can_reduce_alpha_op (op);
  719. }
  720.  
  721. static cairo_status_t
  722. fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor,
  723.                            const cairo_composite_rectangles_t *extents)
  724. {
  725.     cairo_surface_t *dst = extents->surface;
  726.     cairo_surface_t *mask;
  727.  
  728.     TRACE ((stderr, "%s\n", __FUNCTION__));
  729.  
  730.     /* XXX can we avoid querying the clip surface again? */
  731.     mask = traps_get_clip_surface (compositor, extents, &extents->unbounded);
  732.     if (unlikely (mask->status))
  733.         return mask->status;
  734.  
  735.     /* top */
  736.     if (extents->bounded.y != extents->unbounded.y) {
  737.         int x = extents->unbounded.x;
  738.         int y = extents->unbounded.y;
  739.         int width = extents->unbounded.width;
  740.         int height = extents->bounded.y - y;
  741.  
  742.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  743.                                0, 0,
  744.                                0, 0,
  745.                                x, y,
  746.                                width, height);
  747.     }
  748.  
  749.     /* left */
  750.     if (extents->bounded.x != extents->unbounded.x) {
  751.         int x = extents->unbounded.x;
  752.         int y = extents->bounded.y;
  753.         int width = extents->bounded.x - x;
  754.         int height = extents->bounded.height;
  755.  
  756.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  757.                                0, y - extents->unbounded.y,
  758.                                0, 0,
  759.                                x, y,
  760.                                width, height);
  761.     }
  762.  
  763.     /* right */
  764.     if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
  765.         int x = extents->bounded.x + extents->bounded.width;
  766.         int y = extents->bounded.y;
  767.         int width = extents->unbounded.x + extents->unbounded.width - x;
  768.         int height = extents->bounded.height;
  769.  
  770.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  771.                                x - extents->unbounded.x, y - extents->unbounded.y,
  772.                                0, 0,
  773.                                x, y,
  774.                                width, height);
  775.     }
  776.  
  777.     /* bottom */
  778.     if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
  779.         int x = extents->unbounded.x;
  780.         int y = extents->bounded.y + extents->bounded.height;
  781.         int width = extents->unbounded.width;
  782.         int height = extents->unbounded.y + extents->unbounded.height - y;
  783.  
  784.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  785.                                0, y - extents->unbounded.y,
  786.                                0, 0,
  787.                                x, y,
  788.                                width, height);
  789.     }
  790.  
  791.     cairo_surface_destroy (mask);
  792.  
  793.     return CAIRO_STATUS_SUCCESS;
  794. }
  795.  
  796. static void
  797. add_rect (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2)
  798. {
  799.     cairo_box_t box;
  800.     cairo_int_status_t status;
  801.  
  802.     box.p1.x = _cairo_fixed_from_int (x1);
  803.     box.p1.y = _cairo_fixed_from_int (y1);
  804.     box.p2.x = _cairo_fixed_from_int (x2);
  805.     box.p2.y = _cairo_fixed_from_int (y2);
  806.  
  807.     status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
  808.     assert (status == CAIRO_INT_STATUS_SUCCESS);
  809. }
  810.  
  811. static cairo_status_t
  812. fixup_unbounded (const cairo_traps_compositor_t *compositor,
  813.                  cairo_composite_rectangles_t *extents,
  814.                  cairo_boxes_t *boxes)
  815. {
  816.     cairo_surface_t *dst = extents->surface;
  817.     cairo_boxes_t clear, tmp;
  818.     cairo_box_t box;
  819.     cairo_int_status_t status;
  820.  
  821.     TRACE ((stderr, "%s\n", __FUNCTION__));
  822.  
  823.     if (extents->bounded.width  == extents->unbounded.width &&
  824.         extents->bounded.height == extents->unbounded.height)
  825.     {
  826.         return CAIRO_STATUS_SUCCESS;
  827.     }
  828.  
  829.     assert (extents->clip->path == NULL);
  830.  
  831.     /* subtract the drawn boxes from the unbounded area */
  832.     _cairo_boxes_init (&clear);
  833.  
  834.     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
  835.     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
  836.     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
  837.     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
  838.  
  839.     if (boxes == NULL) {
  840.         if (extents->bounded.width == 0 || extents->bounded.height == 0) {
  841.             goto empty;
  842.         } else {
  843.             /* top */
  844.             if (extents->bounded.y != extents->unbounded.y) {
  845.                 add_rect (&clear,
  846.                           extents->unbounded.x, extents->unbounded.y,
  847.                           extents->unbounded.x + extents->unbounded.width,
  848.                           extents->bounded.y);
  849.             }
  850.             /* left */
  851.             if (extents->bounded.x != extents->unbounded.x) {
  852.                 add_rect (&clear,
  853.                           extents->unbounded.x, extents->bounded.y,
  854.                           extents->bounded.x,
  855.                           extents->bounded.y + extents->bounded.height);
  856.             }
  857.             /* right */
  858.             if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
  859.                 add_rect (&clear,
  860.                           extents->bounded.x + extents->bounded.width,
  861.                           extents->bounded.y,
  862.                           extents->unbounded.x + extents->unbounded.width,
  863.                           extents->bounded.y + extents->bounded.height);
  864.             }
  865.             /* bottom */
  866.             if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
  867.                 add_rect (&clear,
  868.                           extents->unbounded.x,
  869.                           extents->bounded.y + extents->bounded.height,
  870.                           extents->unbounded.x + extents->unbounded.width,
  871.                           extents->unbounded.y + extents->unbounded.height);
  872.             }
  873.         }
  874.     } else if (boxes->num_boxes) {
  875.         _cairo_boxes_init (&tmp);
  876.  
  877.         assert (boxes->is_pixel_aligned);
  878.  
  879.         status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
  880.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  881.  
  882.         tmp.chunks.next = &boxes->chunks;
  883.         tmp.num_boxes += boxes->num_boxes;
  884.  
  885.         status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
  886.                                                           CAIRO_FILL_RULE_WINDING,
  887.                                                           &clear);
  888.         tmp.chunks.next = NULL;
  889.         if (unlikely (status))
  890.             goto error;
  891.     } else {
  892. empty:
  893.         box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
  894.         box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
  895.  
  896.         status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
  897.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  898.     }
  899.  
  900.     /* Now intersect with the clip boxes */
  901.     if (extents->clip->num_boxes) {
  902.         _cairo_boxes_init_for_array (&tmp,
  903.                                      extents->clip->boxes,
  904.                                      extents->clip->num_boxes);
  905.         status = _cairo_boxes_intersect (&clear, &tmp, &clear);
  906.         if (unlikely (status))
  907.             goto error;
  908.     }
  909.  
  910.     status = compositor->fill_boxes (dst,
  911.                                      CAIRO_OPERATOR_CLEAR,
  912.                                      CAIRO_COLOR_TRANSPARENT,
  913.                                      &clear);
  914.  
  915. error:
  916.     _cairo_boxes_fini (&clear);
  917.     return status;
  918. }
  919.  
  920. enum {
  921.     NEED_CLIP_REGION = 0x1,
  922.     NEED_CLIP_SURFACE = 0x2,
  923.     FORCE_CLIP_REGION = 0x4,
  924. };
  925.  
  926. static cairo_bool_t
  927. need_bounded_clip (cairo_composite_rectangles_t *extents)
  928. {
  929.     unsigned int flags = 0;
  930.  
  931.     if (extents->clip->num_boxes > 1 ||
  932.         extents->mask.width > extents->unbounded.width ||
  933.         extents->mask.height > extents->unbounded.height)
  934.     {
  935.         flags |= NEED_CLIP_REGION;
  936.     }
  937.  
  938.     if (extents->clip->num_boxes > 1 ||
  939.         extents->mask.width > extents->bounded.width ||
  940.         extents->mask.height > extents->bounded.height)
  941.     {
  942.         flags |= FORCE_CLIP_REGION;
  943.     }
  944.  
  945.     if (! _cairo_clip_is_region (extents->clip))
  946.         flags |= NEED_CLIP_SURFACE;
  947.  
  948.     return flags;
  949. }
  950.  
  951. static cairo_bool_t
  952. need_unbounded_clip (cairo_composite_rectangles_t *extents)
  953. {
  954.     unsigned int flags = 0;
  955.     if (! extents->is_bounded) {
  956.         flags |= NEED_CLIP_REGION;
  957.         if (! _cairo_clip_is_region (extents->clip))
  958.             flags |= NEED_CLIP_SURFACE;
  959.     }
  960.     if (extents->clip->path != NULL)
  961.         flags |= NEED_CLIP_SURFACE;
  962.     return flags;
  963. }
  964.  
  965. static cairo_status_t
  966. clip_and_composite (const cairo_traps_compositor_t *compositor,
  967.                     cairo_composite_rectangles_t *extents,
  968.                     draw_func_t          draw_func,
  969.                     draw_func_t          mask_func,
  970.                     void                *draw_closure,
  971.                     unsigned int need_clip)
  972. {
  973.     cairo_surface_t *dst = extents->surface;
  974.     cairo_operator_t op = extents->op;
  975.     cairo_pattern_t *source = &extents->source_pattern.base;
  976.     cairo_surface_t *src;
  977.     int src_x, src_y;
  978.     cairo_region_t *clip_region = NULL;
  979.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  980.  
  981.     TRACE ((stderr, "%s\n", __FUNCTION__));
  982.  
  983.     if (reduce_alpha_op (extents)) {
  984.         op = CAIRO_OPERATOR_ADD;
  985.         source = NULL;
  986.     }
  987.  
  988.     if (op == CAIRO_OPERATOR_CLEAR) {
  989.         op = CAIRO_OPERATOR_DEST_OUT;
  990.         source = NULL;
  991.     }
  992.  
  993.     compositor->acquire (dst);
  994.  
  995.     if (need_clip & NEED_CLIP_REGION) {
  996.         const cairo_rectangle_int_t *limit;
  997.  
  998.         if ((need_clip & FORCE_CLIP_REGION) == 0)
  999.             limit = &extents->unbounded;
  1000.         else
  1001.             limit = &extents->destination;
  1002.  
  1003.         clip_region = _cairo_clip_get_region (extents->clip);
  1004.         if (clip_region != NULL &&
  1005.             cairo_region_contains_rectangle (clip_region,
  1006.                                              limit) == CAIRO_REGION_OVERLAP_IN)
  1007.             clip_region = NULL;
  1008.  
  1009.         if (clip_region != NULL) {
  1010.             status = compositor->set_clip_region (dst, clip_region);
  1011.             if (unlikely (status)) {
  1012.                 compositor->release (dst);
  1013.                 return status;
  1014.             }
  1015.         }
  1016.     }
  1017.  
  1018.     if (extents->bounded.width == 0 || extents->bounded.height == 0)
  1019.         goto skip;
  1020.  
  1021.     src = compositor->pattern_to_surface (dst, source, FALSE,
  1022.                                           &extents->bounded,
  1023.                                           &extents->source_sample_area,
  1024.                                           &src_x, &src_y);
  1025.     if (unlikely (status = src->status))
  1026.         goto error;
  1027.  
  1028.     if (op == CAIRO_OPERATOR_SOURCE) {
  1029.         status = clip_and_composite_source (compositor, dst,
  1030.                                             draw_func, mask_func, draw_closure,
  1031.                                             src, src_x, src_y,
  1032.                                             extents);
  1033.     } else {
  1034.         if (need_clip & NEED_CLIP_SURFACE) {
  1035.             if (extents->is_bounded) {
  1036.                 status = clip_and_composite_with_mask (compositor, extents,
  1037.                                                        draw_func, mask_func,
  1038.                                                        draw_closure,
  1039.                                                        op, src, src_x, src_y);
  1040.             } else {
  1041.                 status = clip_and_composite_combine (compositor, extents,
  1042.                                                      draw_func, draw_closure,
  1043.                                                      op, src, src_x, src_y);
  1044.             }
  1045.         } else {
  1046.             status = draw_func (compositor,
  1047.                                 dst, draw_closure,
  1048.                                 op, src, src_x, src_y,
  1049.                                 0, 0,
  1050.                                 &extents->bounded,
  1051.                                 extents->clip);
  1052.         }
  1053.     }
  1054.     cairo_surface_destroy (src);
  1055.  
  1056. skip:
  1057.     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
  1058.         if (need_clip & NEED_CLIP_SURFACE)
  1059.             status = fixup_unbounded_with_mask (compositor, extents);
  1060.         else
  1061.             status = fixup_unbounded (compositor, extents, NULL);
  1062.     }
  1063.  
  1064. error:
  1065.     if (clip_region)
  1066.         compositor->set_clip_region (dst, NULL);
  1067.  
  1068.     compositor->release (dst);
  1069.  
  1070.     return status;
  1071. }
  1072.  
  1073. /* meta-ops */
  1074.  
  1075. typedef struct {
  1076.     cairo_traps_t traps;
  1077.     cairo_antialias_t antialias;
  1078. } composite_traps_info_t;
  1079.  
  1080. static cairo_int_status_t
  1081. composite_traps (const cairo_traps_compositor_t *compositor,
  1082.                  cairo_surface_t                *dst,
  1083.                  void                            *closure,
  1084.                  cairo_operator_t                op,
  1085.                  cairo_surface_t                *src,
  1086.                  int src_x, int src_y,
  1087.                  int dst_x, int dst_y,
  1088.                  const cairo_rectangle_int_t *extents,
  1089.                  cairo_clip_t                   *clip)
  1090. {
  1091.     composite_traps_info_t *info = closure;
  1092.  
  1093.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1094.  
  1095.     return compositor->composite_traps (dst, op, src,
  1096.                                         src_x - dst_x, src_y - dst_y,
  1097.                                         dst_x, dst_y,
  1098.                                         extents,
  1099.                                         info->antialias, &info->traps);
  1100. }
  1101.  
  1102. typedef struct {
  1103.     cairo_tristrip_t strip;
  1104.     cairo_antialias_t antialias;
  1105. } composite_tristrip_info_t;
  1106.  
  1107. static cairo_int_status_t
  1108. composite_tristrip (const cairo_traps_compositor_t *compositor,
  1109.                     cairo_surface_t             *dst,
  1110.                     void                                 *closure,
  1111.                     cairo_operator_t             op,
  1112.                     cairo_surface_t             *src,
  1113.                     int src_x, int src_y,
  1114.                     int dst_x, int dst_y,
  1115.                     const cairo_rectangle_int_t *extents,
  1116.                     cairo_clip_t                        *clip)
  1117. {
  1118.     composite_tristrip_info_t *info = closure;
  1119.  
  1120.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1121.  
  1122.     return compositor->composite_tristrip (dst, op, src,
  1123.                                            src_x - dst_x, src_y - dst_y,
  1124.                                            dst_x, dst_y,
  1125.                                            extents,
  1126.                                            info->antialias, &info->strip);
  1127. }
  1128.  
  1129. static cairo_bool_t
  1130. is_recording_pattern (const cairo_pattern_t *pattern)
  1131. {
  1132.     cairo_surface_t *surface;
  1133.  
  1134.     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
  1135.         return FALSE;
  1136.  
  1137.     surface = ((const cairo_surface_pattern_t *) pattern)->surface;
  1138.     surface = _cairo_surface_get_source (surface, NULL);
  1139.     return _cairo_surface_is_recording (surface);
  1140. }
  1141.  
  1142. static cairo_surface_t *
  1143. recording_pattern_get_surface (const cairo_pattern_t *pattern)
  1144. {
  1145.     cairo_surface_t *surface;
  1146.  
  1147.     surface = ((const cairo_surface_pattern_t *) pattern)->surface;
  1148.     return _cairo_surface_get_source (surface, NULL);
  1149. }
  1150.  
  1151. static cairo_bool_t
  1152. recording_pattern_contains_sample (const cairo_pattern_t *pattern,
  1153.                                    const cairo_rectangle_int_t *sample)
  1154. {
  1155.     cairo_recording_surface_t *surface;
  1156.  
  1157.     if (! is_recording_pattern (pattern))
  1158.         return FALSE;
  1159.  
  1160.     if (pattern->extend == CAIRO_EXTEND_NONE)
  1161.         return TRUE;
  1162.  
  1163.     surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern);
  1164.     if (surface->unbounded)
  1165.         return TRUE;
  1166.  
  1167.     return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
  1168. }
  1169.  
  1170. static cairo_bool_t
  1171. op_reduces_to_source (cairo_composite_rectangles_t *extents)
  1172. {
  1173.     if (extents->op == CAIRO_OPERATOR_SOURCE)
  1174.         return TRUE;
  1175.  
  1176.     if (extents->surface->is_clear)
  1177.         return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
  1178.  
  1179.     return FALSE;
  1180. }
  1181.  
  1182. static cairo_status_t
  1183. composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
  1184.                          cairo_composite_rectangles_t *extents,
  1185.                          cairo_boxes_t *boxes)
  1186. {
  1187.     cairo_surface_t *dst = extents->surface;
  1188.     cairo_operator_t op = extents->op;
  1189.     cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (extents->clip);
  1190.     cairo_bool_t op_is_source;
  1191.     cairo_status_t status;
  1192.  
  1193.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1194.  
  1195.     if (need_clip_mask &&
  1196.         (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE))
  1197.     {
  1198.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1199.     }
  1200.  
  1201.     op_is_source = op_reduces_to_source (extents);
  1202.  
  1203.     /* Are we just copying a recording surface? */
  1204.     if (! need_clip_mask && op_is_source &&
  1205.         recording_pattern_contains_sample (&extents->source_pattern.base,
  1206.                                            &extents->source_sample_area))
  1207.     {
  1208.         cairo_clip_t *recording_clip;
  1209.         cairo_pattern_t *source = &extents->source_pattern.base;
  1210.  
  1211.         /* XXX could also do tiling repeat modes... */
  1212.  
  1213.         /* first clear the area about to be overwritten */
  1214.         if (! dst->is_clear) {
  1215.             status = compositor->acquire (dst);
  1216.             if (unlikely (status))
  1217.                 return status;
  1218.  
  1219.             status = compositor->fill_boxes (dst,
  1220.                                              CAIRO_OPERATOR_CLEAR,
  1221.                                              CAIRO_COLOR_TRANSPARENT,
  1222.                                              boxes);
  1223.             compositor->release (dst);
  1224.             if (unlikely (status))
  1225.                 return status;
  1226.         }
  1227.  
  1228.         recording_clip = _cairo_clip_from_boxes (boxes);
  1229.         status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
  1230.                                                             &source->matrix,
  1231.                                                             dst, recording_clip);
  1232.         _cairo_clip_destroy (recording_clip);
  1233.  
  1234.         return status;
  1235.     }
  1236.  
  1237.     status = compositor->acquire (dst);
  1238.     if (unlikely (status))
  1239.         return status;
  1240.  
  1241.     if (! need_clip_mask &&
  1242.         (op == CAIRO_OPERATOR_CLEAR ||
  1243.          extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID))
  1244.     {
  1245.         const cairo_color_t *color;
  1246.  
  1247.         if (op == CAIRO_OPERATOR_CLEAR) {
  1248.             color = CAIRO_COLOR_TRANSPARENT;
  1249.         } else {
  1250.             color = &((cairo_solid_pattern_t *) &extents->source_pattern)->color;
  1251.             if (op_is_source)
  1252.                 op = CAIRO_OPERATOR_SOURCE;
  1253.         }
  1254.  
  1255.         status = compositor->fill_boxes (dst, op, color, boxes);
  1256.     }
  1257.     else
  1258.     {
  1259.         cairo_surface_t *src, *mask = NULL;
  1260.         cairo_pattern_t *source = &extents->source_pattern.base;
  1261.         int src_x, src_y;
  1262.         int mask_x = 0, mask_y = 0;
  1263.  
  1264.         if (need_clip_mask) {
  1265.             mask = traps_get_clip_surface (compositor,
  1266.                                            extents, &extents->bounded);
  1267.             if (unlikely (mask->status))
  1268.                 return mask->status;
  1269.  
  1270.             mask_x = -extents->bounded.x;
  1271.             mask_y = -extents->bounded.y;
  1272.  
  1273.             if (op == CAIRO_OPERATOR_CLEAR) {
  1274.                 source = NULL;
  1275.                 op = CAIRO_OPERATOR_DEST_OUT;
  1276.             }
  1277.         } else if (op_is_source)
  1278.             op = CAIRO_OPERATOR_SOURCE;
  1279.  
  1280.         src = compositor->pattern_to_surface (dst, source, FALSE,
  1281.                                               &extents->bounded,
  1282.                                               &extents->source_sample_area,
  1283.                                               &src_x, &src_y);
  1284.         if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
  1285.             status = compositor->composite_boxes (dst, op, src, mask,
  1286.                                                   src_x, src_y,
  1287.                                                   mask_x, mask_y,
  1288.                                                   0, 0,
  1289.                                                   boxes, &extents->bounded);
  1290.             cairo_surface_destroy (src);
  1291.         } else
  1292.             status = src->status;
  1293.  
  1294.         cairo_surface_destroy (mask);
  1295.     }
  1296.  
  1297.     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
  1298.         status = fixup_unbounded (compositor, extents, boxes);
  1299.  
  1300.     compositor->release (dst);
  1301.  
  1302.     return status;
  1303. }
  1304.  
  1305. static cairo_status_t
  1306. upload_boxes (const cairo_traps_compositor_t *compositor,
  1307.               cairo_composite_rectangles_t *extents,
  1308.               cairo_boxes_t *boxes)
  1309. {
  1310.     cairo_surface_t *dst = extents->surface;
  1311.     const cairo_pattern_t *source = &extents->source_pattern.base;
  1312.     cairo_surface_t *src;
  1313.     cairo_rectangle_int_t limit;
  1314.     cairo_int_status_t status;
  1315.     int tx, ty;
  1316.  
  1317.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1318.  
  1319.     src = _cairo_pattern_get_source((cairo_surface_pattern_t *)source,
  1320.                                     &limit);
  1321.     if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
  1322.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1323.  
  1324.     if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
  1325.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1326.  
  1327.     /* Check that the data is entirely within the image */
  1328.     if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
  1329.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1330.  
  1331.     if (extents->bounded.x + extents->bounded.width  + tx > limit.x + limit.width ||
  1332.         extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
  1333.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1334.  
  1335.     tx += limit.x;
  1336.     ty += limit.y;
  1337.  
  1338.     if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
  1339.         status = compositor->draw_image_boxes (dst,
  1340.                                                (cairo_image_surface_t *)src,
  1341.                                                boxes, tx, ty);
  1342.     else
  1343.         status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
  1344.                                          tx, ty);
  1345.  
  1346.     return status;
  1347. }
  1348.  
  1349. static cairo_int_status_t
  1350. trim_extents_to_traps (cairo_composite_rectangles_t *extents,
  1351.                        cairo_traps_t *traps)
  1352. {
  1353.     cairo_box_t box;
  1354.  
  1355.     _cairo_traps_extents (traps, &box);
  1356.     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
  1357. }
  1358.  
  1359. static cairo_int_status_t
  1360. trim_extents_to_tristrip (cairo_composite_rectangles_t *extents,
  1361.                           cairo_tristrip_t *strip)
  1362. {
  1363.     cairo_box_t box;
  1364.  
  1365.     _cairo_tristrip_extents (strip, &box);
  1366.     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
  1367. }
  1368.  
  1369. static cairo_int_status_t
  1370. trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
  1371.                        cairo_boxes_t *boxes)
  1372. {
  1373.     cairo_box_t box;
  1374.  
  1375.     _cairo_boxes_extents (boxes, &box);
  1376.     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
  1377. }
  1378.  
  1379. static cairo_int_status_t
  1380. boxes_for_traps (cairo_boxes_t *boxes,
  1381.                  cairo_traps_t *traps,
  1382.                  cairo_antialias_t antialias)
  1383. {
  1384.     int i;
  1385.  
  1386.     /* first check that the traps are rectilinear */
  1387.     if (antialias == CAIRO_ANTIALIAS_NONE) {
  1388.         for (i = 0; i < traps->num_traps; i++) {
  1389.             const cairo_trapezoid_t *t = &traps->traps[i];
  1390.             if (_cairo_fixed_integer_round_down (t->left.p1.x) !=
  1391.                 _cairo_fixed_integer_round_down (t->left.p2.x) ||
  1392.                 _cairo_fixed_integer_round_down (t->right.p1.x) !=
  1393.                 _cairo_fixed_integer_round_down (t->right.p2.x))
  1394.             {
  1395.                 return CAIRO_INT_STATUS_UNSUPPORTED;
  1396.             }
  1397.         }
  1398.     } else {
  1399.         for (i = 0; i < traps->num_traps; i++) {
  1400.             const cairo_trapezoid_t *t = &traps->traps[i];
  1401.             if (t->left.p1.x != t->left.p2.x || t->right.p1.x != t->right.p2.x)
  1402.                 return CAIRO_INT_STATUS_UNSUPPORTED;
  1403.         }
  1404.     }
  1405.  
  1406.     _cairo_boxes_init (boxes);
  1407.  
  1408.     boxes->num_boxes    = traps->num_traps;
  1409.     boxes->chunks.base  = (cairo_box_t *) traps->traps;
  1410.     boxes->chunks.count = traps->num_traps;
  1411.     boxes->chunks.size  = traps->num_traps;
  1412.  
  1413.     if (antialias != CAIRO_ANTIALIAS_NONE) {
  1414.         for (i = 0; i < traps->num_traps; i++) {
  1415.             /* Note the traps and boxes alias so we need to take the local copies first. */
  1416.             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
  1417.             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
  1418.             cairo_fixed_t y1 = traps->traps[i].top;
  1419.             cairo_fixed_t y2 = traps->traps[i].bottom;
  1420.  
  1421.             boxes->chunks.base[i].p1.x = x1;
  1422.             boxes->chunks.base[i].p1.y = y1;
  1423.             boxes->chunks.base[i].p2.x = x2;
  1424.             boxes->chunks.base[i].p2.y = y2;
  1425.  
  1426.             if (boxes->is_pixel_aligned) {
  1427.                 boxes->is_pixel_aligned =
  1428.                     _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
  1429.                     _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
  1430.             }
  1431.         }
  1432.     } else {
  1433.         boxes->is_pixel_aligned = TRUE;
  1434.  
  1435.         for (i = 0; i < traps->num_traps; i++) {
  1436.             /* Note the traps and boxes alias so we need to take the local copies first. */
  1437.             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
  1438.             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
  1439.             cairo_fixed_t y1 = traps->traps[i].top;
  1440.             cairo_fixed_t y2 = traps->traps[i].bottom;
  1441.  
  1442.             /* round down here to match Pixman's behavior when using traps. */
  1443.             boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
  1444.             boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
  1445.             boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
  1446.             boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
  1447.         }
  1448.     }
  1449.  
  1450.     return CAIRO_INT_STATUS_SUCCESS;
  1451. }
  1452.  
  1453. static cairo_status_t
  1454. clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
  1455.                           cairo_composite_rectangles_t *extents,
  1456.                           cairo_boxes_t *boxes);
  1457.  
  1458. static cairo_status_t
  1459. clip_and_composite_polygon (const cairo_traps_compositor_t *compositor,
  1460.                             cairo_composite_rectangles_t *extents,
  1461.                             cairo_polygon_t *polygon,
  1462.                             cairo_antialias_t antialias,
  1463.                             cairo_fill_rule_t fill_rule,
  1464.                             cairo_bool_t curvy)
  1465. {
  1466.     composite_traps_info_t traps;
  1467.     cairo_surface_t *dst = extents->surface;
  1468.     cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
  1469.     cairo_int_status_t status;
  1470.  
  1471.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1472.  
  1473.     if (polygon->num_edges == 0) {
  1474.         status = CAIRO_INT_STATUS_SUCCESS;
  1475.  
  1476.         if (! extents->is_bounded) {
  1477.             cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
  1478.  
  1479.             if (clip_region &&
  1480.                 cairo_region_contains_rectangle (clip_region,
  1481.                                                  &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
  1482.                 clip_region = NULL;
  1483.  
  1484.             if (clip_region != NULL) {
  1485.                 status = compositor->set_clip_region (dst, clip_region);
  1486.                 if (unlikely (status))
  1487.                     return status;
  1488.             }
  1489.  
  1490.             if (clip_surface)
  1491.                 status = fixup_unbounded_with_mask (compositor, extents);
  1492.             else
  1493.                 status = fixup_unbounded (compositor, extents, NULL);
  1494.  
  1495.             if (clip_region != NULL)
  1496.                 compositor->set_clip_region (dst, NULL);
  1497.         }
  1498.  
  1499.         return status;
  1500.     }
  1501.  
  1502.     if (extents->clip->path != NULL && extents->is_bounded) {
  1503.         cairo_polygon_t clipper;
  1504.         cairo_fill_rule_t clipper_fill_rule;
  1505.         cairo_antialias_t clipper_antialias;
  1506.  
  1507.         status = _cairo_clip_get_polygon (extents->clip,
  1508.                                           &clipper,
  1509.                                           &clipper_fill_rule,
  1510.                                           &clipper_antialias);
  1511.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  1512.             if (clipper_antialias == antialias) {
  1513.                 status = _cairo_polygon_intersect (polygon, fill_rule,
  1514.                                                    &clipper, clipper_fill_rule);
  1515.                 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  1516.                     cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
  1517.                     _cairo_clip_destroy (extents->clip);
  1518.                     extents->clip = clip;
  1519.  
  1520.                     fill_rule = CAIRO_FILL_RULE_WINDING;
  1521.                 }
  1522.                 _cairo_polygon_fini (&clipper);
  1523.             }
  1524.         }
  1525.     }
  1526.  
  1527.     if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
  1528.         cairo_boxes_t boxes;
  1529.  
  1530.         _cairo_boxes_init (&boxes);
  1531.         status = _cairo_rasterise_polygon_to_boxes (polygon, fill_rule, &boxes);
  1532.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  1533.             assert (boxes.is_pixel_aligned);
  1534.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  1535.         }
  1536.         _cairo_boxes_fini (&boxes);
  1537.         if ((status != CAIRO_INT_STATUS_UNSUPPORTED))
  1538.             return status;
  1539.     }
  1540.  
  1541.     _cairo_traps_init (&traps.traps);
  1542.  
  1543.     if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
  1544.         status = _cairo_rasterise_polygon_to_traps (polygon, fill_rule, antialias, &traps.traps);
  1545.     } else {
  1546.         status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
  1547.     }
  1548.     if (unlikely (status))
  1549.         goto CLEANUP_TRAPS;
  1550.  
  1551.     status = trim_extents_to_traps (extents, &traps.traps);
  1552.     if (unlikely (status))
  1553.         goto CLEANUP_TRAPS;
  1554.  
  1555.     /* Use a fast path if the trapezoids consist of a set of boxes.  */
  1556.     status = CAIRO_INT_STATUS_UNSUPPORTED;
  1557.     if (1) {
  1558.         cairo_boxes_t boxes;
  1559.  
  1560.         status = boxes_for_traps (&boxes, &traps.traps, antialias);
  1561.         if (status == CAIRO_INT_STATUS_SUCCESS) {
  1562.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  1563.             /* XXX need to reconstruct the traps! */
  1564.             assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
  1565.         }
  1566.     }
  1567.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  1568.         /* Otherwise render the trapezoids to a mask and composite in the usual
  1569.          * fashion.
  1570.          */
  1571.         unsigned int flags = 0;
  1572.  
  1573.         /* For unbounded operations, the X11 server will estimate the
  1574.          * affected rectangle and apply the operation to that. However,
  1575.          * there are cases where this is an overestimate (e.g. the
  1576.          * clip-fill-{eo,nz}-unbounded test).
  1577.          *
  1578.          * The clip will trim that overestimate to our expectations.
  1579.          */
  1580.         if (! extents->is_bounded)
  1581.             flags |= FORCE_CLIP_REGION;
  1582.  
  1583.         traps.antialias = antialias;
  1584.         status = clip_and_composite (compositor, extents,
  1585.                                      composite_traps, NULL, &traps,
  1586.                                      need_unbounded_clip (extents) | flags);
  1587.     }
  1588.  
  1589. CLEANUP_TRAPS:
  1590.     _cairo_traps_fini (&traps.traps);
  1591.  
  1592.     return status;
  1593. }
  1594.  
  1595. struct composite_opacity_info {
  1596.     const cairo_traps_compositor_t *compositor;
  1597.     uint8_t op;
  1598.     cairo_surface_t *dst;
  1599.     cairo_surface_t *src;
  1600.     int src_x, src_y;
  1601.     double opacity;
  1602. };
  1603.  
  1604. static void composite_opacity(void *closure,
  1605.                               int16_t x, int16_t y,
  1606.                               int16_t w, int16_t h,
  1607.                               uint16_t coverage)
  1608. {
  1609.     struct composite_opacity_info *info = closure;
  1610.     const cairo_traps_compositor_t *compositor = info->compositor;
  1611.     cairo_surface_t *mask;
  1612.     int mask_x, mask_y;
  1613.     cairo_color_t color;
  1614.     cairo_solid_pattern_t solid;
  1615.  
  1616.     _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
  1617.     _cairo_pattern_init_solid (&solid, &color);
  1618.     mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
  1619.                                            &_cairo_unbounded_rectangle,
  1620.                                            &_cairo_unbounded_rectangle,
  1621.                                            &mask_x, &mask_y);
  1622.     if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
  1623.         if (info->src) {
  1624.             compositor->composite (info->dst, info->op, info->src, mask,
  1625.                                    x + info->src_x,  y + info->src_y,
  1626.                                    mask_x,           mask_y,
  1627.                                    x,                y,
  1628.                                    w,                h);
  1629.         } else {
  1630.             compositor->composite (info->dst, info->op, mask, NULL,
  1631.                                    mask_x,            mask_y,
  1632.                                    0,                 0,
  1633.                                    x,                 y,
  1634.                                    w,                 h);
  1635.         }
  1636.     }
  1637.  
  1638.     cairo_surface_destroy (mask);
  1639. }
  1640.  
  1641.  
  1642. static cairo_int_status_t
  1643. composite_opacity_boxes (const cairo_traps_compositor_t *compositor,
  1644.                          cairo_surface_t                *dst,
  1645.                          void                           *closure,
  1646.                          cairo_operator_t                op,
  1647.                          cairo_surface_t                *src,
  1648.                          int                             src_x,
  1649.                          int                             src_y,
  1650.                          int                             dst_x,
  1651.                          int                             dst_y,
  1652.                          const cairo_rectangle_int_t    *extents,
  1653.                          cairo_clip_t                   *clip)
  1654. {
  1655.     const cairo_solid_pattern_t *mask = closure;
  1656.     struct composite_opacity_info info;
  1657.     int i;
  1658.  
  1659.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1660.  
  1661.     info.compositor = compositor;
  1662.     info.op = op;
  1663.     info.dst = dst;
  1664.  
  1665.     info.src = src;
  1666.     info.src_x = src_x;
  1667.     info.src_y = src_y;
  1668.  
  1669.     info.opacity = mask->color.alpha / (double) 0xffff;
  1670.  
  1671.     /* XXX for lots of boxes create a clip region for the fully opaque areas */
  1672.     for (i = 0; i < clip->num_boxes; i++)
  1673.         do_unaligned_box(composite_opacity, &info,
  1674.                          &clip->boxes[i], dst_x, dst_y);
  1675.  
  1676.     return CAIRO_STATUS_SUCCESS;
  1677. }
  1678.  
  1679. static cairo_int_status_t
  1680. composite_boxes (const cairo_traps_compositor_t *compositor,
  1681.                  cairo_surface_t                *dst,
  1682.                  void                           *closure,
  1683.                  cairo_operator_t                op,
  1684.                  cairo_surface_t                *src,
  1685.                  int                             src_x,
  1686.                  int                             src_y,
  1687.                  int                             dst_x,
  1688.                  int                             dst_y,
  1689.                  const cairo_rectangle_int_t    *extents,
  1690.                  cairo_clip_t                   *clip)
  1691. {
  1692.     cairo_traps_t traps;
  1693.     cairo_status_t status;
  1694.  
  1695.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1696.  
  1697.     status = _cairo_traps_init_boxes (&traps, closure);
  1698.     if (unlikely (status))
  1699.         return status;
  1700.  
  1701.     status = compositor->composite_traps (dst, op, src,
  1702.                                           src_x - dst_x, src_y - dst_y,
  1703.                                           dst_x, dst_y,
  1704.                                           extents,
  1705.                                           CAIRO_ANTIALIAS_DEFAULT, &traps);
  1706.     _cairo_traps_fini (&traps);
  1707.  
  1708.     return status;
  1709. }
  1710.  
  1711. static cairo_status_t
  1712. clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
  1713.                           cairo_composite_rectangles_t *extents,
  1714.                           cairo_boxes_t *boxes)
  1715. {
  1716.     cairo_int_status_t status;
  1717.  
  1718.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1719.  
  1720.     if (boxes->num_boxes == 0 && extents->is_bounded)
  1721.         return CAIRO_STATUS_SUCCESS;
  1722.  
  1723.     status = trim_extents_to_boxes (extents, boxes);
  1724.     if (unlikely (status))
  1725.         return status;
  1726.  
  1727.     if (boxes->is_pixel_aligned && extents->clip->path == NULL &&
  1728.         extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
  1729.         (op_reduces_to_source (extents) ||
  1730.          (extents->op == CAIRO_OPERATOR_OVER &&
  1731.           (extents->source_pattern.surface.surface->content & CAIRO_CONTENT_ALPHA) == 0)))
  1732.     {
  1733.         status = upload_boxes (compositor, extents, boxes);
  1734.         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  1735.             return status;
  1736.     }
  1737.  
  1738.     /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
  1739.     if (extents->clip->path != NULL && extents->is_bounded) {
  1740.         cairo_polygon_t polygon;
  1741.         cairo_fill_rule_t fill_rule;
  1742.         cairo_antialias_t antialias;
  1743.         cairo_clip_t *clip;
  1744.  
  1745.         clip = _cairo_clip_copy (extents->clip);
  1746.         clip = _cairo_clip_intersect_boxes (clip, boxes);
  1747.         if (_cairo_clip_is_all_clipped (clip))
  1748.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  1749.  
  1750.         status = _cairo_clip_get_polygon (clip, &polygon,
  1751.                                           &fill_rule, &antialias);
  1752.         _cairo_clip_path_destroy (clip->path);
  1753.         clip->path = NULL;
  1754.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  1755.             cairo_clip_t *saved_clip = extents->clip;
  1756.             extents->clip = clip;
  1757.  
  1758.             status = clip_and_composite_polygon (compositor, extents, &polygon,
  1759.                                                  antialias, fill_rule, FALSE);
  1760.  
  1761.             clip = extents->clip;
  1762.             extents->clip = saved_clip;
  1763.  
  1764.             _cairo_polygon_fini (&polygon);
  1765.         }
  1766.         _cairo_clip_destroy (clip);
  1767.  
  1768.         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  1769.             return status;
  1770.     }
  1771.  
  1772.     /* Use a fast path if the boxes are pixel aligned (or nearly aligned!) */
  1773.     if (boxes->is_pixel_aligned) {
  1774.         status = composite_aligned_boxes (compositor, extents, boxes);
  1775.         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  1776.             return status;
  1777.     }
  1778.  
  1779.     return clip_and_composite (compositor, extents,
  1780.                                composite_boxes, NULL, boxes,
  1781.                                need_unbounded_clip (extents));
  1782. }
  1783.  
  1784. static cairo_int_status_t
  1785. composite_traps_as_boxes (const cairo_traps_compositor_t *compositor,
  1786.                           cairo_composite_rectangles_t *extents,
  1787.                           composite_traps_info_t *info)
  1788. {
  1789.     cairo_boxes_t boxes;
  1790.  
  1791.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1792.  
  1793.     if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes))
  1794.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1795.  
  1796.     return clip_and_composite_boxes (compositor, extents, &boxes);
  1797. }
  1798.  
  1799. static cairo_int_status_t
  1800. clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
  1801.                           cairo_composite_rectangles_t *extents,
  1802.                           composite_traps_info_t *info,
  1803.                           unsigned flags)
  1804. {
  1805.     cairo_int_status_t status;
  1806.  
  1807.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1808.  
  1809.     status = trim_extents_to_traps (extents, &info->traps);
  1810.     if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
  1811.         return status;
  1812.  
  1813.     status = CAIRO_INT_STATUS_UNSUPPORTED;
  1814.     if ((flags & FORCE_CLIP_REGION) == 0)
  1815.         status = composite_traps_as_boxes (compositor, extents, info);
  1816.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  1817.         /* For unbounded operations, the X11 server will estimate the
  1818.          * affected rectangle and apply the operation to that. However,
  1819.          * there are cases where this is an overestimate (e.g. the
  1820.          * clip-fill-{eo,nz}-unbounded test).
  1821.          *
  1822.          * The clip will trim that overestimate to our expectations.
  1823.          */
  1824.         if (! extents->is_bounded)
  1825.             flags |= FORCE_CLIP_REGION;
  1826.  
  1827.         status = clip_and_composite (compositor, extents,
  1828.                                      composite_traps, NULL, info,
  1829.                                      need_unbounded_clip (extents) | flags);
  1830.     }
  1831.  
  1832.     return status;
  1833. }
  1834.  
  1835. static cairo_int_status_t
  1836. clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor,
  1837.                              cairo_composite_rectangles_t *extents,
  1838.                              composite_tristrip_info_t *info)
  1839. {
  1840.     cairo_int_status_t status;
  1841.     unsigned int flags = 0;
  1842.  
  1843.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1844.  
  1845.     status = trim_extents_to_tristrip (extents, &info->strip);
  1846.     if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
  1847.         return status;
  1848.  
  1849.     if (! extents->is_bounded)
  1850.         flags |= FORCE_CLIP_REGION;
  1851.  
  1852.     status = clip_and_composite (compositor, extents,
  1853.                                  composite_tristrip, NULL, info,
  1854.                                  need_unbounded_clip (extents) | flags);
  1855.  
  1856.     return status;
  1857. }
  1858.  
  1859. struct composite_mask {
  1860.     cairo_surface_t *mask;
  1861.     int mask_x, mask_y;
  1862. };
  1863.  
  1864. static cairo_int_status_t
  1865. composite_mask (const cairo_traps_compositor_t *compositor,
  1866.                 cairo_surface_t                 *dst,
  1867.                 void                            *closure,
  1868.                 cairo_operator_t                 op,
  1869.                 cairo_surface_t                 *src,
  1870.                 int                              src_x,
  1871.                 int                              src_y,
  1872.                 int                              dst_x,
  1873.                 int                              dst_y,
  1874.                 const cairo_rectangle_int_t     *extents,
  1875.                 cairo_clip_t                    *clip)
  1876. {
  1877.     struct composite_mask *data = closure;
  1878.  
  1879.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1880.  
  1881.     if (src != NULL) {
  1882.         compositor->composite (dst, op, src, data->mask,
  1883.                                extents->x + src_x, extents->y + src_y,
  1884.                                extents->x + data->mask_x, extents->y + data->mask_y,
  1885.                                extents->x - dst_x,  extents->y - dst_y,
  1886.                                extents->width,      extents->height);
  1887.     } else {
  1888.         compositor->composite (dst, op, data->mask, NULL,
  1889.                                extents->x + data->mask_x, extents->y + data->mask_y,
  1890.                                0, 0,
  1891.                                extents->x - dst_x,  extents->y - dst_y,
  1892.                                extents->width,      extents->height);
  1893.     }
  1894.  
  1895.     return CAIRO_STATUS_SUCCESS;
  1896. }
  1897.  
  1898. struct composite_box_info {
  1899.     const cairo_traps_compositor_t *compositor;
  1900.     cairo_surface_t *dst;
  1901.     cairo_surface_t *src;
  1902.     int src_x, src_y;
  1903.     uint8_t op;
  1904. };
  1905.  
  1906. static void composite_box(void *closure,
  1907.                           int16_t x, int16_t y,
  1908.                           int16_t w, int16_t h,
  1909.                           uint16_t coverage)
  1910. {
  1911.     struct composite_box_info *info = closure;
  1912.     const cairo_traps_compositor_t *compositor = info->compositor;
  1913.  
  1914.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1915.  
  1916.     if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
  1917.         cairo_surface_t *mask;
  1918.         cairo_color_t color;
  1919.         cairo_solid_pattern_t solid;
  1920.         int mask_x, mask_y;
  1921.  
  1922.         _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
  1923.         _cairo_pattern_init_solid (&solid, &color);
  1924.  
  1925.         mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
  1926.                                                &_cairo_unbounded_rectangle,
  1927.                                                &_cairo_unbounded_rectangle,
  1928.                                                &mask_x, &mask_y);
  1929.  
  1930.         if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
  1931.             compositor->composite (info->dst, info->op, info->src, mask,
  1932.                                    x + info->src_x,  y + info->src_y,
  1933.                                    mask_x,           mask_y,
  1934.                                    x,                y,
  1935.                                    w,                h);
  1936.         }
  1937.  
  1938.         cairo_surface_destroy (mask);
  1939.     } else {
  1940.         compositor->composite (info->dst, info->op, info->src, NULL,
  1941.                                x + info->src_x,  y + info->src_y,
  1942.                                0,                0,
  1943.                                x,                y,
  1944.                                w,                h);
  1945.     }
  1946. }
  1947.  
  1948. static cairo_int_status_t
  1949. composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor,
  1950.                            cairo_surface_t              *dst,
  1951.                            void                         *closure,
  1952.                            cairo_operator_t              op,
  1953.                            cairo_surface_t              *src,
  1954.                            int                           src_x,
  1955.                            int                           src_y,
  1956.                            int                           dst_x,
  1957.                            int                           dst_y,
  1958.                            const cairo_rectangle_int_t  *extents,
  1959.                            cairo_clip_t                 *clip)
  1960. {
  1961.     struct composite_mask *data = closure;
  1962.     struct composite_box_info info;
  1963.     int i;
  1964.  
  1965.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1966.  
  1967.     info.compositor = compositor;
  1968.     info.op = CAIRO_OPERATOR_SOURCE;
  1969.     info.dst = dst;
  1970.     info.src = data->mask;
  1971.     info.src_x = data->mask_x;
  1972.     info.src_y = data->mask_y;
  1973.  
  1974.     info.src_x += dst_x;
  1975.     info.src_y += dst_y;
  1976.  
  1977.     for (i = 0; i < clip->num_boxes; i++)
  1978.         do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
  1979.  
  1980.     return CAIRO_STATUS_SUCCESS;
  1981. }
  1982.  
  1983. static cairo_int_status_t
  1984. composite_mask_clip (const cairo_traps_compositor_t *compositor,
  1985.                      cairo_surface_t                    *dst,
  1986.                      void                               *closure,
  1987.                      cairo_operator_t                    op,
  1988.                      cairo_surface_t                    *src,
  1989.                      int                                 src_x,
  1990.                      int                                 src_y,
  1991.                      int                                 dst_x,
  1992.                      int                                 dst_y,
  1993.                      const cairo_rectangle_int_t        *extents,
  1994.                      cairo_clip_t                       *clip)
  1995. {
  1996.     struct composite_mask *data = closure;
  1997.     cairo_polygon_t polygon;
  1998.     cairo_fill_rule_t fill_rule;
  1999.     composite_traps_info_t info;
  2000.     cairo_status_t status;
  2001.  
  2002.     TRACE ((stderr, "%s\n", __FUNCTION__));
  2003.  
  2004.     status = _cairo_clip_get_polygon (clip, &polygon,
  2005.                                       &fill_rule, &info.antialias);
  2006.     if (unlikely (status))
  2007.         return status;
  2008.  
  2009.     _cairo_traps_init (&info.traps);
  2010.     status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
  2011.                                                         &polygon,
  2012.                                                         fill_rule);
  2013.     _cairo_polygon_fini (&polygon);
  2014.     if (unlikely (status))
  2015.         return status;
  2016.  
  2017.     status = composite_traps (compositor, dst, &info,
  2018.                               CAIRO_OPERATOR_SOURCE,
  2019.                               data->mask,
  2020.                               data->mask_x + dst_x, data->mask_y + dst_y,
  2021.                               dst_x, dst_y,
  2022.                               extents, NULL);
  2023.     _cairo_traps_fini (&info.traps);
  2024.  
  2025.     return status;
  2026. }
  2027.  
  2028. /* high-level compositor interface */
  2029.  
  2030. static cairo_int_status_t
  2031. _cairo_traps_compositor_paint (const cairo_compositor_t *_compositor,
  2032.                                cairo_composite_rectangles_t *extents)
  2033. {
  2034.     cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
  2035.     cairo_boxes_t boxes;
  2036.     cairo_int_status_t status;
  2037.  
  2038.     TRACE ((stderr, "%s\n", __FUNCTION__));
  2039.  
  2040.     status = compositor->check_composite (extents);
  2041.     if (unlikely (status))
  2042.         return status;
  2043.  
  2044.      _cairo_clip_steal_boxes (extents->clip, &boxes);
  2045.      status = clip_and_composite_boxes (compositor, extents, &boxes);
  2046.      _cairo_clip_unsteal_boxes (extents->clip, &boxes);
  2047.  
  2048.     return status;
  2049. }
  2050.  
  2051. static cairo_int_status_t
  2052. _cairo_traps_compositor_mask (const cairo_compositor_t *_compositor,
  2053.                               cairo_composite_rectangles_t *extents)
  2054. {
  2055.     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
  2056.     cairo_int_status_t status;
  2057.  
  2058.     TRACE ((stderr, "%s\n", __FUNCTION__));
  2059.  
  2060.     status = compositor->check_composite (extents);
  2061.     if (unlikely (status))
  2062.         return status;
  2063.  
  2064.     if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
  2065.         extents->clip->path == NULL) {
  2066.         status = clip_and_composite (compositor, extents,
  2067.                                      composite_opacity_boxes,
  2068.                                      composite_opacity_boxes,
  2069.                                      &extents->mask_pattern,
  2070.                                      need_unbounded_clip (extents));
  2071.     } else {
  2072.         struct composite_mask data;
  2073.  
  2074.         data.mask = compositor->pattern_to_surface (extents->surface,
  2075.                                                     &extents->mask_pattern.base,
  2076.                                                     TRUE,
  2077.                                                     &extents->bounded,
  2078.                                                     &extents->mask_sample_area,
  2079.                                                     &data.mask_x,
  2080.                                                     &data.mask_y);
  2081.         if (unlikely (data.mask->status))
  2082.             return data.mask->status;
  2083.  
  2084.         status = clip_and_composite (compositor, extents,
  2085.                                      composite_mask,
  2086.                                      extents->clip->path ? composite_mask_clip : composite_mask_clip_boxes,
  2087.                                      &data, need_bounded_clip (extents));
  2088.  
  2089.         cairo_surface_destroy (data.mask);
  2090.     }
  2091.  
  2092.     return status;
  2093. }
  2094.  
  2095. static cairo_int_status_t
  2096. _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor,
  2097.                                 cairo_composite_rectangles_t *extents,
  2098.                                 const cairo_path_fixed_t *path,
  2099.                                 const cairo_stroke_style_t *style,
  2100.                                 const cairo_matrix_t    *ctm,
  2101.                                 const cairo_matrix_t    *ctm_inverse,
  2102.                                 double                   tolerance,
  2103.                                 cairo_antialias_t        antialias)
  2104. {
  2105.     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
  2106.     cairo_int_status_t status;
  2107.  
  2108.     TRACE ((stderr, "%s\n", __FUNCTION__));
  2109.  
  2110.     status = compositor->check_composite (extents);
  2111.     if (unlikely (status))
  2112.         return status;
  2113.  
  2114.     status = CAIRO_INT_STATUS_UNSUPPORTED;
  2115.     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
  2116.         cairo_boxes_t boxes;
  2117.  
  2118.         _cairo_boxes_init_with_clip (&boxes, extents->clip);
  2119.         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
  2120.                                                                 style,
  2121.                                                                 ctm,
  2122.                                                                 antialias,
  2123.                                                                 &boxes);
  2124.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  2125.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  2126.         _cairo_boxes_fini (&boxes);
  2127.     }
  2128.  
  2129.     if (status == CAIRO_INT_STATUS_UNSUPPORTED && 0 &&
  2130.         _cairo_clip_is_region (extents->clip)) /* XXX */
  2131.     {
  2132.         composite_tristrip_info_t info;
  2133.  
  2134.         info.antialias = antialias;
  2135.         _cairo_tristrip_init_with_clip (&info.strip, extents->clip);
  2136.         status = _cairo_path_fixed_stroke_to_tristrip (path, style,
  2137.                                                        ctm, ctm_inverse,
  2138.                                                        tolerance,
  2139.                                                        &info.strip);
  2140.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  2141.             status = clip_and_composite_tristrip (compositor, extents, &info);
  2142.         _cairo_tristrip_fini (&info.strip);
  2143.     }
  2144.  
  2145.     if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
  2146.         path->has_curve_to && antialias == CAIRO_ANTIALIAS_NONE) {
  2147.         cairo_polygon_t polygon;
  2148.  
  2149.         _cairo_polygon_init_with_clip (&polygon, extents->clip);
  2150.         status = _cairo_path_fixed_stroke_to_polygon (path, style,
  2151.                                                       ctm, ctm_inverse,
  2152.                                                       tolerance,
  2153.                                                       &polygon);
  2154.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  2155.             status = clip_and_composite_polygon (compositor,
  2156.                                                  extents, &polygon,
  2157.                                                  CAIRO_ANTIALIAS_NONE,
  2158.                                                  CAIRO_FILL_RULE_WINDING,
  2159.                                                  TRUE);
  2160.         _cairo_polygon_fini (&polygon);
  2161.     }
  2162.  
  2163.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  2164.         cairo_int_status_t (*func) (const cairo_path_fixed_t    *path,
  2165.                                     const cairo_stroke_style_t  *stroke_style,
  2166.                                     const cairo_matrix_t        *ctm,
  2167.                                     const cairo_matrix_t        *ctm_inverse,
  2168.                                     double                       tolerance,
  2169.                                     cairo_traps_t               *traps);
  2170.         composite_traps_info_t info;
  2171.         unsigned flags;
  2172.  
  2173.         if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) {
  2174.             func = _cairo_path_fixed_stroke_polygon_to_traps;
  2175.             flags = 0;
  2176.         } else {
  2177.             func = _cairo_path_fixed_stroke_to_traps;
  2178.             flags = need_bounded_clip (extents) & ~NEED_CLIP_SURFACE;
  2179.         }
  2180.  
  2181.         info.antialias = antialias;
  2182.         _cairo_traps_init_with_clip (&info.traps, extents->clip);
  2183.         status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps);
  2184.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  2185.             status = clip_and_composite_traps (compositor, extents, &info, flags);
  2186.         _cairo_traps_fini (&info.traps);
  2187.     }
  2188.  
  2189.     return status;
  2190. }
  2191.  
  2192. static cairo_int_status_t
  2193. _cairo_traps_compositor_fill (const cairo_compositor_t *_compositor,
  2194.                               cairo_composite_rectangles_t *extents,
  2195.                               const cairo_path_fixed_t  *path,
  2196.                               cairo_fill_rule_t          fill_rule,
  2197.                               double                     tolerance,
  2198.                               cairo_antialias_t          antialias)
  2199. {
  2200.     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
  2201.     cairo_int_status_t status;
  2202.  
  2203.     TRACE ((stderr, "%s\n", __FUNCTION__));
  2204.  
  2205.     status = compositor->check_composite (extents);
  2206.     if (unlikely (status))
  2207.         return status;
  2208.  
  2209.     status = CAIRO_INT_STATUS_UNSUPPORTED;
  2210.     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
  2211.         cairo_boxes_t boxes;
  2212.  
  2213.         _cairo_boxes_init_with_clip (&boxes, extents->clip);
  2214.         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
  2215.                                                               fill_rule,
  2216.                                                               antialias,
  2217.                                                               &boxes);
  2218.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  2219.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  2220.         _cairo_boxes_fini (&boxes);
  2221.     }
  2222.  
  2223.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  2224.         cairo_polygon_t polygon;
  2225.  
  2226. #if 0
  2227.         if (extents->mask.width  > extents->unbounded.width ||
  2228.             extents->mask.height > extents->unbounded.height)
  2229.         {
  2230.             cairo_box_t limits;
  2231.             _cairo_box_from_rectangle (&limits, &extents->unbounded);
  2232.             _cairo_polygon_init (&polygon, &limits, 1);
  2233.         }
  2234.         else
  2235.         {
  2236.             _cairo_polygon_init (&polygon, NULL, 0);
  2237.         }
  2238.  
  2239.         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
  2240.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  2241.             status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
  2242.                                                           extents->clip->boxes,
  2243.                                                           extents->clip->num_boxes);
  2244.         }
  2245. #else
  2246.         _cairo_polygon_init_with_clip (&polygon, extents->clip);
  2247.         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
  2248. #endif
  2249.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  2250.             status = clip_and_composite_polygon (compositor, extents, &polygon,
  2251.                                                  antialias, fill_rule, path->has_curve_to);
  2252.         }
  2253.         _cairo_polygon_fini (&polygon);
  2254.     }
  2255.  
  2256.     return status;
  2257. }
  2258.  
  2259. static cairo_int_status_t
  2260. composite_glyphs (const cairo_traps_compositor_t *compositor,
  2261.                   cairo_surface_t       *dst,
  2262.                   void *closure,
  2263.                   cairo_operator_t       op,
  2264.                   cairo_surface_t       *src,
  2265.                   int src_x, int src_y,
  2266.                   int dst_x, int dst_y,
  2267.                   const cairo_rectangle_int_t *extents,
  2268.                   cairo_clip_t          *clip)
  2269. {
  2270.     cairo_composite_glyphs_info_t *info = closure;
  2271.  
  2272.     TRACE ((stderr, "%s\n", __FUNCTION__));
  2273.  
  2274.     if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0)
  2275.         info->use_mask = 0;
  2276.  
  2277.     return compositor->composite_glyphs (dst, op, src,
  2278.                                          src_x, src_y,
  2279.                                          dst_x, dst_y,
  2280.                                          info);
  2281. }
  2282.  
  2283. static cairo_int_status_t
  2284. _cairo_traps_compositor_glyphs (const cairo_compositor_t        *_compositor,
  2285.                                 cairo_composite_rectangles_t    *extents,
  2286.                                 cairo_scaled_font_t             *scaled_font,
  2287.                                 cairo_glyph_t                   *glyphs,
  2288.                                 int                              num_glyphs,
  2289.                                 cairo_bool_t                     overlap)
  2290. {
  2291.     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
  2292.     cairo_int_status_t status;
  2293.  
  2294.     TRACE ((stderr, "%s\n", __FUNCTION__));
  2295.  
  2296.     status = compositor->check_composite (extents);
  2297.     if (unlikely (status))
  2298.         return status;
  2299.  
  2300.     _cairo_scaled_font_freeze_cache (scaled_font);
  2301.     status = compositor->check_composite_glyphs (extents,
  2302.                                                  scaled_font, glyphs,
  2303.                                                  &num_glyphs);
  2304.     if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  2305.         cairo_composite_glyphs_info_t info;
  2306.  
  2307.         info.font = scaled_font;
  2308.         info.glyphs = glyphs;
  2309.         info.num_glyphs = num_glyphs;
  2310.         info.use_mask = overlap || ! extents->is_bounded;
  2311.         info.extents = extents->bounded;
  2312.  
  2313.         status = clip_and_composite (compositor, extents,
  2314.                                      composite_glyphs, NULL, &info,
  2315.                                      need_bounded_clip (extents) | FORCE_CLIP_REGION);
  2316.     }
  2317.     _cairo_scaled_font_thaw_cache (scaled_font);
  2318.  
  2319.     return status;
  2320. }
  2321.  
  2322. void
  2323. _cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
  2324.                               const cairo_compositor_t  *delegate)
  2325. {
  2326.     compositor->base.delegate = delegate;
  2327.  
  2328.     compositor->base.paint = _cairo_traps_compositor_paint;
  2329.     compositor->base.mask = _cairo_traps_compositor_mask;
  2330.     compositor->base.fill = _cairo_traps_compositor_fill;
  2331.     compositor->base.stroke = _cairo_traps_compositor_stroke;
  2332.     compositor->base.glyphs = _cairo_traps_compositor_glyphs;
  2333. }
  2334.