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-compositor-private.h"
  45. #include "cairo-clip-inline.h"
  46. #include "cairo-clip-private.h"
  47. #include "cairo-image-surface-private.h"
  48. #include "cairo-paginated-private.h"
  49. #include "cairo-pattern-inline.h"
  50. #include "cairo-region-private.h"
  51. #include "cairo-recording-surface-inline.h"
  52. #include "cairo-spans-compositor-private.h"
  53. #include "cairo-surface-subsurface-private.h"
  54. #include "cairo-surface-snapshot-private.h"
  55. #include "cairo-surface-observer-private.h"
  56.  
  57. typedef struct {
  58.     cairo_polygon_t     *polygon;
  59.     cairo_fill_rule_t    fill_rule;
  60.     cairo_antialias_t    antialias;
  61. } composite_spans_info_t;
  62.  
  63. static cairo_int_status_t
  64. composite_polygon (const cairo_spans_compositor_t       *compositor,
  65.                    cairo_composite_rectangles_t          *extents,
  66.                    cairo_polygon_t                      *polygon,
  67.                    cairo_fill_rule_t                     fill_rule,
  68.                    cairo_antialias_t                     antialias);
  69.  
  70. static cairo_int_status_t
  71. composite_boxes (const cairo_spans_compositor_t *compositor,
  72.                  cairo_composite_rectangles_t *extents,
  73.                  cairo_boxes_t          *boxes);
  74.  
  75. static cairo_int_status_t
  76. clip_and_composite_polygon (const cairo_spans_compositor_t      *compositor,
  77.                             cairo_composite_rectangles_t         *extents,
  78.                             cairo_polygon_t                     *polygon,
  79.                             cairo_fill_rule_t                    fill_rule,
  80.                             cairo_antialias_t                    antialias);
  81. static cairo_surface_t *
  82. get_clip_surface (const cairo_spans_compositor_t *compositor,
  83.                   cairo_surface_t *dst,
  84.                   const cairo_clip_t *clip,
  85.                   const cairo_rectangle_int_t *extents)
  86. {
  87.     cairo_composite_rectangles_t composite;
  88.     cairo_surface_t *surface;
  89.     cairo_box_t box;
  90.     cairo_polygon_t polygon;
  91.     const cairo_clip_path_t *clip_path;
  92.     cairo_antialias_t antialias;
  93.     cairo_fill_rule_t fill_rule;
  94.     cairo_int_status_t status;
  95.  
  96.     assert (clip->path);
  97.  
  98.     surface = _cairo_surface_create_similar_solid (dst,
  99.                                                    CAIRO_CONTENT_ALPHA,
  100.                                                    extents->width,
  101.                                                    extents->height,
  102.                                                    CAIRO_COLOR_TRANSPARENT);
  103.  
  104.     _cairo_box_from_rectangle (&box, extents);
  105.     _cairo_polygon_init (&polygon, &box, 1);
  106.  
  107.     clip_path = clip->path;
  108.     status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
  109.                                                 clip_path->tolerance,
  110.                                                 &polygon);
  111.     if (unlikely (status))
  112.         goto cleanup_polygon;
  113.  
  114.     polygon.num_limits = 0;
  115.  
  116.     antialias = clip_path->antialias;
  117.     fill_rule = clip_path->fill_rule;
  118.  
  119.     if (clip->boxes) {
  120.         cairo_polygon_t intersect;
  121.         cairo_boxes_t tmp;
  122.  
  123.         _cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes);
  124.         status= _cairo_polygon_init_boxes (&intersect, &tmp);
  125.         if (unlikely (status))
  126.             goto cleanup_polygon;
  127.  
  128.         status = _cairo_polygon_intersect (&polygon, fill_rule,
  129.                                            &intersect, CAIRO_FILL_RULE_WINDING);
  130.         _cairo_polygon_fini (&intersect);
  131.  
  132.         if (unlikely (status))
  133.             goto cleanup_polygon;
  134.  
  135.         fill_rule = CAIRO_FILL_RULE_WINDING;
  136.     }
  137.  
  138.     polygon.limits = NULL;
  139.     polygon.num_limits = 0;
  140.  
  141.     clip_path = clip_path->prev;
  142.     while (clip_path) {
  143.         if (clip_path->antialias == antialias) {
  144.             cairo_polygon_t next;
  145.  
  146.             _cairo_polygon_init (&next, NULL, 0);
  147.             status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
  148.                                                         clip_path->tolerance,
  149.                                                         &next);
  150.             if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  151.                 status = _cairo_polygon_intersect (&polygon, fill_rule,
  152.                                                    &next, clip_path->fill_rule);
  153.             _cairo_polygon_fini (&next);
  154.             if (unlikely (status))
  155.                 goto cleanup_polygon;
  156.  
  157.             fill_rule = CAIRO_FILL_RULE_WINDING;
  158.         }
  159.  
  160.         clip_path = clip_path->prev;
  161.     }
  162.  
  163.     _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
  164.     status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
  165.                                                            CAIRO_OPERATOR_ADD,
  166.                                                            &_cairo_pattern_white.base,
  167.                                                            &polygon,
  168.                                                            NULL);
  169.     if (unlikely (status))
  170.         goto cleanup_polygon;
  171.  
  172.     status = composite_polygon (compositor, &composite,
  173.                                 &polygon, fill_rule, antialias);
  174.     _cairo_composite_rectangles_fini (&composite);
  175.     _cairo_polygon_fini (&polygon);
  176.     if (unlikely (status))
  177.         goto error;
  178.  
  179.     _cairo_polygon_init (&polygon, &box, 1);
  180.  
  181.     clip_path = clip->path;
  182.     antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
  183.     clip_path = clip_path->prev;
  184.     while (clip_path) {
  185.         if (clip_path->antialias == antialias) {
  186.             if (polygon.num_edges == 0) {
  187.                 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
  188.                                                             clip_path->tolerance,
  189.                                                             &polygon);
  190.  
  191.                 fill_rule = clip_path->fill_rule;
  192.                 polygon.limits = NULL;
  193.                 polygon.num_limits = 0;
  194.             } else {
  195.                 cairo_polygon_t next;
  196.  
  197.                 _cairo_polygon_init (&next, NULL, 0);
  198.                 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
  199.                                                             clip_path->tolerance,
  200.                                                             &next);
  201.                 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  202.                     status = _cairo_polygon_intersect (&polygon, fill_rule,
  203.                                                        &next, clip_path->fill_rule);
  204.                 _cairo_polygon_fini (&next);
  205.                 fill_rule = CAIRO_FILL_RULE_WINDING;
  206.             }
  207.             if (unlikely (status))
  208.                 goto error;
  209.         }
  210.  
  211.         clip_path = clip_path->prev;
  212.     }
  213.  
  214.     if (polygon.num_edges) {
  215.         _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
  216.         status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
  217.                                                                CAIRO_OPERATOR_IN,
  218.                                                                &_cairo_pattern_white.base,
  219.                                                                &polygon,
  220.                                                                NULL);
  221.         if (unlikely (status))
  222.             goto cleanup_polygon;
  223.  
  224.         status = composite_polygon (compositor, &composite,
  225.                                     &polygon, fill_rule, antialias);
  226.         _cairo_composite_rectangles_fini (&composite);
  227.         _cairo_polygon_fini (&polygon);
  228.         if (unlikely (status))
  229.             goto error;
  230.     }
  231.  
  232.     return surface;
  233.  
  234. cleanup_polygon:
  235.     _cairo_polygon_fini (&polygon);
  236. error:
  237.     cairo_surface_destroy (surface);
  238.     return _cairo_int_surface_create_in_error (status);
  239. }
  240.  
  241. static cairo_int_status_t
  242. fixup_unbounded_mask (const cairo_spans_compositor_t *compositor,
  243.                       const cairo_composite_rectangles_t *extents,
  244.                       cairo_boxes_t *boxes)
  245. {
  246.     cairo_composite_rectangles_t composite;
  247.     cairo_surface_t *clip;
  248.     cairo_int_status_t status;
  249.  
  250.     TRACE((stderr, "%s\n", __FUNCTION__));
  251.  
  252.     clip = get_clip_surface (compositor, extents->surface, extents->clip,
  253.                              &extents->unbounded);
  254.     if (unlikely (clip->status)) {
  255.         if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO)
  256.             return CAIRO_STATUS_SUCCESS;
  257.  
  258.         return clip->status;
  259.     }
  260.  
  261.     status = _cairo_composite_rectangles_init_for_boxes (&composite,
  262.                                                          extents->surface,
  263.                                                          CAIRO_OPERATOR_CLEAR,
  264.                                                          &_cairo_pattern_clear.base,
  265.                                                          boxes,
  266.                                                          NULL);
  267.     if (unlikely (status))
  268.         goto cleanup_clip;
  269.  
  270.     _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip);
  271.     composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
  272.     composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE;
  273.  
  274.     status = composite_boxes (compositor, &composite, boxes);
  275.  
  276.     _cairo_pattern_fini (&composite.mask_pattern.base);
  277.     _cairo_composite_rectangles_fini (&composite);
  278.  
  279. cleanup_clip:
  280.     cairo_surface_destroy (clip);
  281.     return status;
  282. }
  283.  
  284. static cairo_int_status_t
  285. fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor,
  286.                          const cairo_composite_rectangles_t *extents,
  287.                          cairo_boxes_t *boxes)
  288. {
  289.     cairo_polygon_t polygon, intersect;
  290.     cairo_composite_rectangles_t composite;
  291.     cairo_fill_rule_t fill_rule;
  292.     cairo_antialias_t antialias;
  293.     cairo_int_status_t status;
  294.  
  295.     TRACE((stderr, "%s\n", __FUNCTION__));
  296.  
  297.     /* Can we treat the clip as a regular clear-polygon and use it to fill? */
  298.     status = _cairo_clip_get_polygon (extents->clip, &polygon,
  299.                                       &fill_rule, &antialias);
  300.     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
  301.         return status;
  302.  
  303.     status= _cairo_polygon_init_boxes (&intersect, boxes);
  304.     if (unlikely (status))
  305.         goto cleanup_polygon;
  306.  
  307.     status = _cairo_polygon_intersect (&polygon, fill_rule,
  308.                                        &intersect, CAIRO_FILL_RULE_WINDING);
  309.     _cairo_polygon_fini (&intersect);
  310.  
  311.     if (unlikely (status))
  312.         goto cleanup_polygon;
  313.  
  314.     status = _cairo_composite_rectangles_init_for_polygon (&composite,
  315.                                                            extents->surface,
  316.                                                            CAIRO_OPERATOR_CLEAR,
  317.                                                            &_cairo_pattern_clear.base,
  318.                                                            &polygon,
  319.                                                            NULL);
  320.     if (unlikely (status))
  321.         goto cleanup_polygon;
  322.  
  323.     status = composite_polygon (compositor, &composite,
  324.                                 &polygon, fill_rule, antialias);
  325.  
  326.     _cairo_composite_rectangles_fini (&composite);
  327. cleanup_polygon:
  328.     _cairo_polygon_fini (&polygon);
  329.  
  330.     return status;
  331. }
  332.  
  333. static cairo_int_status_t
  334. fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
  335.                        const cairo_composite_rectangles_t *extents,
  336.                        cairo_boxes_t *boxes)
  337. {
  338.     cairo_boxes_t tmp, clear;
  339.     cairo_box_t box;
  340.     cairo_int_status_t status;
  341.  
  342.     assert (boxes->is_pixel_aligned);
  343.  
  344.     TRACE ((stderr, "%s\n", __FUNCTION__));
  345.     if (extents->bounded.width  == extents->unbounded.width &&
  346.         extents->bounded.height == extents->unbounded.height)
  347.     {
  348.         return CAIRO_STATUS_SUCCESS;
  349.     }
  350.  
  351.     /* subtract the drawn boxes from the unbounded area */
  352.     _cairo_boxes_init (&clear);
  353.  
  354.     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
  355.     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
  356.     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
  357.     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
  358.  
  359.     if (boxes->num_boxes) {
  360.         _cairo_boxes_init (&tmp);
  361.  
  362.         status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
  363.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  364.  
  365.         tmp.chunks.next = &boxes->chunks;
  366.         tmp.num_boxes += boxes->num_boxes;
  367.  
  368.         status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
  369.                                                           CAIRO_FILL_RULE_WINDING,
  370.                                                           &clear);
  371.         tmp.chunks.next = NULL;
  372.         if (unlikely (status))
  373.             goto error;
  374.     } else {
  375.         box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
  376.         box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
  377.  
  378.         status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
  379.         assert (status == CAIRO_INT_STATUS_SUCCESS);
  380.     }
  381.  
  382.     /* If we have a clip polygon, we need to intersect with that as well */
  383.     if (extents->clip->path) {
  384.         status = fixup_unbounded_polygon (compositor, extents, &clear);
  385.         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
  386.             status = fixup_unbounded_mask (compositor, extents, &clear);
  387.     } else {
  388.         /* Otherwise just intersect with the clip boxes */
  389.         if (extents->clip->num_boxes) {
  390.             _cairo_boxes_init_for_array (&tmp,
  391.                                          extents->clip->boxes,
  392.                                          extents->clip->num_boxes);
  393.             status = _cairo_boxes_intersect (&clear, &tmp, &clear);
  394.             if (unlikely (status))
  395.                 goto error;
  396.         }
  397.  
  398.         if (clear.is_pixel_aligned) {
  399.             status = compositor->fill_boxes (extents->surface,
  400.                                              CAIRO_OPERATOR_CLEAR,
  401.                                              CAIRO_COLOR_TRANSPARENT,
  402.                                              &clear);
  403.         } else {
  404.             cairo_composite_rectangles_t composite;
  405.  
  406.             status = _cairo_composite_rectangles_init_for_boxes (&composite,
  407.                                                                  extents->surface,
  408.                                                                  CAIRO_OPERATOR_CLEAR,
  409.                                                                  &_cairo_pattern_clear.base,
  410.                                                                  &clear,
  411.                                                                  NULL);
  412.             if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  413.                 status = composite_boxes (compositor, &composite, &clear);
  414.                 _cairo_composite_rectangles_fini (&composite);
  415.             }
  416.         }
  417.     }
  418.  
  419. error:
  420.     _cairo_boxes_fini (&clear);
  421.     return status;
  422. }
  423.  
  424. static cairo_surface_t *
  425. unwrap_source (const cairo_pattern_t *pattern)
  426. {
  427.     cairo_rectangle_int_t limit;
  428.  
  429.     return _cairo_pattern_get_source ((cairo_surface_pattern_t *)pattern,
  430.                                       &limit);
  431. }
  432.  
  433. static cairo_bool_t
  434. is_recording_pattern (const cairo_pattern_t *pattern)
  435. {
  436.     cairo_surface_t *surface;
  437.  
  438.     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
  439.         return FALSE;
  440.  
  441.     surface = ((const cairo_surface_pattern_t *) pattern)->surface;
  442.     return _cairo_surface_is_recording (surface);
  443. }
  444.  
  445. static cairo_bool_t
  446. recording_pattern_contains_sample (const cairo_pattern_t *pattern,
  447.                                    const cairo_rectangle_int_t *sample)
  448. {
  449.     cairo_recording_surface_t *surface;
  450.  
  451.     if (! is_recording_pattern (pattern))
  452.         return FALSE;
  453.  
  454.     if (pattern->extend == CAIRO_EXTEND_NONE)
  455.         return TRUE;
  456.  
  457.     surface = (cairo_recording_surface_t *) unwrap_source (pattern);
  458.     if (surface->unbounded)
  459.         return TRUE;
  460.  
  461.     return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
  462. }
  463.  
  464. static cairo_bool_t
  465. op_reduces_to_source (const cairo_composite_rectangles_t *extents,
  466.                       cairo_bool_t no_mask)
  467. {
  468.     if (extents->op == CAIRO_OPERATOR_SOURCE)
  469.         return TRUE;
  470.  
  471.     if (extents->surface->is_clear)
  472.         return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
  473.  
  474.     if (no_mask && extents->op == CAIRO_OPERATOR_OVER)
  475.         return _cairo_pattern_is_opaque (&extents->source_pattern.base,
  476.                                          &extents->source_sample_area);
  477.  
  478.     return FALSE;
  479. }
  480.  
  481. static cairo_status_t
  482. upload_boxes (const cairo_spans_compositor_t *compositor,
  483.               const cairo_composite_rectangles_t *extents,
  484.               cairo_boxes_t *boxes)
  485. {
  486.     cairo_surface_t *dst = extents->surface;
  487.     const cairo_surface_pattern_t *source = &extents->source_pattern.surface;
  488.     cairo_surface_t *src;
  489.     cairo_rectangle_int_t limit;
  490.     cairo_int_status_t status;
  491.     int tx, ty;
  492.  
  493.     TRACE ((stderr, "%s\n", __FUNCTION__));
  494.  
  495.     src = _cairo_pattern_get_source(source, &limit);
  496.     if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
  497.         return CAIRO_INT_STATUS_UNSUPPORTED;
  498.  
  499.     if (! _cairo_matrix_is_integer_translation (&source->base.matrix, &tx, &ty))
  500.         return CAIRO_INT_STATUS_UNSUPPORTED;
  501.  
  502.     /* Check that the data is entirely within the image */
  503.     if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
  504.         return CAIRO_INT_STATUS_UNSUPPORTED;
  505.  
  506.     if (extents->bounded.x + extents->bounded.width  + tx > limit.x + limit.width ||
  507.         extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
  508.         return CAIRO_INT_STATUS_UNSUPPORTED;
  509.  
  510.     tx += limit.x;
  511.     ty += limit.y;
  512.  
  513.     if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
  514.         status = compositor->draw_image_boxes (dst,
  515.                                                (cairo_image_surface_t *)src,
  516.                                                boxes, tx, ty);
  517.     else
  518.         status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
  519.                                          tx, ty);
  520.  
  521.     return status;
  522. }
  523.  
  524. static cairo_bool_t
  525. _clip_is_region (const cairo_clip_t *clip)
  526. {
  527.     int i;
  528.  
  529.     if (clip->is_region)
  530.         return TRUE;
  531.  
  532.     if (clip->path)
  533.         return FALSE;
  534.  
  535.     for (i = 0; i < clip->num_boxes; i++) {
  536.         const cairo_box_t *b = &clip->boxes[i];
  537.         if (!_cairo_fixed_is_integer (b->p1.x | b->p1.y |  b->p2.x | b->p2.y))
  538.             return FALSE;
  539.     }
  540.  
  541.     return TRUE;
  542. }
  543.  
  544. static cairo_int_status_t
  545. composite_aligned_boxes (const cairo_spans_compositor_t         *compositor,
  546.                          const cairo_composite_rectangles_t     *extents,
  547.                          cairo_boxes_t                          *boxes)
  548. {
  549.     cairo_surface_t *dst = extents->surface;
  550.     cairo_operator_t op = extents->op;
  551.     const cairo_pattern_t *source = &extents->source_pattern.base;
  552.     cairo_int_status_t status;
  553.     cairo_bool_t need_clip_mask = ! _clip_is_region (extents->clip);
  554.     cairo_bool_t op_is_source;
  555.     cairo_bool_t no_mask;
  556.     cairo_bool_t inplace;
  557.  
  558.     TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
  559.             __FUNCTION__, need_clip_mask, extents->is_bounded));
  560.     if (need_clip_mask && ! extents->is_bounded) {
  561.         TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
  562.         return CAIRO_INT_STATUS_UNSUPPORTED;
  563.     }
  564.  
  565.     no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
  566.         CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color);
  567.     op_is_source = op_reduces_to_source (extents, no_mask);
  568.     inplace = ! need_clip_mask && op_is_source && no_mask;
  569.  
  570.     TRACE ((stderr, "%s: op-is-source=%d [op=%d], no-mask=%d, inplace=%d\n",
  571.             __FUNCTION__, op_is_source, op, no_mask, inplace));
  572.  
  573.     if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
  574.         /* SOURCE with a mask is actually a LERP in cairo semantics */
  575.         if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) {
  576.             TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__));
  577.             return CAIRO_INT_STATUS_UNSUPPORTED;
  578.         }
  579.     }
  580.  
  581.     /* Are we just copying a recording surface? */
  582.     if (inplace &&
  583.         recording_pattern_contains_sample (&extents->source_pattern.base,
  584.                                            &extents->source_sample_area))
  585.     {
  586.         cairo_clip_t *recording_clip;
  587.         const cairo_pattern_t *source = &extents->source_pattern.base;
  588.  
  589.         /* XXX could also do tiling repeat modes... */
  590.  
  591.         /* first clear the area about to be overwritten */
  592.         if (! dst->is_clear) {
  593.             status = compositor->fill_boxes (dst,
  594.                                              CAIRO_OPERATOR_CLEAR,
  595.                                              CAIRO_COLOR_TRANSPARENT,
  596.                                              boxes);
  597.             if (unlikely (status))
  598.                 return status;
  599.  
  600.             dst->is_clear = TRUE;
  601.         }
  602.  
  603.         recording_clip = _cairo_clip_from_boxes (boxes);
  604.         status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
  605.                                                             &source->matrix,
  606.                                                             dst, recording_clip);
  607.         _cairo_clip_destroy (recording_clip);
  608.  
  609.         return status;
  610.     }
  611.  
  612.     status = CAIRO_INT_STATUS_UNSUPPORTED;
  613.     if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
  614.         const cairo_color_t *color;
  615.  
  616.         color = &((cairo_solid_pattern_t *) source)->color;
  617.         if (op_is_source)
  618.             op = CAIRO_OPERATOR_SOURCE;
  619.         status = compositor->fill_boxes (dst, op, color, boxes);
  620.     } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
  621.         status = upload_boxes (compositor, extents, boxes);
  622.     }
  623.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  624.         cairo_surface_t *src;
  625.         cairo_surface_t *mask = NULL;
  626.         int src_x, src_y;
  627.         int mask_x = 0, mask_y = 0;
  628.  
  629.         /* All typical cases will have been resolved before now... */
  630.         if (need_clip_mask) {
  631.             mask = get_clip_surface (compositor, dst, extents->clip,
  632.                                      &extents->bounded);
  633.             if (unlikely (mask->status))
  634.                 return mask->status;
  635.  
  636.             mask_x = -extents->bounded.x;
  637.             mask_y = -extents->bounded.y;
  638.         }
  639.  
  640.         /* XXX but this is still ugly */
  641.         if (! no_mask) {
  642.             src = compositor->pattern_to_surface (dst,
  643.                                                   &extents->mask_pattern.base,
  644.                                                   TRUE,
  645.                                                   &extents->bounded,
  646.                                                   &extents->mask_sample_area,
  647.                                                   &src_x, &src_y);
  648.             if (unlikely (src->status)) {
  649.                 cairo_surface_destroy (mask);
  650.                 return src->status;
  651.             }
  652.  
  653.             if (mask != NULL) {
  654.                 status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
  655.                                                       src, NULL,
  656.                                                       src_x, src_y,
  657.                                                       0, 0,
  658.                                                       mask_x, mask_y,
  659.                                                       boxes, &extents->bounded);
  660.  
  661.                 cairo_surface_destroy (src);
  662.             } else {
  663.                 mask = src;
  664.                 mask_x = src_x;
  665.                 mask_y = src_y;
  666.             }
  667.         }
  668.  
  669.         src = compositor->pattern_to_surface (dst, source, FALSE,
  670.                                               &extents->bounded,
  671.                                               &extents->source_sample_area,
  672.                                               &src_x, &src_y);
  673.         if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
  674.             status = compositor->composite_boxes (dst, op, src, mask,
  675.                                                   src_x, src_y,
  676.                                                   mask_x, mask_y,
  677.                                                   0, 0,
  678.                                                   boxes, &extents->bounded);
  679.             cairo_surface_destroy (src);
  680.         } else
  681.             status = src->status;
  682.  
  683.         cairo_surface_destroy (mask);
  684.     }
  685.  
  686.     if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
  687.         status = fixup_unbounded_boxes (compositor, extents, boxes);
  688.  
  689.     return status;
  690. }
  691.  
  692. static cairo_bool_t
  693. composite_needs_clip (const cairo_composite_rectangles_t *composite,
  694.                       const cairo_box_t *extents)
  695. {
  696.     return !_cairo_clip_contains_box (composite->clip, extents);
  697. }
  698.  
  699. static cairo_int_status_t
  700. composite_boxes (const cairo_spans_compositor_t *compositor,
  701.                  cairo_composite_rectangles_t *extents,
  702.                  cairo_boxes_t          *boxes)
  703. {
  704.     cairo_abstract_span_renderer_t renderer;
  705.     cairo_rectangular_scan_converter_t converter;
  706.     const struct _cairo_boxes_chunk *chunk;
  707.     cairo_int_status_t status;
  708.     cairo_box_t box;
  709.  
  710.     TRACE ((stderr, "%s\n", __FUNCTION__));
  711.     _cairo_box_from_rectangle (&box, &extents->unbounded);
  712.     if (composite_needs_clip (extents, &box)) {
  713.         TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
  714.         return CAIRO_INT_STATUS_UNSUPPORTED;
  715.     }
  716.  
  717.     _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
  718.     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
  719.         const cairo_box_t *box = chunk->base;
  720.         int i;
  721.  
  722.         for (i = 0; i < chunk->count; i++) {
  723.             status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
  724.             if (unlikely (status))
  725.                 goto cleanup_converter;
  726.         }
  727.     }
  728.  
  729.     status = compositor->renderer_init (&renderer, extents,
  730.                                         CAIRO_ANTIALIAS_DEFAULT, FALSE);
  731.     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  732.         status = converter.base.generate (&converter.base, &renderer.base);
  733.     compositor->renderer_fini (&renderer, status);
  734.  
  735. cleanup_converter:
  736.     converter.base.destroy (&converter.base);
  737.     return status;
  738. }
  739.  
  740. static cairo_int_status_t
  741. composite_polygon (const cairo_spans_compositor_t       *compositor,
  742.                    cairo_composite_rectangles_t          *extents,
  743.                    cairo_polygon_t                      *polygon,
  744.                    cairo_fill_rule_t                     fill_rule,
  745.                    cairo_antialias_t                     antialias)
  746. {
  747.     cairo_abstract_span_renderer_t renderer;
  748.     cairo_scan_converter_t *converter;
  749.     cairo_bool_t needs_clip;
  750.     cairo_int_status_t status;
  751.  
  752.     if (extents->is_bounded)
  753.         needs_clip = extents->clip->path != NULL;
  754.     else
  755.         needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1;
  756.     TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
  757.     if (needs_clip) {
  758.         TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
  759.         return CAIRO_INT_STATUS_UNSUPPORTED;
  760.         converter = _cairo_clip_tor_scan_converter_create (extents->clip,
  761.                                                            polygon,
  762.                                                            fill_rule, antialias);
  763.     } else {
  764.         const cairo_rectangle_int_t *r = &extents->unbounded;
  765.  
  766.         if (antialias == CAIRO_ANTIALIAS_FAST) {
  767.             converter = _cairo_tor22_scan_converter_create (r->x, r->y,
  768.                                                             r->x + r->width,
  769.                                                             r->y + r->height,
  770.                                                             fill_rule, antialias);
  771.             status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
  772.         } else if (antialias == CAIRO_ANTIALIAS_NONE) {
  773.             converter = _cairo_mono_scan_converter_create (r->x, r->y,
  774.                                                            r->x + r->width,
  775.                                                            r->y + r->height,
  776.                                                            fill_rule);
  777.             status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
  778.         } else {
  779.             converter = _cairo_tor_scan_converter_create (r->x, r->y,
  780.                                                           r->x + r->width,
  781.                                                           r->y + r->height,
  782.                                                           fill_rule, antialias);
  783.             status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
  784.         }
  785.     }
  786.     if (unlikely (status))
  787.         goto cleanup_converter;
  788.  
  789.     status = compositor->renderer_init (&renderer, extents,
  790.                                         antialias, needs_clip);
  791.     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  792.         status = converter->generate (converter, &renderer.base);
  793.     compositor->renderer_fini (&renderer, status);
  794.  
  795. cleanup_converter:
  796.     converter->destroy (converter);
  797.     return status;
  798. }
  799.  
  800. static cairo_int_status_t
  801. trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
  802.                        cairo_boxes_t *boxes)
  803. {
  804.     cairo_box_t box;
  805.  
  806.     _cairo_boxes_extents (boxes, &box);
  807.     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
  808. }
  809.  
  810. static cairo_int_status_t
  811. trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
  812.                          cairo_polygon_t *polygon)
  813. {
  814.     return _cairo_composite_rectangles_intersect_mask_extents (extents,
  815.                                                                &polygon->extents);
  816. }
  817.  
  818. static cairo_int_status_t
  819. clip_and_composite_boxes (const cairo_spans_compositor_t        *compositor,
  820.                           cairo_composite_rectangles_t          *extents,
  821.                           cairo_boxes_t                         *boxes)
  822. {
  823.     cairo_int_status_t status;
  824.     cairo_polygon_t polygon;
  825.  
  826.     TRACE ((stderr, "%s\n", __FUNCTION__));
  827.     status = trim_extents_to_boxes (extents, boxes);
  828.     if (unlikely (status))
  829.         return status;
  830.  
  831.     if (boxes->num_boxes == 0) {
  832.         if (extents->is_bounded)
  833.             return CAIRO_STATUS_SUCCESS;
  834.  
  835.         return fixup_unbounded_boxes (compositor, extents, boxes);
  836.     }
  837.  
  838.     /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
  839.     if (extents->clip->path != NULL && extents->is_bounded) {
  840.         cairo_polygon_t polygon;
  841.         cairo_fill_rule_t fill_rule;
  842.         cairo_antialias_t antialias;
  843.         cairo_clip_t *clip;
  844.  
  845.         clip = _cairo_clip_copy (extents->clip);
  846.         clip = _cairo_clip_intersect_boxes (clip, boxes);
  847.         if (_cairo_clip_is_all_clipped (clip))
  848.             return CAIRO_INT_STATUS_NOTHING_TO_DO;
  849.  
  850.         status = _cairo_clip_get_polygon (clip, &polygon,
  851.                                           &fill_rule, &antialias);
  852.         _cairo_clip_path_destroy (clip->path);
  853.         clip->path = NULL;
  854.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  855.             cairo_clip_t *saved_clip = extents->clip;
  856.             extents->clip = clip;
  857.  
  858.             status = clip_and_composite_polygon (compositor, extents, &polygon,
  859.                                                  fill_rule, antialias);
  860.  
  861.             clip = extents->clip;
  862.             extents->clip = saved_clip;
  863.  
  864.             _cairo_polygon_fini (&polygon);
  865.         }
  866.         _cairo_clip_destroy (clip);
  867.  
  868.         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  869.             return status;
  870.     }
  871.  
  872.     if (boxes->is_pixel_aligned) {
  873.         status = composite_aligned_boxes (compositor, extents, boxes);
  874.         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  875.             return status;
  876.     }
  877.  
  878.     status = composite_boxes (compositor, extents, boxes);
  879.     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  880.         return status;
  881.  
  882.     status = _cairo_polygon_init_boxes (&polygon, boxes);
  883.     if (unlikely (status))
  884.         return status;
  885.  
  886.     status = composite_polygon (compositor, extents, &polygon,
  887.                                 CAIRO_FILL_RULE_WINDING,
  888.                                 CAIRO_ANTIALIAS_DEFAULT);
  889.     _cairo_polygon_fini (&polygon);
  890.  
  891.     return status;
  892. }
  893.  
  894. static cairo_int_status_t
  895. clip_and_composite_polygon (const cairo_spans_compositor_t      *compositor,
  896.                             cairo_composite_rectangles_t         *extents,
  897.                             cairo_polygon_t                     *polygon,
  898.                             cairo_fill_rule_t                    fill_rule,
  899.                             cairo_antialias_t                    antialias)
  900. {
  901.     cairo_int_status_t status;
  902.  
  903.     TRACE ((stderr, "%s\n", __FUNCTION__));
  904.  
  905.     /* XXX simply uses polygon limits.point extemities, tessellation? */
  906.     status = trim_extents_to_polygon (extents, polygon);
  907.     if (unlikely (status))
  908.         return status;
  909.  
  910.     if (_cairo_polygon_is_empty (polygon)) {
  911.         cairo_boxes_t boxes;
  912.  
  913.         if (extents->is_bounded)
  914.             return CAIRO_STATUS_SUCCESS;
  915.  
  916.         _cairo_boxes_init (&boxes);
  917.         extents->bounded.width = extents->bounded.height = 0;
  918.         return fixup_unbounded_boxes (compositor, extents, &boxes);
  919.     }
  920.  
  921.     if (extents->is_bounded && extents->clip->path) {
  922.         cairo_polygon_t clipper;
  923.         cairo_antialias_t clip_antialias;
  924.         cairo_fill_rule_t clip_fill_rule;
  925.  
  926.         TRACE((stderr, "%s - combining shape with clip polygon\n",
  927.                __FUNCTION__));
  928.  
  929.         status = _cairo_clip_get_polygon (extents->clip,
  930.                                           &clipper,
  931.                                           &clip_fill_rule,
  932.                                           &clip_antialias);
  933.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  934.             cairo_clip_t *old_clip;
  935.  
  936.             if (clip_antialias == antialias) {
  937.                 status = _cairo_polygon_intersect (polygon, fill_rule,
  938.                                                    &clipper, clip_fill_rule);
  939.                 _cairo_polygon_fini (&clipper);
  940.                 if (unlikely (status))
  941.                     return status;
  942.  
  943.                 old_clip = extents->clip;
  944.                 extents->clip = _cairo_clip_copy_region (extents->clip);
  945.                 _cairo_clip_destroy (old_clip);
  946.  
  947.                 status = trim_extents_to_polygon (extents, polygon);
  948.                 if (unlikely (status))
  949.                     return status;
  950.  
  951.                 fill_rule = CAIRO_FILL_RULE_WINDING;
  952.             } else {
  953.                 _cairo_polygon_fini (&clipper);
  954.             }
  955.         }
  956.     }
  957.  
  958.     return composite_polygon (compositor, extents,
  959.                               polygon, fill_rule, antialias);
  960. }
  961.  
  962. /* high-level compositor interface */
  963.  
  964. static cairo_int_status_t
  965. _cairo_spans_compositor_paint (const cairo_compositor_t         *_compositor,
  966.                                cairo_composite_rectangles_t     *extents)
  967. {
  968.     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
  969.     cairo_boxes_t boxes;
  970.     cairo_int_status_t status;
  971.  
  972.     TRACE ((stderr, "%s\n", __FUNCTION__));
  973.     _cairo_clip_steal_boxes (extents->clip, &boxes);
  974.     status = clip_and_composite_boxes (compositor, extents, &boxes);
  975.     _cairo_clip_unsteal_boxes (extents->clip, &boxes);
  976.  
  977.     return status;
  978. }
  979.  
  980. static cairo_int_status_t
  981. _cairo_spans_compositor_mask (const cairo_compositor_t          *_compositor,
  982.                               cairo_composite_rectangles_t      *extents)
  983. {
  984.     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
  985.     cairo_int_status_t status;
  986.     cairo_boxes_t boxes;
  987.  
  988.     TRACE ((stderr, "%s\n", __FUNCTION__));
  989.     _cairo_clip_steal_boxes (extents->clip, &boxes);
  990.     status = clip_and_composite_boxes (compositor, extents, &boxes);
  991.     _cairo_clip_unsteal_boxes (extents->clip, &boxes);
  992.  
  993.     return status;
  994. }
  995.  
  996. static cairo_int_status_t
  997. _cairo_spans_compositor_stroke (const cairo_compositor_t        *_compositor,
  998.                                 cairo_composite_rectangles_t     *extents,
  999.                                 const cairo_path_fixed_t        *path,
  1000.                                 const cairo_stroke_style_t      *style,
  1001.                                 const cairo_matrix_t            *ctm,
  1002.                                 const cairo_matrix_t            *ctm_inverse,
  1003.                                 double                           tolerance,
  1004.                                 cairo_antialias_t                antialias)
  1005. {
  1006.     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
  1007.     cairo_int_status_t status;
  1008.  
  1009.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1010.     TRACE_ (_cairo_debug_print_path (stderr, path));
  1011.     TRACE_ (_cairo_debug_print_clip (stderr, extents->clip));
  1012.  
  1013.     status = CAIRO_INT_STATUS_UNSUPPORTED;
  1014.     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
  1015.         cairo_boxes_t boxes;
  1016.  
  1017.         _cairo_boxes_init (&boxes);
  1018.         if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
  1019.             _cairo_boxes_limit (&boxes,
  1020.                                 extents->clip->boxes,
  1021.                                 extents->clip->num_boxes);
  1022.  
  1023.         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
  1024.                                                                 style,
  1025.                                                                 ctm,
  1026.                                                                 antialias,
  1027.                                                                 &boxes);
  1028.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  1029.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  1030.         _cairo_boxes_fini (&boxes);
  1031.     }
  1032.  
  1033.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  1034.         cairo_polygon_t polygon;
  1035.         cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING;
  1036.  
  1037.         if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
  1038.                                                    &extents->mask))
  1039.         {
  1040.             if (extents->clip->num_boxes == 1) {
  1041.                 _cairo_polygon_init (&polygon, extents->clip->boxes, 1);
  1042.             } else {
  1043.                 cairo_box_t limits;
  1044.                 _cairo_box_from_rectangle (&limits, &extents->unbounded);
  1045.                 _cairo_polygon_init (&polygon, &limits, 1);
  1046.             }
  1047.         }
  1048.         else
  1049.         {
  1050.             _cairo_polygon_init (&polygon, NULL, 0);
  1051.         }
  1052.         status = _cairo_path_fixed_stroke_to_polygon (path,
  1053.                                                       style,
  1054.                                                       ctm, ctm_inverse,
  1055.                                                       tolerance,
  1056.                                                       &polygon);
  1057.         TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
  1058.         polygon.num_limits = 0;
  1059.  
  1060.         if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
  1061.             status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
  1062.                                                           extents->clip->boxes,
  1063.                                                           extents->clip->num_boxes);
  1064.         }
  1065.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  1066.             cairo_clip_t *saved_clip = extents->clip;
  1067.  
  1068.             if (extents->is_bounded) {
  1069.                 extents->clip = _cairo_clip_copy_path (extents->clip);
  1070.                 extents->clip = _cairo_clip_intersect_box(extents->clip,
  1071.                                                           &polygon.extents);
  1072.             }
  1073.  
  1074.             status = clip_and_composite_polygon (compositor, extents, &polygon,
  1075.                                                  fill_rule, antialias);
  1076.  
  1077.             if (extents->is_bounded) {
  1078.                 _cairo_clip_destroy (extents->clip);
  1079.                 extents->clip = saved_clip;
  1080.             }
  1081.         }
  1082.         _cairo_polygon_fini (&polygon);
  1083.     }
  1084.  
  1085.     return status;
  1086. }
  1087.  
  1088. static cairo_int_status_t
  1089. _cairo_spans_compositor_fill (const cairo_compositor_t          *_compositor,
  1090.                               cairo_composite_rectangles_t       *extents,
  1091.                               const cairo_path_fixed_t          *path,
  1092.                               cairo_fill_rule_t                  fill_rule,
  1093.                               double                             tolerance,
  1094.                               cairo_antialias_t                  antialias)
  1095. {
  1096.     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
  1097.     cairo_int_status_t status;
  1098.  
  1099.     TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias));
  1100.  
  1101.     status = CAIRO_INT_STATUS_UNSUPPORTED;
  1102.     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
  1103.         cairo_boxes_t boxes;
  1104.  
  1105.         TRACE((stderr, "%s - rectilinear\n", __FUNCTION__));
  1106.  
  1107.         _cairo_boxes_init (&boxes);
  1108.         if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
  1109.             _cairo_boxes_limit (&boxes,
  1110.                                 extents->clip->boxes,
  1111.                                 extents->clip->num_boxes);
  1112.         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
  1113.                                                               fill_rule,
  1114.                                                               antialias,
  1115.                                                               &boxes);
  1116.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  1117.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  1118.         _cairo_boxes_fini (&boxes);
  1119.     }
  1120.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  1121.         cairo_polygon_t polygon;
  1122.  
  1123.         TRACE((stderr, "%s - polygon\n", __FUNCTION__));
  1124.  
  1125.         if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
  1126.                                                    &extents->mask))
  1127.         {
  1128.             TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__));
  1129.             if (extents->clip->num_boxes == 1) {
  1130.                 _cairo_polygon_init (&polygon, extents->clip->boxes, 1);
  1131.             } else {
  1132.                 cairo_box_t limits;
  1133.                 _cairo_box_from_rectangle (&limits, &extents->unbounded);
  1134.                 _cairo_polygon_init (&polygon, &limits, 1);
  1135.             }
  1136.         }
  1137.         else
  1138.         {
  1139.             _cairo_polygon_init (&polygon, NULL, 0);
  1140.         }
  1141.  
  1142.         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
  1143.         TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
  1144.         polygon.num_limits = 0;
  1145.  
  1146.         if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
  1147.             TRACE((stderr, "%s - polygon intersect with %d clip boxes\n",
  1148.                    __FUNCTION__, extents->clip->num_boxes));
  1149.             status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
  1150.                                                           extents->clip->boxes,
  1151.                                                           extents->clip->num_boxes);
  1152.         }
  1153.         TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
  1154.         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
  1155.             cairo_clip_t *saved_clip = extents->clip;
  1156.  
  1157.             if (extents->is_bounded) {
  1158.                 TRACE((stderr, "%s - polygon discard clip boxes\n",
  1159.                        __FUNCTION__));
  1160.                 extents->clip = _cairo_clip_copy_path (extents->clip);
  1161.                 extents->clip = _cairo_clip_intersect_box(extents->clip,
  1162.                                                           &polygon.extents);
  1163.             }
  1164.  
  1165.             status = clip_and_composite_polygon (compositor, extents, &polygon,
  1166.                                                  fill_rule, antialias);
  1167.  
  1168.             if (extents->is_bounded) {
  1169.                 _cairo_clip_destroy (extents->clip);
  1170.                 extents->clip = saved_clip;
  1171.             }
  1172.         }
  1173.         _cairo_polygon_fini (&polygon);
  1174.  
  1175.         TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status));
  1176.     }
  1177.  
  1178.     return status;
  1179. }
  1180.  
  1181. void
  1182. _cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
  1183.                               const cairo_compositor_t  *delegate)
  1184. {
  1185.     compositor->base.delegate = delegate;
  1186.  
  1187.     compositor->base.paint  = _cairo_spans_compositor_paint;
  1188.     compositor->base.mask   = _cairo_spans_compositor_mask;
  1189.     compositor->base.fill   = _cairo_spans_compositor_fill;
  1190.     compositor->base.stroke = _cairo_spans_compositor_stroke;
  1191.     compositor->base.glyphs = NULL;
  1192. }
  1193.