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 "test-compositor-surface-private.h"
  45.  
  46. #include "cairo-clip-private.h"
  47. #include "cairo-composite-rectangles-private.h"
  48. #include "cairo-compositor-private.h"
  49. #include "cairo-error-private.h"
  50. #include "cairo-image-surface-private.h"
  51. #include "cairo-region-private.h"
  52. #include "cairo-traps-private.h"
  53.  
  54. /* The intention is that this is a surface that just works, and most
  55.  * important of all does not try to be clever!
  56.  */
  57.  
  58. typedef cairo_int_status_t
  59. (*draw_func_t) (cairo_image_surface_t           *dst,
  60.                 void                            *closure,
  61.                 cairo_operator_t                 op,
  62.                 const cairo_pattern_t           *pattern,
  63.                 int                              dst_x,
  64.                 int                              dst_y,
  65.                 const cairo_rectangle_int_t     *extents);
  66.  
  67. static pixman_op_t
  68. _pixman_operator (cairo_operator_t op)
  69. {
  70.     switch ((int) op) {
  71.     case CAIRO_OPERATOR_CLEAR:
  72.         return PIXMAN_OP_CLEAR;
  73.  
  74.     case CAIRO_OPERATOR_SOURCE:
  75.         return PIXMAN_OP_SRC;
  76.     case CAIRO_OPERATOR_OVER:
  77.         return PIXMAN_OP_OVER;
  78.     case CAIRO_OPERATOR_IN:
  79.         return PIXMAN_OP_IN;
  80.     case CAIRO_OPERATOR_OUT:
  81.         return PIXMAN_OP_OUT;
  82.     case CAIRO_OPERATOR_ATOP:
  83.         return PIXMAN_OP_ATOP;
  84.  
  85.     case CAIRO_OPERATOR_DEST:
  86.         return PIXMAN_OP_DST;
  87.     case CAIRO_OPERATOR_DEST_OVER:
  88.         return PIXMAN_OP_OVER_REVERSE;
  89.     case CAIRO_OPERATOR_DEST_IN:
  90.         return PIXMAN_OP_IN_REVERSE;
  91.     case CAIRO_OPERATOR_DEST_OUT:
  92.         return PIXMAN_OP_OUT_REVERSE;
  93.     case CAIRO_OPERATOR_DEST_ATOP:
  94.         return PIXMAN_OP_ATOP_REVERSE;
  95.  
  96.     case CAIRO_OPERATOR_XOR:
  97.         return PIXMAN_OP_XOR;
  98.     case CAIRO_OPERATOR_ADD:
  99.         return PIXMAN_OP_ADD;
  100.     case CAIRO_OPERATOR_SATURATE:
  101.         return PIXMAN_OP_SATURATE;
  102.  
  103.     case CAIRO_OPERATOR_MULTIPLY:
  104.         return PIXMAN_OP_MULTIPLY;
  105.     case CAIRO_OPERATOR_SCREEN:
  106.         return PIXMAN_OP_SCREEN;
  107.     case CAIRO_OPERATOR_OVERLAY:
  108.         return PIXMAN_OP_OVERLAY;
  109.     case CAIRO_OPERATOR_DARKEN:
  110.         return PIXMAN_OP_DARKEN;
  111.     case CAIRO_OPERATOR_LIGHTEN:
  112.         return PIXMAN_OP_LIGHTEN;
  113.     case CAIRO_OPERATOR_COLOR_DODGE:
  114.         return PIXMAN_OP_COLOR_DODGE;
  115.     case CAIRO_OPERATOR_COLOR_BURN:
  116.         return PIXMAN_OP_COLOR_BURN;
  117.     case CAIRO_OPERATOR_HARD_LIGHT:
  118.         return PIXMAN_OP_HARD_LIGHT;
  119.     case CAIRO_OPERATOR_SOFT_LIGHT:
  120.         return PIXMAN_OP_SOFT_LIGHT;
  121.     case CAIRO_OPERATOR_DIFFERENCE:
  122.         return PIXMAN_OP_DIFFERENCE;
  123.     case CAIRO_OPERATOR_EXCLUSION:
  124.         return PIXMAN_OP_EXCLUSION;
  125.     case CAIRO_OPERATOR_HSL_HUE:
  126.         return PIXMAN_OP_HSL_HUE;
  127.     case CAIRO_OPERATOR_HSL_SATURATION:
  128.         return PIXMAN_OP_HSL_SATURATION;
  129.     case CAIRO_OPERATOR_HSL_COLOR:
  130.         return PIXMAN_OP_HSL_COLOR;
  131.     case CAIRO_OPERATOR_HSL_LUMINOSITY:
  132.         return PIXMAN_OP_HSL_LUMINOSITY;
  133.  
  134.     default:
  135.         ASSERT_NOT_REACHED;
  136.         return PIXMAN_OP_OVER;
  137.     }
  138. }
  139.  
  140. static cairo_image_surface_t *
  141. create_composite_mask (cairo_image_surface_t    *dst,
  142.                        void                     *draw_closure,
  143.                        draw_func_t               draw_func,
  144.                        const cairo_composite_rectangles_t *extents)
  145. {
  146.     cairo_image_surface_t *surface;
  147.     cairo_int_status_t status;
  148.  
  149.     TRACE ((stderr, "%s\n", __FUNCTION__));
  150.  
  151.     surface = (cairo_image_surface_t *)
  152.         _cairo_image_surface_create_with_pixman_format (NULL, PIXMAN_a8,
  153.                                                         extents->bounded.width,
  154.                                                         extents->bounded.height,
  155.                                                         0);
  156.     if (unlikely (surface->base.status))
  157.         return surface;
  158.  
  159.     status = draw_func (surface, draw_closure,
  160.                         CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base,
  161.                         extents->bounded.x, extents->bounded.y,
  162.                         &extents->bounded);
  163.     if (unlikely (status))
  164.         goto error;
  165.  
  166.     status = _cairo_clip_combine_with_surface (extents->clip,
  167.                                                &surface->base,
  168.                                                extents->bounded.x,
  169.                                                extents->bounded.y);
  170.     if (unlikely (status))
  171.         goto error;
  172.  
  173.     return surface;
  174.  
  175. error:
  176.     cairo_surface_destroy (&surface->base);
  177.     return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
  178. }
  179.  
  180. /* Handles compositing with a clip surface when the operator allows
  181.  * us to combine the clip with the mask
  182.  */
  183. static cairo_status_t
  184. clip_and_composite_with_mask (const cairo_composite_rectangles_t*extents,
  185.                               draw_func_t                draw_func,
  186.                               void                      *draw_closure)
  187. {
  188.     cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
  189.     cairo_image_surface_t *mask;
  190.     pixman_image_t *src;
  191.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  192.     int src_x, src_y;
  193.  
  194.     TRACE ((stderr, "%s\n", __FUNCTION__));
  195.  
  196.     mask = create_composite_mask (dst, draw_closure, draw_func, extents);
  197.     if (unlikely (mask->base.status))
  198.         return mask->base.status;
  199.  
  200.     src = _pixman_image_for_pattern (dst,
  201.                                      &extents->source_pattern.base, FALSE,
  202.                                      &extents->bounded,
  203.                                      &extents->source_sample_area,
  204.                                      &src_x, &src_y);
  205.     if (unlikely (src == NULL)) {
  206.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  207.         goto error;
  208.     }
  209.  
  210.     pixman_image_composite32 (_pixman_operator (extents->op),
  211.                               src, mask->pixman_image, dst->pixman_image,
  212.                               extents->bounded.x + src_x,
  213.                               extents->bounded.y + src_y,
  214.                               0, 0,
  215.                               extents->bounded.x,      extents->bounded.y,
  216.                               extents->bounded.width,  extents->bounded.height);
  217.  
  218.     pixman_image_unref (src);
  219. error:
  220.     cairo_surface_destroy (&mask->base);
  221.     return status;
  222. }
  223.  
  224. /* Handles compositing with a clip surface when we have to do the operation
  225.  * in two pieces and combine them together.
  226.  */
  227. static cairo_status_t
  228. clip_and_composite_combine (const cairo_composite_rectangles_t*extents,
  229.                             draw_func_t                  draw_func,
  230.                             void                        *draw_closure)
  231. {
  232.     cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
  233.     cairo_image_surface_t *tmp, *clip;
  234.     int clip_x, clip_y;
  235.     cairo_status_t status;
  236.  
  237.     TRACE ((stderr, "%s\n", __FUNCTION__));
  238.  
  239.     tmp = (cairo_image_surface_t *)
  240.         _cairo_image_surface_create_with_pixman_format (NULL,
  241.                                                         dst->pixman_format,
  242.                                                         extents->bounded.width,
  243.                                                         extents->bounded.height,
  244.                                                         0);
  245.     if (unlikely (tmp->base.status))
  246.         return tmp->base.status;
  247.  
  248.     pixman_image_composite32 (PIXMAN_OP_SRC,
  249.                               dst->pixman_image, NULL, tmp->pixman_image,
  250.                               extents->bounded.x,      extents->bounded.y,
  251.                               0, 0,
  252.                               0, 0,
  253.                               extents->bounded.width,  extents->bounded.height);
  254.  
  255.     status = draw_func (tmp, draw_closure,
  256.                         extents->op, &extents->source_pattern.base,
  257.                         extents->bounded.x, extents->bounded.y,
  258.                         &extents->bounded);
  259.     if (unlikely (status))
  260.         goto error;
  261.  
  262.     clip = (cairo_image_surface_t *)
  263.         _cairo_clip_get_surface (extents->clip, &dst->base, &clip_x, &clip_y);
  264.     if (unlikely (clip->base.status))
  265.         goto error;
  266.  
  267.     pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  268.                               clip->pixman_image, NULL, dst->pixman_image,
  269.                               extents->bounded.x - clip_x, extents->bounded.y - clip_y,
  270.                               0,      0,
  271.                               extents->bounded.x, extents->bounded.y,
  272.                               extents->bounded.width, extents->bounded.height);
  273.     pixman_image_composite32 (PIXMAN_OP_ADD,
  274.                               tmp->pixman_image, clip->pixman_image, dst->pixman_image,
  275.                               0,  0,
  276.                               extents->bounded.x - clip_x, extents->bounded.y - clip_y,
  277.                               extents->bounded.x, extents->bounded.y,
  278.                               extents->bounded.width, extents->bounded.height);
  279.  
  280.     cairo_surface_destroy (&clip->base);
  281.  
  282.  error:
  283.     cairo_surface_destroy (&tmp->base);
  284.  
  285.     return status;
  286. }
  287.  
  288. /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
  289.  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
  290.  */
  291. static cairo_status_t
  292. clip_and_composite_source (const cairo_composite_rectangles_t   *extents,
  293.                            draw_func_t                           draw_func,
  294.                            void                                 *draw_closure)
  295. {
  296.     cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
  297.     cairo_image_surface_t *mask;
  298.     pixman_image_t *src;
  299.     int src_x, src_y;
  300.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  301.  
  302.     TRACE ((stderr, "%s\n", __FUNCTION__));
  303.  
  304.     mask = create_composite_mask (dst, draw_closure, draw_func, extents);
  305.     if (unlikely (mask->base.status))
  306.         return mask->base.status;
  307.  
  308.     pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  309.                               mask->pixman_image, NULL, dst->pixman_image,
  310.                               0,      0,
  311.                               0,      0,
  312.                               extents->bounded.x, extents->bounded.y,
  313.                               extents->bounded.width, extents->bounded.height);
  314.  
  315.     src = _pixman_image_for_pattern (dst,
  316.                                      &extents->source_pattern.base, FALSE,
  317.                                      &extents->bounded,
  318.                                      &extents->source_sample_area,
  319.                                      &src_x, &src_y);
  320.     if (unlikely (src == NULL)) {
  321.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  322.         goto error;
  323.     }
  324.  
  325.     pixman_image_composite32 (PIXMAN_OP_ADD,
  326.                               src, mask->pixman_image, dst->pixman_image,
  327.                               extents->bounded.x + src_x,  extents->bounded.y + src_y,
  328.                               0, 0,
  329.                               extents->bounded.x, extents->bounded.y,
  330.                               extents->bounded.width, extents->bounded.height);
  331.  
  332.     pixman_image_unref (src);
  333.  
  334. error:
  335.     cairo_surface_destroy (&mask->base);
  336.     return status;
  337. }
  338.  
  339. static cairo_status_t
  340. fixup_unbounded (const cairo_composite_rectangles_t *extents)
  341. {
  342.     cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
  343.     pixman_image_t *mask;
  344.     int mask_x, mask_y;
  345.  
  346.     TRACE ((stderr, "%s\n", __FUNCTION__));
  347.  
  348.     if (! _cairo_clip_is_region (extents->clip)) {
  349.         cairo_image_surface_t *clip;
  350.  
  351.         clip = (cairo_image_surface_t *)
  352.             _cairo_clip_get_surface (extents->clip, &dst->base,
  353.                                      &mask_x, &mask_y);
  354.         if (unlikely (clip->base.status))
  355.             return clip->base.status;
  356.  
  357.         mask = pixman_image_ref (clip->pixman_image);
  358.         cairo_surface_destroy (&clip->base);
  359.     } else {
  360.         mask_x = mask_y = 0;
  361.         mask = _pixman_image_for_color (CAIRO_COLOR_WHITE);
  362.         if (unlikely (mask == NULL))
  363.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  364.     }
  365.  
  366.     /* top */
  367.     if (extents->bounded.y != extents->unbounded.y) {
  368.         int x = extents->unbounded.x;
  369.         int y = extents->unbounded.y;
  370.         int width = extents->unbounded.width;
  371.         int height = extents->bounded.y - y;
  372.  
  373.         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  374.                                   mask, NULL, dst->pixman_image,
  375.                                   x - mask_x, y - mask_y,
  376.                                   0, 0,
  377.                                   x, y,
  378.                                   width, height);
  379.     }
  380.  
  381.     /* left */
  382.     if (extents->bounded.x != extents->unbounded.x) {
  383.         int x = extents->unbounded.x;
  384.         int y = extents->bounded.y;
  385.         int width = extents->bounded.x - x;
  386.         int height = extents->bounded.height;
  387.  
  388.         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  389.                                   mask, NULL, dst->pixman_image,
  390.                                   x - mask_x, y - mask_y,
  391.                                   0, 0,
  392.                                   x, y,
  393.                                   width, height);
  394.     }
  395.  
  396.     /* right */
  397.     if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
  398.         int x = extents->bounded.x + extents->bounded.width;
  399.         int y = extents->bounded.y;
  400.         int width = extents->unbounded.x + extents->unbounded.width - x;
  401.         int height = extents->bounded.height;
  402.  
  403.         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  404.                                   mask, NULL, dst->pixman_image,
  405.                                   x - mask_x, y - mask_y,
  406.                                   0, 0,
  407.                                   x, y,
  408.                                   width, height);
  409.     }
  410.  
  411.     /* bottom */
  412.     if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
  413.         int x = extents->unbounded.x;
  414.         int y = extents->bounded.y + extents->bounded.height;
  415.         int width = extents->unbounded.width;
  416.         int height = extents->unbounded.y + extents->unbounded.height - y;
  417.  
  418.         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
  419.                                   mask, NULL, dst->pixman_image,
  420.                                   x - mask_x, y - mask_y,
  421.                                   0, 0,
  422.                                   x, y,
  423.                                   width, height);
  424.     }
  425.  
  426.     pixman_image_unref (mask);
  427.  
  428.     return CAIRO_STATUS_SUCCESS;
  429. }
  430.  
  431. static cairo_int_status_t
  432. set_clip_region (cairo_composite_rectangles_t *extents)
  433. {
  434.     cairo_image_surface_t *dst = (cairo_image_surface_t *) extents->surface;
  435.     cairo_region_t *region = _cairo_clip_get_region (extents->clip);
  436.     pixman_region32_t *rgn = region ? &region->rgn : NULL;
  437.     if (! pixman_image_set_clip_region32 (dst->pixman_image, rgn))
  438.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  439.  
  440.     return CAIRO_STATUS_SUCCESS;
  441. }
  442.  
  443. static cairo_status_t
  444. clip_and_composite (cairo_composite_rectangles_t *extents,
  445.                     draw_func_t          draw_func,
  446.                     void                *draw_closure)
  447. {
  448.     cairo_status_t status;
  449.  
  450.     status = set_clip_region (extents);
  451.     if (unlikely (status))
  452.         return status;
  453.  
  454.     if (extents->op == CAIRO_OPERATOR_SOURCE) {
  455.         status = clip_and_composite_source (extents, draw_func, draw_closure);
  456.     } else {
  457.         if (extents->op == CAIRO_OPERATOR_CLEAR) {
  458.             extents->source_pattern.solid = _cairo_pattern_white;
  459.             extents->op = CAIRO_OPERATOR_DEST_OUT;
  460.         }
  461.         if (! _cairo_clip_is_region (extents->clip)) {
  462.             if (extents->is_bounded)
  463.                 status = clip_and_composite_with_mask (extents, draw_func, draw_closure);
  464.             else
  465.                 status = clip_and_composite_combine (extents, draw_func, draw_closure);
  466.         } else {
  467.             status = draw_func ((cairo_image_surface_t *) extents->surface,
  468.                                 draw_closure,
  469.                                 extents->op,
  470.                                 &extents->source_pattern.base,
  471.                                 0, 0,
  472.                                 &extents->bounded);
  473.         }
  474.     }
  475.  
  476.     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
  477.         status = fixup_unbounded (extents);
  478.  
  479.     return status;
  480. }
  481.  
  482. /* high-level compositor interface */
  483.  
  484. static cairo_int_status_t
  485. composite_paint (cairo_image_surface_t          *dst,
  486.                  void                           *closure,
  487.                  cairo_operator_t                op,
  488.                  const cairo_pattern_t          *pattern,
  489.                  int                             dst_x,
  490.                  int                             dst_y,
  491.                  const cairo_rectangle_int_t    *extents)
  492. {
  493.     cairo_rectangle_int_t sample;
  494.     pixman_image_t *src;
  495.     int src_x, src_y;
  496.  
  497.     TRACE ((stderr, "%s\n", __FUNCTION__));
  498.  
  499.     _cairo_pattern_sampled_area (pattern, extents, &sample);
  500.     src = _pixman_image_for_pattern (dst,
  501.                                      pattern, FALSE,
  502.                                      extents, &sample,
  503.                                      &src_x, &src_y);
  504.     if (unlikely (src == NULL))
  505.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  506.  
  507.     TRACE ((stderr, "%s: src=(%d, %d), dst=(%d, %d) size=%dx%d\n", __FUNCTION__,
  508.             extents->x + src_x, extents->y + src_y,
  509.             extents->x - dst_x, extents->y - dst_y,
  510.             extents->width, extents->height));
  511.  
  512.     pixman_image_composite32 (_pixman_operator (op),
  513.                               src, NULL, dst->pixman_image,
  514.                               extents->x + src_x, extents->y + src_y,
  515.                               0, 0,
  516.                               extents->x - dst_x, extents->y - dst_y,
  517.                               extents->width, extents->height);
  518.  
  519.     pixman_image_unref (src);
  520.  
  521.     return CAIRO_STATUS_SUCCESS;
  522. }
  523.  
  524. static cairo_int_status_t
  525. base_compositor_paint (const cairo_compositor_t *_compositor,
  526.                        cairo_composite_rectangles_t *extents)
  527. {
  528.     TRACE ((stderr, "%s\n", __FUNCTION__));
  529.     return clip_and_composite (extents, composite_paint, NULL);
  530. }
  531.  
  532. static cairo_int_status_t
  533. composite_mask (cairo_image_surface_t           *dst,
  534.                 void                            *closure,
  535.                 cairo_operator_t                 op,
  536.                 const cairo_pattern_t           *pattern,
  537.                 int                              dst_x,
  538.                 int                              dst_y,
  539.                 const cairo_rectangle_int_t      *extents)
  540. {
  541.     cairo_rectangle_int_t sample;
  542.     pixman_image_t *src, *mask;
  543.     int src_x, src_y;
  544.     int mask_x, mask_y;
  545.  
  546.     TRACE ((stderr, "%s\n", __FUNCTION__));
  547.  
  548.     _cairo_pattern_sampled_area (pattern, extents, &sample);
  549.     src = _pixman_image_for_pattern (dst, pattern, FALSE,
  550.                                      extents, &sample,
  551.                                      &src_x, &src_y);
  552.     if (unlikely (src == NULL))
  553.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  554.  
  555.     _cairo_pattern_sampled_area (closure, extents, &sample);
  556.     mask = _pixman_image_for_pattern (dst, closure, TRUE,
  557.                                       extents, &sample,
  558.                                       &mask_x, &mask_y);
  559.     if (unlikely (mask == NULL)) {
  560.         pixman_image_unref (src);
  561.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  562.     }
  563.  
  564.     pixman_image_composite32 (_pixman_operator (op),
  565.                               src, mask, dst->pixman_image,
  566.                               extents->x + src_x, extents->y + src_y,
  567.                               extents->x + mask_x, extents->y + mask_y,
  568.                               extents->x - dst_x, extents->y - dst_y,
  569.                               extents->width, extents->height);
  570.  
  571.     pixman_image_unref (mask);
  572.     pixman_image_unref (src);
  573.  
  574.     return CAIRO_STATUS_SUCCESS;
  575. }
  576.  
  577. static cairo_int_status_t
  578. base_compositor_mask (const cairo_compositor_t *_compositor,
  579.                       cairo_composite_rectangles_t *extents)
  580. {
  581.     TRACE ((stderr, "%s\n", __FUNCTION__));
  582.     return clip_and_composite (extents, composite_mask, &extents->mask_pattern.base);
  583. }
  584.  
  585. typedef struct {
  586.     cairo_traps_t traps;
  587.     cairo_antialias_t antialias;
  588. } composite_traps_info_t;
  589.  
  590. static cairo_int_status_t
  591. composite_traps (cairo_image_surface_t  *dst,
  592.                  void                   *closure,
  593.                  cairo_operator_t        op,
  594.                  const cairo_pattern_t  *pattern,
  595.                  int                     dst_x,
  596.                  int                     dst_y,
  597.                  const cairo_rectangle_int_t *extents)
  598. {
  599.     composite_traps_info_t *info = closure;
  600.     cairo_rectangle_int_t sample;
  601.     pixman_image_t *src, *mask;
  602.     int src_x, src_y;
  603.  
  604.     TRACE ((stderr, "%s\n", __FUNCTION__));
  605.  
  606.     _cairo_pattern_sampled_area (pattern, extents, &sample);
  607.     src = _pixman_image_for_pattern (dst, pattern, FALSE,
  608.                                      extents, &sample,
  609.                                      &src_x, &src_y);
  610.     if (unlikely (src == NULL))
  611.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  612.  
  613.     mask = pixman_image_create_bits (info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8,
  614.                                      extents->width, extents->height,
  615.                                      NULL, 0);
  616.     if (unlikely (mask == NULL)) {
  617.         pixman_image_unref (src);
  618.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  619.     }
  620.  
  621.     _pixman_image_add_traps (mask, extents->x, extents->y, &info->traps);
  622.     pixman_image_composite32 (_pixman_operator (op),
  623.                               src, mask, dst->pixman_image,
  624.                               extents->x + src_x - dst_x, extents->y + src_y - dst_y,
  625.                               0, 0,
  626.                               extents->x - dst_x, extents->y - dst_y,
  627.                               extents->width, extents->height);
  628.  
  629.     pixman_image_unref (mask);
  630.     pixman_image_unref (src);
  631.  
  632.     return  CAIRO_STATUS_SUCCESS;
  633. }
  634.  
  635. static cairo_int_status_t
  636. trim_extents_to_traps (cairo_composite_rectangles_t *extents,
  637.                        cairo_traps_t *traps)
  638. {
  639.     cairo_box_t box;
  640.  
  641.     /* X trims the affected area to the extents of the trapezoids, so
  642.      * we need to compensate when fixing up the unbounded area.
  643.     */
  644.     _cairo_traps_extents (traps, &box);
  645.     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
  646. }
  647.  
  648. static cairo_int_status_t
  649. base_compositor_stroke (const cairo_compositor_t *_compositor,
  650.                         cairo_composite_rectangles_t *extents,
  651.                         const cairo_path_fixed_t *path,
  652.                         const cairo_stroke_style_t *style,
  653.                         const cairo_matrix_t    *ctm,
  654.                         const cairo_matrix_t    *ctm_inverse,
  655.                         double                   tolerance,
  656.                         cairo_antialias_t        antialias)
  657. {
  658.     composite_traps_info_t info;
  659.     cairo_int_status_t status;
  660.  
  661.     TRACE ((stderr, "%s\n", __FUNCTION__));
  662.  
  663.     info.antialias = antialias;
  664.     _cairo_traps_init_with_clip (&info.traps, extents->clip);
  665.     status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
  666.                                                         ctm, ctm_inverse,
  667.                                                         tolerance,
  668.                                                         &info.traps);
  669.     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  670.         status = trim_extents_to_traps (extents, &info.traps);
  671.     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  672.         status = clip_and_composite (extents, composite_traps, &info);
  673.     _cairo_traps_fini (&info.traps);
  674.  
  675.     return status;
  676. }
  677.  
  678. static cairo_int_status_t
  679. base_compositor_fill (const cairo_compositor_t *_compositor,
  680.                       cairo_composite_rectangles_t *extents,
  681.                       const cairo_path_fixed_t  *path,
  682.                       cairo_fill_rule_t          fill_rule,
  683.                       double                     tolerance,
  684.                       cairo_antialias_t          antialias)
  685. {
  686.     composite_traps_info_t info;
  687.     cairo_int_status_t status;
  688.  
  689.     TRACE ((stderr, "%s\n", __FUNCTION__));
  690.  
  691.     info.antialias = antialias;
  692.     _cairo_traps_init_with_clip (&info.traps, extents->clip);
  693.     status = _cairo_path_fixed_fill_to_traps (path,
  694.                                               fill_rule, tolerance,
  695.                                               &info.traps);
  696.     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  697.         status = trim_extents_to_traps (extents, &info.traps);
  698.     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
  699.         status = clip_and_composite (extents, composite_traps, &info);
  700.     _cairo_traps_fini (&info.traps);
  701.  
  702.     return status;
  703. }
  704.  
  705. static cairo_int_status_t
  706. composite_glyphs (cairo_image_surface_t *dst,
  707.                   void                   *closure,
  708.                   cairo_operator_t       op,
  709.                   const cairo_pattern_t *pattern,
  710.                   int                    dst_x,
  711.                   int                    dst_y,
  712.                   const cairo_rectangle_int_t *extents)
  713. {
  714.     cairo_composite_glyphs_info_t *info = closure;
  715.     pixman_image_t *mask;
  716.     cairo_status_t status;
  717.     int i;
  718.  
  719.     TRACE ((stderr, "%s\n", __FUNCTION__));
  720.  
  721.     mask = pixman_image_create_bits (PIXMAN_a8,
  722.                                      extents->width, extents->height,
  723.                                      NULL, 0);
  724.     if (unlikely (mask == NULL))
  725.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  726.  
  727.     status = CAIRO_STATUS_SUCCESS;
  728.     _cairo_scaled_font_freeze_cache (info->font);
  729.     for (i = 0; i < info->num_glyphs; i++) {
  730.         cairo_image_surface_t *glyph_surface;
  731.         cairo_scaled_glyph_t *scaled_glyph;
  732.         unsigned long glyph_index = info->glyphs[i].index;
  733.         int x, y;
  734.  
  735.         status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
  736.                                              CAIRO_SCALED_GLYPH_INFO_SURFACE,
  737.                                              &scaled_glyph);
  738.  
  739.         if (unlikely (status))
  740.             break;
  741.  
  742.         glyph_surface = scaled_glyph->surface;
  743.         if (glyph_surface->width && glyph_surface->height) {
  744.             /* round glyph locations to the nearest pixel */
  745.             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
  746.             x = _cairo_lround (info->glyphs[i].x -
  747.                                glyph_surface->base.device_transform.x0);
  748.             y = _cairo_lround (info->glyphs[i].y -
  749.                                glyph_surface->base.device_transform.y0);
  750.  
  751.             pixman_image_composite32 (PIXMAN_OP_ADD,
  752.                                       glyph_surface->pixman_image, NULL, mask,
  753.                                       0, 0,
  754.                                       0, 0,
  755.                                       x - extents->x, y - extents->y,
  756.                                       glyph_surface->width,
  757.                                       glyph_surface->height);
  758.         }
  759.     }
  760.     _cairo_scaled_font_thaw_cache (info->font);
  761.  
  762.     if (status == CAIRO_STATUS_SUCCESS) {
  763.         cairo_rectangle_int_t sample;
  764.         pixman_image_t *src;
  765.         int src_x, src_y;
  766.  
  767.         _cairo_pattern_sampled_area (pattern, extents, &sample);
  768.         src = _pixman_image_for_pattern (dst, pattern, FALSE,
  769.                                          extents, &sample,
  770.                                          &src_x, &src_y);
  771.         if (src != NULL) {
  772.             dst_x = extents->x - dst_x;
  773.             dst_y = extents->y - dst_y;
  774.             pixman_image_composite32 (_pixman_operator (op),
  775.                                       src, mask, dst->pixman_image,
  776.                                       src_x + dst_x,  src_y + dst_y,
  777.                                       0, 0,
  778.                                       dst_x, dst_y,
  779.                                       extents->width, extents->height);
  780.             pixman_image_unref (src);
  781.         } else
  782.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  783.     }
  784.     pixman_image_unref (mask);
  785.  
  786.     return status;
  787. }
  788.  
  789. static cairo_int_status_t
  790. base_compositor_glyphs (const cairo_compositor_t        *_compositor,
  791.                         cairo_composite_rectangles_t    *extents,
  792.                         cairo_scaled_font_t             *scaled_font,
  793.                         cairo_glyph_t                   *glyphs,
  794.                         int                              num_glyphs,
  795.                         cairo_bool_t                     overlap)
  796. {
  797.     cairo_composite_glyphs_info_t info;
  798.  
  799.     info.font = scaled_font;
  800.     info.glyphs = glyphs;
  801.     info.num_glyphs = num_glyphs;
  802.  
  803.     TRACE ((stderr, "%s\n", __FUNCTION__));
  804.     return clip_and_composite (extents, composite_glyphs, &info);
  805. }
  806.  
  807. static const cairo_compositor_t base_compositor = {
  808.     &__cairo_no_compositor,
  809.  
  810.     base_compositor_paint,
  811.     base_compositor_mask,
  812.     base_compositor_stroke,
  813.     base_compositor_fill,
  814.     base_compositor_glyphs,
  815. };
  816.  
  817. cairo_surface_t *
  818. _cairo_test_base_compositor_surface_create (cairo_content_t     content,
  819.                                             int         width,
  820.                                             int         height)
  821. {
  822.     return test_compositor_surface_create (&base_compositor,
  823.                                            content, width, height);
  824. }
  825.