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. /* This compositor renders the shape to a mask using an image surface
  43.  * then calls composite.
  44.  */
  45.  
  46. #include "cairoint.h"
  47.  
  48. #include "cairo-clip-inline.h"
  49. #include "cairo-compositor-private.h"
  50. #include "cairo-image-surface-private.h"
  51. #include "cairo-pattern-inline.h"
  52. #include "cairo-region-private.h"
  53. #include "cairo-surface-observer-private.h"
  54. #include "cairo-surface-offset-private.h"
  55. #include "cairo-surface-snapshot-private.h"
  56. #include "cairo-surface-subsurface-private.h"
  57.  
  58. typedef cairo_int_status_t
  59. (*draw_func_t) (const cairo_mask_compositor_t *compositor,
  60.                 cairo_surface_t                 *dst,
  61.                 void                            *closure,
  62.                 cairo_operator_t                 op,
  63.                 const cairo_pattern_t           *src,
  64.                 const cairo_rectangle_int_t     *src_sample,
  65.                 int                              dst_x,
  66.                 int                              dst_y,
  67.                 const cairo_rectangle_int_t     *extents,
  68.                 cairo_clip_t                    *clip);
  69.  
  70. static void do_unaligned_row(void (*blt)(void *closure,
  71.                                          int16_t x, int16_t y,
  72.                                          int16_t w, int16_t h,
  73.                                          uint16_t coverage),
  74.                              void *closure,
  75.                              const cairo_box_t *b,
  76.                              int tx, int y, int h,
  77.                              uint16_t coverage)
  78. {
  79.     int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
  80.     int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
  81.     if (x2 > x1) {
  82.         if (! _cairo_fixed_is_integer (b->p1.x)) {
  83.             blt(closure, x1, y, 1, h,
  84.                 coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
  85.             x1++;
  86.         }
  87.  
  88.         if (x2 > x1)
  89.             blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
  90.  
  91.         if (! _cairo_fixed_is_integer (b->p2.x))
  92.             blt(closure, x2, y, 1, h,
  93.                 coverage * _cairo_fixed_fractional_part (b->p2.x));
  94.     } else
  95.         blt(closure, x1, y, 1, h,
  96.             coverage * (b->p2.x - b->p1.x));
  97. }
  98.  
  99. static void do_unaligned_box(void (*blt)(void *closure,
  100.                                          int16_t x, int16_t y,
  101.                                          int16_t w, int16_t h,
  102.                                          uint16_t coverage),
  103.                              void *closure,
  104.                              const cairo_box_t *b, int tx, int ty)
  105. {
  106.     int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
  107.     int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
  108.     if (y2 > y1) {
  109.         if (! _cairo_fixed_is_integer (b->p1.y)) {
  110.             do_unaligned_row(blt, closure, b, tx, y1, 1,
  111.                              256 - _cairo_fixed_fractional_part (b->p1.y));
  112.             y1++;
  113.         }
  114.  
  115.         if (y2 > y1)
  116.             do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
  117.  
  118.         if (! _cairo_fixed_is_integer (b->p2.y))
  119.             do_unaligned_row(blt, closure, b, tx, y2, 1,
  120.                              _cairo_fixed_fractional_part (b->p2.y));
  121.     } else
  122.         do_unaligned_row(blt, closure, b, tx, y1, 1,
  123.                          b->p2.y - b->p1.y);
  124. }
  125.  
  126. struct blt_in {
  127.     const cairo_mask_compositor_t *compositor;
  128.     cairo_surface_t *dst;
  129. };
  130.  
  131. static void blt_in(void *closure,
  132.                    int16_t x, int16_t y,
  133.                    int16_t w, int16_t h,
  134.                    uint16_t coverage)
  135. {
  136.     struct blt_in *info = closure;
  137.     cairo_color_t color;
  138.     cairo_rectangle_int_t rect;
  139.  
  140.     if (coverage == 0xffff)
  141.         return;
  142.  
  143.     rect.x = x;
  144.     rect.y = y;
  145.     rect.width  = w;
  146.     rect.height = h;
  147.  
  148.     _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
  149.     info->compositor->fill_rectangles (info->dst, CAIRO_OPERATOR_IN,
  150.                                        &color, &rect, 1);
  151. }
  152.  
  153. static cairo_surface_t *
  154. create_composite_mask (const cairo_mask_compositor_t *compositor,
  155.                        cairo_surface_t          *dst,
  156.                        void                     *draw_closure,
  157.                        draw_func_t               draw_func,
  158.                        draw_func_t               mask_func,
  159.                        const cairo_composite_rectangles_t *extents)
  160. {
  161.     cairo_surface_t *surface;
  162.     cairo_int_status_t status;
  163.     struct blt_in info;
  164.     int i;
  165.  
  166.     surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA,
  167.                                                      extents->bounded.width,
  168.                                                      extents->bounded.height);
  169.     if (unlikely (surface->status))
  170.         return surface;
  171.  
  172.     status = compositor->acquire (surface);
  173.     if (unlikely (status)) {
  174.         cairo_surface_destroy (surface);
  175.         return _cairo_int_surface_create_in_error (status);
  176.     }
  177.  
  178.     if (!surface->is_clear) {
  179.         cairo_rectangle_int_t rect;
  180.  
  181.         rect.x = rect.y = 0;
  182.         rect.width = extents->bounded.width;
  183.         rect.height = extents->bounded.height;
  184.  
  185.         status = compositor->fill_rectangles (surface, CAIRO_OPERATOR_CLEAR,
  186.                                               CAIRO_COLOR_TRANSPARENT,
  187.                                               &rect, 1);
  188.         if (unlikely (status))
  189.             goto error;
  190.     }
  191.  
  192.     if (mask_func) {
  193.         status = mask_func (compositor, surface, draw_closure,
  194.                             CAIRO_OPERATOR_SOURCE, NULL, NULL,
  195.                             extents->bounded.x, extents->bounded.y,
  196.                             &extents->bounded, extents->clip);
  197.         if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
  198.             goto out;
  199.     }
  200.  
  201.     /* Is it worth setting the clip region here? */
  202.     status = draw_func (compositor, surface, draw_closure,
  203.                         CAIRO_OPERATOR_ADD, NULL, NULL,
  204.                         extents->bounded.x, extents->bounded.y,
  205.                         &extents->bounded, NULL);
  206.     if (unlikely (status))
  207.         goto error;
  208.  
  209.     info.compositor = compositor;
  210.     info.dst = surface;
  211.     for (i = 0; i < extents->clip->num_boxes; i++) {
  212.         cairo_box_t *b = &extents->clip->boxes[i];
  213.  
  214.         if (! _cairo_fixed_is_integer (b->p1.x) ||
  215.             ! _cairo_fixed_is_integer (b->p1.y) ||
  216.             ! _cairo_fixed_is_integer (b->p2.x) ||
  217.             ! _cairo_fixed_is_integer (b->p2.y))
  218.         {
  219.             do_unaligned_box(blt_in, &info, b,
  220.                              extents->bounded.x,
  221.                              extents->bounded.y);
  222.         }
  223.     }
  224.  
  225.     if (extents->clip->path != NULL) {
  226.         status = _cairo_clip_combine_with_surface (extents->clip, surface,
  227.                                                    extents->bounded.x,
  228.                                                    extents->bounded.y);
  229.         if (unlikely (status))
  230.             goto error;
  231.     }
  232.  
  233. out:
  234.     compositor->release (surface);
  235.     surface->is_clear = FALSE;
  236.     return surface;
  237.  
  238. error:
  239.     compositor->release (surface);
  240.     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
  241.         cairo_surface_destroy (surface);
  242.         surface = _cairo_int_surface_create_in_error (status);
  243.     }
  244.     return surface;
  245. }
  246.  
  247. /* Handles compositing with a clip surface when the operator allows
  248.  * us to combine the clip with the mask
  249.  */
  250. static cairo_status_t
  251. clip_and_composite_with_mask (const cairo_mask_compositor_t *compositor,
  252.                               void                      *draw_closure,
  253.                               draw_func_t                draw_func,
  254.                               draw_func_t                mask_func,
  255.                               cairo_operator_t           op,
  256.                               cairo_pattern_t           *pattern,
  257.                               const cairo_composite_rectangles_t*extents)
  258. {
  259.     cairo_surface_t *dst = extents->surface;
  260.     cairo_surface_t *mask, *src;
  261.     int src_x, src_y;
  262.  
  263.     mask = create_composite_mask (compositor, dst, draw_closure,
  264.                                   draw_func, mask_func,
  265.                                   extents);
  266.     if (unlikely (mask->status))
  267.         return mask->status;
  268.  
  269.     if (pattern != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
  270.         src = compositor->pattern_to_surface (dst,
  271.                                               &extents->source_pattern.base,
  272.                                               FALSE,
  273.                                               &extents->bounded,
  274.                                               &extents->source_sample_area,
  275.                                               &src_x, &src_y);
  276.         if (unlikely (src->status)) {
  277.             cairo_surface_destroy (mask);
  278.             return src->status;
  279.         }
  280.  
  281.         compositor->composite (dst, op, src, mask,
  282.                                extents->bounded.x + src_x,
  283.                                extents->bounded.y + src_y,
  284.                                0, 0,
  285.                                extents->bounded.x,      extents->bounded.y,
  286.                                extents->bounded.width,  extents->bounded.height);
  287.  
  288.         cairo_surface_destroy (src);
  289.     } else {
  290.         compositor->composite (dst, op, mask, NULL,
  291.                                0, 0,
  292.                                0, 0,
  293.                                extents->bounded.x,      extents->bounded.y,
  294.                                extents->bounded.width,  extents->bounded.height);
  295.     }
  296.     cairo_surface_destroy (mask);
  297.  
  298.     return CAIRO_STATUS_SUCCESS;
  299. }
  300.  
  301. static cairo_surface_t *
  302. get_clip_source (const cairo_mask_compositor_t *compositor,
  303.                  cairo_clip_t *clip,
  304.                  cairo_surface_t *dst,
  305.                  const cairo_rectangle_int_t *bounds,
  306.                  int *out_x, int *out_y)
  307. {
  308.     cairo_surface_pattern_t pattern;
  309.     cairo_rectangle_int_t r;
  310.     cairo_surface_t *surface;
  311.  
  312.     surface = _cairo_clip_get_image (clip, dst, bounds);
  313.     if (unlikely (surface->status))
  314.         return surface;
  315.  
  316.     _cairo_pattern_init_for_surface (&pattern, surface);
  317.     pattern.base.filter = CAIRO_FILTER_NEAREST;
  318.     cairo_surface_destroy (surface);
  319.  
  320.     r.x = r.y = 0;
  321.     r.width  = bounds->width;
  322.     r.height = bounds->height;
  323.  
  324.     surface = compositor->pattern_to_surface (dst, &pattern.base, TRUE,
  325.                                               &r, &r, out_x, out_y);
  326.     _cairo_pattern_fini (&pattern.base);
  327.  
  328.     *out_x += -bounds->x;
  329.     *out_y += -bounds->y;
  330.     return surface;
  331. }
  332.  
  333. /* Handles compositing with a clip surface when we have to do the operation
  334.  * in two pieces and combine them together.
  335.  */
  336. static cairo_status_t
  337. clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
  338.                             void                        *draw_closure,
  339.                             draw_func_t          draw_func,
  340.                             cairo_operator_t             op,
  341.                             const cairo_pattern_t       *pattern,
  342.                             const cairo_composite_rectangles_t*extents)
  343. {
  344.     cairo_surface_t *dst = extents->surface;
  345.     cairo_surface_t *tmp, *clip;
  346.     cairo_status_t status;
  347.     int clip_x, clip_y;
  348.  
  349.     tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
  350.                                                  extents->bounded.width,
  351.                                                  extents->bounded.height);
  352.     if (unlikely (tmp->status))
  353.         return tmp->status;
  354.  
  355.     compositor->composite (tmp, CAIRO_OPERATOR_SOURCE, dst, NULL,
  356.                            extents->bounded.x,      extents->bounded.y,
  357.                            0, 0,
  358.                            0, 0,
  359.                            extents->bounded.width,  extents->bounded.height);
  360.  
  361.     status = draw_func (compositor, tmp, draw_closure, op,
  362.                         pattern, &extents->source_sample_area,
  363.                         extents->bounded.x, extents->bounded.y,
  364.                         &extents->bounded, NULL);
  365.     if (unlikely (status))
  366.         goto cleanup;
  367.  
  368.     clip = get_clip_source (compositor,
  369.                             extents->clip, dst, &extents->bounded,
  370.                             &clip_x, &clip_y);
  371.     if (unlikely ((status = clip->status)))
  372.         goto cleanup;
  373.  
  374.     if (dst->is_clear) {
  375.         compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
  376.                                0, 0,
  377.                                clip_x, clip_y,
  378.                                extents->bounded.x,      extents->bounded.y,
  379.                                extents->bounded.width,  extents->bounded.height);
  380.     } else {
  381.         /* Punch the clip out of the destination */
  382.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL,
  383.                                clip_x, clip_y,
  384.                                0, 0,
  385.                                extents->bounded.x,     extents->bounded.y,
  386.                                extents->bounded.width, extents->bounded.height);
  387.  
  388.         /* Now add the two results together */
  389.         compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip,
  390.                                0, 0,
  391.                                clip_x, clip_y,
  392.                                extents->bounded.x,     extents->bounded.y,
  393.                                extents->bounded.width, extents->bounded.height);
  394.     }
  395.     cairo_surface_destroy (clip);
  396.  
  397. cleanup:
  398.     cairo_surface_destroy (tmp);
  399.     return status;
  400. }
  401.  
  402. /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
  403.  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
  404.  */
  405. static cairo_status_t
  406. clip_and_composite_source (const cairo_mask_compositor_t        *compositor,
  407.                            void                         *draw_closure,
  408.                            draw_func_t                   draw_func,
  409.                            draw_func_t                   mask_func,
  410.                            cairo_pattern_t              *pattern,
  411.                            const cairo_composite_rectangles_t   *extents)
  412. {
  413.     cairo_surface_t *dst = extents->surface;
  414.     cairo_surface_t *mask, *src;
  415.     int src_x, src_y;
  416.  
  417.     /* Create a surface that is mask IN clip */
  418.     mask = create_composite_mask (compositor, dst, draw_closure,
  419.                                   draw_func, mask_func,
  420.                                   extents);
  421.     if (unlikely (mask->status))
  422.         return mask->status;
  423.  
  424.     src = compositor->pattern_to_surface (dst,
  425.                                           pattern,
  426.                                           FALSE,
  427.                                           &extents->bounded,
  428.                                           &extents->source_sample_area,
  429.                                           &src_x, &src_y);
  430.     if (unlikely (src->status)) {
  431.         cairo_surface_destroy (mask);
  432.         return src->status;
  433.     }
  434.  
  435.     if (dst->is_clear) {
  436.         compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
  437.                                extents->bounded.x + src_x, extents->bounded.y + src_y,
  438.                                0, 0,
  439.                                extents->bounded.x,      extents->bounded.y,
  440.                                extents->bounded.width,  extents->bounded.height);
  441.     } else {
  442.         /* Compute dest' = dest OUT (mask IN clip) */
  443.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  444.                                0, 0, 0, 0,
  445.                                extents->bounded.x,     extents->bounded.y,
  446.                                extents->bounded.width, extents->bounded.height);
  447.  
  448.         /* Now compute (src IN (mask IN clip)) ADD dest' */
  449.         compositor->composite (dst, CAIRO_OPERATOR_ADD, src, mask,
  450.                                extents->bounded.x + src_x, extents->bounded.y + src_y,
  451.                                0, 0,
  452.                                extents->bounded.x,     extents->bounded.y,
  453.                                extents->bounded.width, extents->bounded.height);
  454.     }
  455.  
  456.     cairo_surface_destroy (src);
  457.     cairo_surface_destroy (mask);
  458.  
  459.     return CAIRO_STATUS_SUCCESS;
  460. }
  461.  
  462. static cairo_bool_t
  463. can_reduce_alpha_op (cairo_operator_t op)
  464. {
  465.     int iop = op;
  466.     switch (iop) {
  467.     case CAIRO_OPERATOR_OVER:
  468.     case CAIRO_OPERATOR_SOURCE:
  469.     case CAIRO_OPERATOR_ADD:
  470.         return TRUE;
  471.     default:
  472.         return FALSE;
  473.     }
  474. }
  475.  
  476. static cairo_bool_t
  477. reduce_alpha_op (cairo_surface_t *dst,
  478.                  cairo_operator_t op,
  479.                  const cairo_pattern_t *pattern)
  480. {
  481.     return dst->is_clear &&
  482.            dst->content == CAIRO_CONTENT_ALPHA &&
  483.            _cairo_pattern_is_opaque_solid (pattern) &&
  484.            can_reduce_alpha_op (op);
  485. }
  486.  
  487. static cairo_status_t
  488. fixup_unbounded (const cairo_mask_compositor_t *compositor,
  489.                  cairo_surface_t *dst,
  490.                  const cairo_composite_rectangles_t *extents)
  491. {
  492.     cairo_rectangle_int_t rects[4];
  493.     int n;
  494.  
  495.     if (extents->bounded.width  == extents->unbounded.width &&
  496.         extents->bounded.height == extents->unbounded.height)
  497.     {
  498.         return CAIRO_STATUS_SUCCESS;
  499.     }
  500.  
  501.     n = 0;
  502.     if (extents->bounded.width == 0 || extents->bounded.height == 0) {
  503.         rects[n].x = extents->unbounded.x;
  504.         rects[n].width = extents->unbounded.width;
  505.         rects[n].y = extents->unbounded.y;
  506.         rects[n].height = extents->unbounded.height;
  507.         n++;
  508.     } else {
  509.         /* top */
  510.         if (extents->bounded.y != extents->unbounded.y) {
  511.             rects[n].x = extents->unbounded.x;
  512.             rects[n].width = extents->unbounded.width;
  513.             rects[n].y = extents->unbounded.y;
  514.             rects[n].height = extents->bounded.y - extents->unbounded.y;
  515.             n++;
  516.         }
  517.         /* left */
  518.         if (extents->bounded.x != extents->unbounded.x) {
  519.             rects[n].x = extents->unbounded.x;
  520.             rects[n].width = extents->bounded.x - extents->unbounded.x;
  521.             rects[n].y = extents->bounded.y;
  522.             rects[n].height = extents->bounded.height;
  523.             n++;
  524.         }
  525.         /* right */
  526.         if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
  527.             rects[n].x = extents->bounded.x + extents->bounded.width;
  528.             rects[n].width = extents->unbounded.x + extents->unbounded.width - rects[n].x;
  529.             rects[n].y = extents->bounded.y;
  530.             rects[n].height = extents->bounded.height;
  531.             n++;
  532.         }
  533.         /* bottom */
  534.         if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
  535.             rects[n].x = extents->unbounded.x;
  536.             rects[n].width = extents->unbounded.width;
  537.             rects[n].y = extents->bounded.y + extents->bounded.height;
  538.             rects[n].height = extents->unbounded.y + extents->unbounded.height - rects[n].y;
  539.             n++;
  540.         }
  541.     }
  542.  
  543.     return compositor->fill_rectangles (dst, CAIRO_OPERATOR_CLEAR,
  544.                                         CAIRO_COLOR_TRANSPARENT,
  545.                                         rects, n);
  546. }
  547.  
  548. static cairo_status_t
  549. fixup_unbounded_with_mask (const cairo_mask_compositor_t *compositor,
  550.                            cairo_surface_t *dst,
  551.                            const cairo_composite_rectangles_t *extents)
  552. {
  553.     cairo_surface_t *mask;
  554.     int mask_x, mask_y;
  555.  
  556.     mask = get_clip_source (compositor,
  557.                             extents->clip, dst, &extents->unbounded,
  558.                             &mask_x, &mask_y);
  559.     if (unlikely (mask->status))
  560.         return mask->status;
  561.  
  562.     /* top */
  563.     if (extents->bounded.y != extents->unbounded.y) {
  564.         int x = extents->unbounded.x;
  565.         int y = extents->unbounded.y;
  566.         int width = extents->unbounded.width;
  567.         int height = extents->bounded.y - y;
  568.  
  569.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  570.                                x + mask_x, y + mask_y,
  571.                                0, 0,
  572.                                x, y,
  573.                                width, height);
  574.     }
  575.  
  576.     /* left */
  577.     if (extents->bounded.x != extents->unbounded.x) {
  578.         int x = extents->unbounded.x;
  579.         int y = extents->bounded.y;
  580.         int width = extents->bounded.x - x;
  581.         int height = extents->bounded.height;
  582.  
  583.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  584.                                x + mask_x, y + mask_y,
  585.                                0, 0,
  586.                                x, y,
  587.                                width, height);
  588.     }
  589.  
  590.     /* right */
  591.     if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
  592.         int x = extents->bounded.x + extents->bounded.width;
  593.         int y = extents->bounded.y;
  594.         int width = extents->unbounded.x + extents->unbounded.width - x;
  595.         int height = extents->bounded.height;
  596.  
  597.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  598.                                x + mask_x, y + mask_y,
  599.                                0, 0,
  600.                                x, y,
  601.                                width, height);
  602.     }
  603.  
  604.     /* bottom */
  605.     if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
  606.         int x = extents->unbounded.x;
  607.         int y = extents->bounded.y + extents->bounded.height;
  608.         int width = extents->unbounded.width;
  609.         int height = extents->unbounded.y + extents->unbounded.height - y;
  610.  
  611.         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
  612.                                x + mask_x, y + mask_y,
  613.                                0, 0,
  614.                                x, y,
  615.                                width, height);
  616.     }
  617.  
  618.     cairo_surface_destroy (mask);
  619.  
  620.     return CAIRO_STATUS_SUCCESS;
  621. }
  622.  
  623. static cairo_status_t
  624. fixup_unbounded_boxes (const cairo_mask_compositor_t *compositor,
  625.                        const cairo_composite_rectangles_t *extents,
  626.                        cairo_boxes_t *boxes)
  627. {
  628.     cairo_surface_t *dst = extents->surface;
  629.     cairo_boxes_t clear;
  630.     cairo_region_t *clip_region;
  631.     cairo_box_t box;
  632.     cairo_status_t status;
  633.     struct _cairo_boxes_chunk *chunk;
  634.     int i;
  635.  
  636.     assert (boxes->is_pixel_aligned);
  637.  
  638.     clip_region = NULL;
  639.     if (_cairo_clip_is_region (extents->clip) &&
  640.         (clip_region = _cairo_clip_get_region (extents->clip)) &&
  641.         cairo_region_contains_rectangle (clip_region,
  642.                                          &extents->bounded) == CAIRO_REGION_OVERLAP_IN)
  643.         clip_region = NULL;
  644.  
  645.  
  646.     if (boxes->num_boxes <= 1 && clip_region == NULL)
  647.         return fixup_unbounded (compositor, dst, extents);
  648.  
  649.     _cairo_boxes_init (&clear);
  650.  
  651.     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
  652.     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
  653.     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
  654.     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
  655.  
  656.     if (clip_region == NULL) {
  657.         cairo_boxes_t tmp;
  658.  
  659.         _cairo_boxes_init (&tmp);
  660.  
  661.         status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
  662.         assert (status == CAIRO_STATUS_SUCCESS);
  663.  
  664.         tmp.chunks.next = &boxes->chunks;
  665.         tmp.num_boxes += boxes->num_boxes;
  666.  
  667.         status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
  668.                                                           CAIRO_FILL_RULE_WINDING,
  669.                                                           &clear);
  670.  
  671.         tmp.chunks.next = NULL;
  672.     } else {
  673.         pixman_box32_t *pbox;
  674.  
  675.         pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
  676.         _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
  677.  
  678.         status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
  679.         assert (status == CAIRO_STATUS_SUCCESS);
  680.  
  681.         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
  682.             for (i = 0; i < chunk->count; i++) {
  683.                 status = _cairo_boxes_add (&clear,
  684.                                            CAIRO_ANTIALIAS_DEFAULT,
  685.                                            &chunk->base[i]);
  686.                 if (unlikely (status)) {
  687.                     _cairo_boxes_fini (&clear);
  688.                     return status;
  689.                 }
  690.             }
  691.         }
  692.  
  693.         status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
  694.                                                           CAIRO_FILL_RULE_WINDING,
  695.                                                           &clear);
  696.     }
  697.  
  698.     if (likely (status == CAIRO_STATUS_SUCCESS)) {
  699.         status = compositor->fill_boxes (dst,
  700.                                          CAIRO_OPERATOR_CLEAR,
  701.                                          CAIRO_COLOR_TRANSPARENT,
  702.                                          &clear);
  703.     }
  704.  
  705.     _cairo_boxes_fini (&clear);
  706.  
  707.     return status;
  708. }
  709.  
  710. enum {
  711.     NEED_CLIP_REGION = 0x1,
  712.     NEED_CLIP_SURFACE = 0x2,
  713.     FORCE_CLIP_REGION = 0x4,
  714. };
  715.  
  716. static cairo_bool_t
  717. need_bounded_clip (cairo_composite_rectangles_t *extents)
  718. {
  719.     unsigned int flags = NEED_CLIP_REGION;
  720.     if (! _cairo_clip_is_region (extents->clip))
  721.         flags |= NEED_CLIP_SURFACE;
  722.     return flags;
  723. }
  724.  
  725. static cairo_bool_t
  726. need_unbounded_clip (cairo_composite_rectangles_t *extents)
  727. {
  728.     unsigned int flags = 0;
  729.     if (! extents->is_bounded) {
  730.         flags |= NEED_CLIP_REGION;
  731.         if (! _cairo_clip_is_region (extents->clip))
  732.             flags |= NEED_CLIP_SURFACE;
  733.     }
  734.     if (extents->clip->path != NULL)
  735.         flags |= NEED_CLIP_SURFACE;
  736.     return flags;
  737. }
  738.  
  739. static cairo_status_t
  740. clip_and_composite (const cairo_mask_compositor_t *compositor,
  741.                     draw_func_t                  draw_func,
  742.                     draw_func_t                  mask_func,
  743.                     void                        *draw_closure,
  744.                     cairo_composite_rectangles_t*extents,
  745.                     unsigned int need_clip)
  746. {
  747.     cairo_surface_t *dst = extents->surface;
  748.     cairo_operator_t op = extents->op;
  749.     cairo_pattern_t *src = &extents->source_pattern.base;
  750.     cairo_region_t *clip_region = NULL;
  751.     cairo_status_t status;
  752.  
  753.     compositor->acquire (dst);
  754.  
  755.     if (need_clip & NEED_CLIP_REGION) {
  756.         clip_region = _cairo_clip_get_region (extents->clip);
  757.         if ((need_clip & FORCE_CLIP_REGION) == 0 &&
  758.             _cairo_composite_rectangles_can_reduce_clip (extents,
  759.                                                          extents->clip))
  760.             clip_region = NULL;
  761.         if (clip_region != NULL) {
  762.             status = compositor->set_clip_region (dst, clip_region);
  763.             if (unlikely (status)) {
  764.                 compositor->release (dst);
  765.                 return status;
  766.             }
  767.         }
  768.     }
  769.  
  770.     if (reduce_alpha_op (dst, op, &extents->source_pattern.base)) {
  771.         op = CAIRO_OPERATOR_ADD;
  772.         src = NULL;
  773.     }
  774.  
  775.     if (op == CAIRO_OPERATOR_SOURCE) {
  776.         status = clip_and_composite_source (compositor,
  777.                                             draw_closure, draw_func, mask_func,
  778.                                             src, extents);
  779.     } else {
  780.         if (op == CAIRO_OPERATOR_CLEAR) {
  781.             op = CAIRO_OPERATOR_DEST_OUT;
  782.             src = NULL;
  783.         }
  784.  
  785.         if (need_clip & NEED_CLIP_SURFACE) {
  786.             if (extents->is_bounded) {
  787.                 status = clip_and_composite_with_mask (compositor,
  788.                                                        draw_closure,
  789.                                                        draw_func,
  790.                                                        mask_func,
  791.                                                        op, src, extents);
  792.             } else {
  793.                 status = clip_and_composite_combine (compositor,
  794.                                                      draw_closure,
  795.                                                      draw_func,
  796.                                                      op, src, extents);
  797.             }
  798.         } else {
  799.             status = draw_func (compositor,
  800.                                 dst, draw_closure,
  801.                                 op, src, &extents->source_sample_area,
  802.                                 0, 0,
  803.                                 &extents->bounded,
  804.                                 extents->clip);
  805.         }
  806.     }
  807.  
  808.     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
  809.         if (need_clip & NEED_CLIP_SURFACE)
  810.             status = fixup_unbounded_with_mask (compositor, dst, extents);
  811.         else
  812.             status = fixup_unbounded (compositor, dst, extents);
  813.     }
  814.  
  815.     if (clip_region)
  816.         compositor->set_clip_region (dst, NULL);
  817.  
  818.     compositor->release (dst);
  819.  
  820.     return status;
  821. }
  822.  
  823. static cairo_int_status_t
  824. trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
  825.                        cairo_boxes_t *boxes)
  826. {
  827.     cairo_box_t box;
  828.  
  829.     _cairo_boxes_extents (boxes, &box);
  830.     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
  831. }
  832.  
  833. static cairo_status_t
  834. upload_boxes (const cairo_mask_compositor_t *compositor,
  835.               cairo_composite_rectangles_t *extents,
  836.               cairo_boxes_t *boxes)
  837. {
  838.     cairo_surface_t *dst = extents->surface;
  839.     const cairo_pattern_t *source = &extents->source_pattern.base;
  840.     cairo_surface_t *src;
  841.     cairo_rectangle_int_t limit;
  842.     cairo_int_status_t status;
  843.     int tx, ty;
  844.  
  845.     src = _cairo_pattern_get_source ((cairo_surface_pattern_t *)source, &limit);
  846.     if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
  847.         return CAIRO_INT_STATUS_UNSUPPORTED;
  848.  
  849.     if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
  850.         return CAIRO_INT_STATUS_UNSUPPORTED;
  851.  
  852.     /* Check that the data is entirely within the image */
  853.     if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
  854.         return CAIRO_INT_STATUS_UNSUPPORTED;
  855.  
  856.     if (extents->bounded.x + extents->bounded.width  + tx > limit.x + limit.width ||
  857.         extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
  858.         return CAIRO_INT_STATUS_UNSUPPORTED;
  859.  
  860.     tx += limit.x;
  861.     ty += limit.y;
  862.  
  863.     if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
  864.         status = compositor->draw_image_boxes (dst,
  865.                                                (cairo_image_surface_t *)src,
  866.                                                boxes, tx, ty);
  867.     else
  868.         status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
  869.                                          tx, ty);
  870.  
  871.     return status;
  872. }
  873.  
  874. static cairo_status_t
  875. composite_boxes (const cairo_mask_compositor_t *compositor,
  876.                  const cairo_composite_rectangles_t *extents,
  877.                  cairo_boxes_t *boxes)
  878. {
  879.     cairo_surface_t *dst = extents->surface;
  880.     cairo_operator_t op = extents->op;
  881.     const cairo_pattern_t *source = &extents->source_pattern.base;
  882.     cairo_bool_t need_clip_mask = extents->clip->path != NULL;
  883.     cairo_status_t status;
  884.  
  885.     if (need_clip_mask &&
  886.         (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
  887.     {
  888.         return CAIRO_INT_STATUS_UNSUPPORTED;
  889.     }
  890.  
  891.     status = compositor->acquire (dst);
  892.     if (unlikely (status))
  893.         return status;
  894.  
  895.     if (! need_clip_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
  896.         const cairo_color_t *color;
  897.  
  898.         color = &((cairo_solid_pattern_t *) source)->color;
  899.         status = compositor->fill_boxes (dst, op, color, boxes);
  900.     } else {
  901.         cairo_surface_t *src, *mask = NULL;
  902.         int src_x, src_y;
  903.         int mask_x = 0, mask_y = 0;
  904.  
  905.         if (need_clip_mask) {
  906.             mask = get_clip_source (compositor,
  907.                                     extents->clip, dst, &extents->bounded,
  908.                                     &mask_x, &mask_y);
  909.             if (unlikely (mask->status))
  910.                 return mask->status;
  911.  
  912.             if (op == CAIRO_OPERATOR_CLEAR) {
  913.                 source = NULL;
  914.                 op = CAIRO_OPERATOR_DEST_OUT;
  915.             }
  916.         }
  917.  
  918.         if (source || mask == NULL) {
  919.             src = compositor->pattern_to_surface (dst, source, FALSE,
  920.                                                   &extents->bounded,
  921.                                                   &extents->source_sample_area,
  922.                                                   &src_x, &src_y);
  923.         } else {
  924.             src = mask;
  925.             src_x = mask_x;
  926.             src_y = mask_y;
  927.             mask = NULL;
  928.         }
  929.  
  930.         status = compositor->composite_boxes (dst, op, src, mask,
  931.                                               src_x, src_y,
  932.                                               mask_x, mask_y,
  933.                                               0, 0,
  934.                                               boxes, &extents->bounded);
  935.  
  936.         cairo_surface_destroy (src);
  937.         cairo_surface_destroy (mask);
  938.     }
  939.  
  940.     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
  941.         status = fixup_unbounded_boxes (compositor, extents, boxes);
  942.  
  943.     compositor->release (dst);
  944.  
  945.     return status;
  946. }
  947.  
  948. static cairo_status_t
  949. clip_and_composite_boxes (const cairo_mask_compositor_t *compositor,
  950.                           cairo_composite_rectangles_t *extents,
  951.                           cairo_boxes_t *boxes)
  952. {
  953.     cairo_surface_t *dst = extents->surface;
  954.     cairo_int_status_t status;
  955.  
  956.     if (boxes->num_boxes == 0) {
  957.         if (extents->is_bounded)
  958.             return CAIRO_STATUS_SUCCESS;
  959.  
  960.         return fixup_unbounded_boxes (compositor, extents, boxes);
  961.     }
  962.  
  963.     if (! boxes->is_pixel_aligned)
  964.         return CAIRO_INT_STATUS_UNSUPPORTED;
  965.  
  966.     status = trim_extents_to_boxes (extents, boxes);
  967.     if (unlikely (status))
  968.         return status;
  969.  
  970.     if (extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
  971.         extents->clip->path == NULL &&
  972.         (extents->op == CAIRO_OPERATOR_SOURCE ||
  973.          (dst->is_clear && (extents->op == CAIRO_OPERATOR_OVER ||
  974.                             extents->op == CAIRO_OPERATOR_ADD))))
  975.     {
  976.         status = upload_boxes (compositor, extents, boxes);
  977.         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  978.             return status;
  979.     }
  980.  
  981.     return composite_boxes (compositor, extents, boxes);
  982. }
  983.  
  984. /* high-level compositor interface */
  985.  
  986. static cairo_int_status_t
  987. _cairo_mask_compositor_paint (const cairo_compositor_t *_compositor,
  988.                               cairo_composite_rectangles_t *extents)
  989. {
  990.     cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
  991.     cairo_boxes_t boxes;
  992.     cairo_int_status_t status;
  993.  
  994.     status = compositor->check_composite (extents);
  995.     if (unlikely (status))
  996.         return status;
  997.  
  998.     _cairo_clip_steal_boxes (extents->clip, &boxes);
  999.     status = clip_and_composite_boxes (compositor, extents, &boxes);
  1000.     _cairo_clip_unsteal_boxes (extents->clip, &boxes);
  1001.  
  1002.     return status;
  1003. }
  1004.  
  1005. struct composite_opacity_info {
  1006.     const cairo_mask_compositor_t *compositor;
  1007.     uint8_t op;
  1008.     cairo_surface_t *dst;
  1009.     cairo_surface_t *src;
  1010.     int src_x, src_y;
  1011.     double opacity;
  1012. };
  1013.  
  1014. static void composite_opacity(void *closure,
  1015.                               int16_t x, int16_t y,
  1016.                               int16_t w, int16_t h,
  1017.                               uint16_t coverage)
  1018. {
  1019.     struct composite_opacity_info *info = closure;
  1020.     const cairo_mask_compositor_t *compositor = info->compositor;
  1021.     cairo_surface_t *mask;
  1022.     int mask_x, mask_y;
  1023.     cairo_color_t color;
  1024.     cairo_solid_pattern_t solid;
  1025.  
  1026.     _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
  1027.     _cairo_pattern_init_solid (&solid, &color);
  1028.     mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
  1029.                                            &_cairo_unbounded_rectangle,
  1030.                                            &_cairo_unbounded_rectangle,
  1031.                                            &mask_x, &mask_y);
  1032.     if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
  1033.         if (info->src) {
  1034.             compositor->composite (info->dst, info->op, info->src, mask,
  1035.                                    x + info->src_x,  y + info->src_y,
  1036.                                    mask_x,           mask_y,
  1037.                                    x,                y,
  1038.                                    w,                h);
  1039.         } else {
  1040.             compositor->composite (info->dst, info->op, mask, NULL,
  1041.                                    mask_x,            mask_y,
  1042.                                    0,                 0,
  1043.                                    x,                 y,
  1044.                                    w,                 h);
  1045.         }
  1046.     }
  1047.  
  1048.     cairo_surface_destroy (mask);
  1049. }
  1050.  
  1051. static cairo_int_status_t
  1052. composite_opacity_boxes (const cairo_mask_compositor_t *compositor,
  1053.                          cairo_surface_t                *dst,
  1054.                          void                           *closure,
  1055.                          cairo_operator_t                op,
  1056.                          const cairo_pattern_t          *src_pattern,
  1057.                          const cairo_rectangle_int_t    *src_sample,
  1058.                          int                             dst_x,
  1059.                          int                             dst_y,
  1060.                          const cairo_rectangle_int_t    *extents,
  1061.                          cairo_clip_t                   *clip)
  1062. {
  1063.     const cairo_solid_pattern_t *mask_pattern = closure;
  1064.     struct composite_opacity_info info;
  1065.     int i;
  1066.  
  1067.     assert (clip);
  1068.  
  1069.     info.compositor = compositor;
  1070.     info.op = op;
  1071.     info.dst = dst;
  1072.  
  1073.     if (src_pattern != NULL) {
  1074.         info.src = compositor->pattern_to_surface (dst, src_pattern, FALSE,
  1075.                                                    extents, src_sample,
  1076.                                                    &info.src_x, &info.src_y);
  1077.         if (unlikely (info.src->status))
  1078.             return info.src->status;
  1079.     } else
  1080.         info.src = NULL;
  1081.  
  1082.     info.opacity = mask_pattern->color.alpha / (double) 0xffff;
  1083.  
  1084.     /* XXX for lots of boxes create a clip region for the fully opaque areas */
  1085.     for (i = 0; i < clip->num_boxes; i++)
  1086.         do_unaligned_box(composite_opacity, &info,
  1087.                          &clip->boxes[i], dst_x, dst_y);
  1088.     cairo_surface_destroy (info.src);
  1089.  
  1090.     return CAIRO_STATUS_SUCCESS;
  1091. }
  1092.  
  1093. struct composite_box_info {
  1094.     const cairo_mask_compositor_t *compositor;
  1095.     cairo_surface_t *dst;
  1096.     cairo_surface_t *src;
  1097.     int src_x, src_y;
  1098.     uint8_t op;
  1099. };
  1100.  
  1101. static void composite_box(void *closure,
  1102.                           int16_t x, int16_t y,
  1103.                           int16_t w, int16_t h,
  1104.                           uint16_t coverage)
  1105. {
  1106.     struct composite_box_info *info = closure;
  1107.     const cairo_mask_compositor_t *compositor = info->compositor;
  1108.  
  1109.     if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
  1110.         cairo_surface_t *mask;
  1111.         cairo_color_t color;
  1112.         cairo_solid_pattern_t solid;
  1113.         int mask_x, mask_y;
  1114.  
  1115.         _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
  1116.         _cairo_pattern_init_solid (&solid, &color);
  1117.  
  1118.         mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
  1119.                                                &_cairo_unbounded_rectangle,
  1120.                                                &_cairo_unbounded_rectangle,
  1121.                                                &mask_x, &mask_y);
  1122.  
  1123.         if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
  1124.             compositor->composite (info->dst, info->op, info->src, mask,
  1125.                                    x + info->src_x,  y + info->src_y,
  1126.                                    mask_x,           mask_y,
  1127.                                    x,                y,
  1128.                                    w,                h);
  1129.         }
  1130.  
  1131.         cairo_surface_destroy (mask);
  1132.     } else {
  1133.         compositor->composite (info->dst, info->op, info->src, NULL,
  1134.                                x + info->src_x,  y + info->src_y,
  1135.                                0,                0,
  1136.                                x,                y,
  1137.                                w,                h);
  1138.     }
  1139. }
  1140.  
  1141. static cairo_int_status_t
  1142. composite_mask_clip_boxes (const cairo_mask_compositor_t *compositor,
  1143.                            cairo_surface_t              *dst,
  1144.                            void                         *closure,
  1145.                            cairo_operator_t              op,
  1146.                            const cairo_pattern_t        *src_pattern,
  1147.                            const cairo_rectangle_int_t  *src_sample,
  1148.                            int                           dst_x,
  1149.                            int                           dst_y,
  1150.                            const cairo_rectangle_int_t  *extents,
  1151.                            cairo_clip_t                 *clip)
  1152. {
  1153.     cairo_composite_rectangles_t *composite = closure;
  1154.     struct composite_box_info info;
  1155.     int i;
  1156.  
  1157.     assert (src_pattern == NULL);
  1158.     assert (op == CAIRO_OPERATOR_SOURCE);
  1159.  
  1160.     info.compositor = compositor;
  1161.     info.op = CAIRO_OPERATOR_SOURCE;
  1162.     info.dst = dst;
  1163.     info.src = compositor->pattern_to_surface (dst,
  1164.                                                &composite->mask_pattern.base,
  1165.                                                FALSE, extents,
  1166.                                                &composite->mask_sample_area,
  1167.                                                &info.src_x, &info.src_y);
  1168.     if (unlikely (info.src->status))
  1169.         return info.src->status;
  1170.  
  1171.     info.src_x += dst_x;
  1172.     info.src_y += dst_y;
  1173.  
  1174.     for (i = 0; i < clip->num_boxes; i++)
  1175.         do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
  1176.  
  1177.     cairo_surface_destroy (info.src);
  1178.  
  1179.     return CAIRO_STATUS_SUCCESS;
  1180. }
  1181.  
  1182. static cairo_int_status_t
  1183. composite_mask (const cairo_mask_compositor_t *compositor,
  1184.                 cairo_surface_t                 *dst,
  1185.                 void                            *closure,
  1186.                 cairo_operator_t                 op,
  1187.                 const cairo_pattern_t           *src_pattern,
  1188.                 const cairo_rectangle_int_t     *src_sample,
  1189.                 int                              dst_x,
  1190.                 int                              dst_y,
  1191.                 const cairo_rectangle_int_t     *extents,
  1192.                 cairo_clip_t                    *clip)
  1193. {
  1194.     cairo_composite_rectangles_t *composite = closure;
  1195.     cairo_surface_t *src, *mask;
  1196.     int src_x, src_y;
  1197.     int mask_x, mask_y;
  1198.  
  1199.     if (src_pattern != NULL) {
  1200.         src = compositor->pattern_to_surface (dst, src_pattern, FALSE,
  1201.                                               extents, src_sample,
  1202.                                               &src_x, &src_y);
  1203.         if (unlikely (src->status))
  1204.             return src->status;
  1205.  
  1206.         mask = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, TRUE,
  1207.                                                extents, &composite->mask_sample_area,
  1208.                                                &mask_x, &mask_y);
  1209.         if (unlikely (mask->status)) {
  1210.             cairo_surface_destroy (src);
  1211.             return mask->status;
  1212.         }
  1213.  
  1214.         compositor->composite (dst, op, src, mask,
  1215.                                extents->x + src_x,  extents->y + src_y,
  1216.                                extents->x + mask_x, extents->y + mask_y,
  1217.                                extents->x - dst_x,  extents->y - dst_y,
  1218.                                extents->width,      extents->height);
  1219.  
  1220.         cairo_surface_destroy (mask);
  1221.         cairo_surface_destroy (src);
  1222.     } else {
  1223.         src = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, FALSE,
  1224.                                               extents, &composite->mask_sample_area,
  1225.                                               &src_x, &src_y);
  1226.         if (unlikely (src->status))
  1227.             return src->status;
  1228.  
  1229.         compositor->composite (dst, op, src, NULL,
  1230.                                extents->x + src_x,  extents->y + src_y,
  1231.                                0, 0,
  1232.                                extents->x - dst_x,  extents->y - dst_y,
  1233.                                extents->width,      extents->height);
  1234.  
  1235.         cairo_surface_destroy (src);
  1236.     }
  1237.  
  1238.     return CAIRO_STATUS_SUCCESS;
  1239. }
  1240.  
  1241. static cairo_int_status_t
  1242. _cairo_mask_compositor_mask (const cairo_compositor_t *_compositor,
  1243.                              cairo_composite_rectangles_t *extents)
  1244. {
  1245.     const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
  1246.     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
  1247.  
  1248.     status = compositor->check_composite (extents);
  1249.     if (unlikely (status))
  1250.         return status;
  1251.  
  1252.     if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
  1253.         extents->clip->path == NULL &&
  1254.         _cairo_clip_is_region (extents->clip)) {
  1255.         status = clip_and_composite (compositor,
  1256.                                      composite_opacity_boxes,
  1257.                                      composite_opacity_boxes,
  1258.                                      &extents->mask_pattern.solid,
  1259.                                      extents, need_unbounded_clip (extents));
  1260.     } else {
  1261.         status = clip_and_composite (compositor,
  1262.                                      composite_mask,
  1263.                                      extents->clip->path == NULL ? composite_mask_clip_boxes : NULL,
  1264.                                      extents,
  1265.                                      extents, need_bounded_clip (extents));
  1266.     }
  1267.  
  1268.     return status;
  1269. }
  1270.  
  1271. static cairo_int_status_t
  1272. _cairo_mask_compositor_stroke (const cairo_compositor_t *_compositor,
  1273.                                cairo_composite_rectangles_t *extents,
  1274.                                const cairo_path_fixed_t *path,
  1275.                                const cairo_stroke_style_t       *style,
  1276.                                const cairo_matrix_t     *ctm,
  1277.                                const cairo_matrix_t     *ctm_inverse,
  1278.                                double            tolerance,
  1279.                                cairo_antialias_t         antialias)
  1280. {
  1281.     const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
  1282.     cairo_surface_t *mask;
  1283.     cairo_surface_pattern_t pattern;
  1284.     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
  1285.  
  1286.     status = compositor->check_composite (extents);
  1287.     if (unlikely (status))
  1288.         return status;
  1289.  
  1290.     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
  1291.         cairo_boxes_t boxes;
  1292.  
  1293.         _cairo_boxes_init_with_clip (&boxes, extents->clip);
  1294.         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
  1295.                                                                 style,
  1296.                                                                 ctm,
  1297.                                                                 antialias,
  1298.                                                                 &boxes);
  1299.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  1300.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  1301.         _cairo_boxes_fini (&boxes);
  1302.     }
  1303.  
  1304.  
  1305.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  1306.         mask = cairo_surface_create_similar_image (extents->surface,
  1307.                                                    CAIRO_FORMAT_A8,
  1308.                                                    extents->bounded.width,
  1309.                                                    extents->bounded.height);
  1310.         if (unlikely (mask->status))
  1311.             return mask->status;
  1312.  
  1313.         status = _cairo_surface_offset_stroke (mask,
  1314.                                                extents->bounded.x,
  1315.                                                extents->bounded.y,
  1316.                                                CAIRO_OPERATOR_ADD,
  1317.                                                &_cairo_pattern_white.base,
  1318.                                                path, style, ctm, ctm_inverse,
  1319.                                                tolerance, antialias,
  1320.                                                extents->clip);
  1321.         if (unlikely (status)) {
  1322.             cairo_surface_destroy (mask);
  1323.             return status;
  1324.         }
  1325.  
  1326.         _cairo_pattern_init_for_surface (&pattern, mask);
  1327.         cairo_surface_destroy (mask);
  1328.  
  1329.         cairo_matrix_init_translate (&pattern.base.matrix,
  1330.                                      -extents->bounded.x,
  1331.                                      -extents->bounded.y);
  1332.         pattern.base.filter = CAIRO_FILTER_NEAREST;
  1333.         pattern.base.extend = CAIRO_EXTEND_NONE;
  1334.         status = _cairo_surface_mask (extents->surface,
  1335.                                       extents->op,
  1336.                                       &extents->source_pattern.base,
  1337.                                       &pattern.base,
  1338.                                       extents->clip);
  1339.         _cairo_pattern_fini (&pattern.base);
  1340.     }
  1341.  
  1342.     return status;
  1343. }
  1344.  
  1345. static cairo_int_status_t
  1346. _cairo_mask_compositor_fill (const cairo_compositor_t *_compositor,
  1347.                              cairo_composite_rectangles_t *extents,
  1348.                              const cairo_path_fixed_t   *path,
  1349.                              cairo_fill_rule_t   fill_rule,
  1350.                              double                      tolerance,
  1351.                              cairo_antialias_t   antialias)
  1352. {
  1353.     const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
  1354.     cairo_surface_t *mask;
  1355.     cairo_surface_pattern_t pattern;
  1356.     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
  1357.  
  1358.     status = compositor->check_composite (extents);
  1359.     if (unlikely (status))
  1360.         return status;
  1361.  
  1362.     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
  1363.         cairo_boxes_t boxes;
  1364.  
  1365.         _cairo_boxes_init_with_clip (&boxes, extents->clip);
  1366.         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
  1367.                                                               fill_rule,
  1368.                                                               antialias,
  1369.                                                               &boxes);
  1370.         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  1371.             status = clip_and_composite_boxes (compositor, extents, &boxes);
  1372.         _cairo_boxes_fini (&boxes);
  1373.     }
  1374.  
  1375.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  1376.         mask = cairo_surface_create_similar_image (extents->surface,
  1377.                                                    CAIRO_FORMAT_A8,
  1378.                                                    extents->bounded.width,
  1379.                                                    extents->bounded.height);
  1380.         if (unlikely (mask->status))
  1381.             return mask->status;
  1382.  
  1383.         status = _cairo_surface_offset_fill (mask,
  1384.                                              extents->bounded.x,
  1385.                                              extents->bounded.y,
  1386.                                              CAIRO_OPERATOR_ADD,
  1387.                                              &_cairo_pattern_white.base,
  1388.                                              path, fill_rule, tolerance, antialias,
  1389.                                              extents->clip);
  1390.         if (unlikely (status)) {
  1391.             cairo_surface_destroy (mask);
  1392.             return status;
  1393.         }
  1394.  
  1395.         _cairo_pattern_init_for_surface (&pattern, mask);
  1396.         cairo_surface_destroy (mask);
  1397.  
  1398.         cairo_matrix_init_translate (&pattern.base.matrix,
  1399.                                      -extents->bounded.x,
  1400.                                      -extents->bounded.y);
  1401.         pattern.base.filter = CAIRO_FILTER_NEAREST;
  1402.         pattern.base.extend = CAIRO_EXTEND_NONE;
  1403.         status = _cairo_surface_mask (extents->surface,
  1404.                                       extents->op,
  1405.                                       &extents->source_pattern.base,
  1406.                                       &pattern.base,
  1407.                                       extents->clip);
  1408.         _cairo_pattern_fini (&pattern.base);
  1409.     }
  1410.  
  1411.     return status;
  1412. }
  1413.  
  1414. static cairo_int_status_t
  1415. _cairo_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
  1416.                                cairo_composite_rectangles_t *extents,
  1417.                                cairo_scaled_font_t      *scaled_font,
  1418.                                cairo_glyph_t            *glyphs,
  1419.                                int                       num_glyphs,
  1420.                                cairo_bool_t              overlap)
  1421. {
  1422.     const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
  1423.     cairo_surface_t *mask;
  1424.     cairo_surface_pattern_t pattern;
  1425.     cairo_int_status_t status;
  1426.  
  1427.     status = compositor->check_composite (extents);
  1428.     if (unlikely (status))
  1429.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1430.  
  1431.     mask = cairo_surface_create_similar_image (extents->surface,
  1432.                                                CAIRO_FORMAT_A8,
  1433.                                                extents->bounded.width,
  1434.                                                extents->bounded.height);
  1435.     if (unlikely (mask->status))
  1436.         return mask->status;
  1437.  
  1438.     status = _cairo_surface_offset_glyphs (mask,
  1439.                                            extents->bounded.x,
  1440.                                            extents->bounded.y,
  1441.                                            CAIRO_OPERATOR_ADD,
  1442.                                            &_cairo_pattern_white.base,
  1443.                                            scaled_font, glyphs, num_glyphs,
  1444.                                            extents->clip);
  1445.     if (unlikely (status)) {
  1446.         cairo_surface_destroy (mask);
  1447.         return status;
  1448.     }
  1449.  
  1450.     _cairo_pattern_init_for_surface (&pattern, mask);
  1451.     cairo_surface_destroy (mask);
  1452.  
  1453.     cairo_matrix_init_translate (&pattern.base.matrix,
  1454.                                  -extents->bounded.x,
  1455.                                  -extents->bounded.y);
  1456.     pattern.base.filter = CAIRO_FILTER_NEAREST;
  1457.     pattern.base.extend = CAIRO_EXTEND_NONE;
  1458.     status = _cairo_surface_mask (extents->surface,
  1459.                                   extents->op,
  1460.                                   &extents->source_pattern.base,
  1461.                                   &pattern.base,
  1462.                                   extents->clip);
  1463.     _cairo_pattern_fini (&pattern.base);
  1464.  
  1465.     return status;
  1466. }
  1467.  
  1468. void
  1469. _cairo_mask_compositor_init (cairo_mask_compositor_t *compositor,
  1470.                              const cairo_compositor_t *delegate)
  1471. {
  1472.     compositor->base.delegate = delegate;
  1473.  
  1474.     compositor->base.paint = _cairo_mask_compositor_paint;
  1475.     compositor->base.mask  = _cairo_mask_compositor_mask;
  1476.     compositor->base.fill  = _cairo_mask_compositor_fill;
  1477.     compositor->base.stroke = _cairo_mask_compositor_stroke;
  1478.     compositor->base.glyphs = _cairo_mask_compositor_glyphs;
  1479. }
  1480.