LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-image-surface.c (source / functions) Hit Total Coverage
Test: output.info Lines: 65 1888 3.4 %
Date: 2017-07-14 16:53:18 Functions: 10 98 10.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
       2             : /* cairo - a vector graphics library with display and print output
       3             :  *
       4             :  * Copyright © 2003 University of Southern California
       5             :  * Copyright © 2009,2010 Intel Corporation
       6             :  *
       7             :  * This library is free software; you can redistribute it and/or
       8             :  * modify it either under the terms of the GNU Lesser General Public
       9             :  * License version 2.1 as published by the Free Software Foundation
      10             :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      11             :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      12             :  * notice, a recipient may use your version of this file under either
      13             :  * the MPL or the LGPL.
      14             :  *
      15             :  * You should have received a copy of the LGPL along with this library
      16             :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      18             :  * You should have received a copy of the MPL along with this library
      19             :  * in the file COPYING-MPL-1.1
      20             :  *
      21             :  * The contents of this file are subject to the Mozilla Public License
      22             :  * Version 1.1 (the "License"); you may not use this file except in
      23             :  * compliance with the License. You may obtain a copy of the License at
      24             :  * http://www.mozilla.org/MPL/
      25             :  *
      26             :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      27             :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      28             :  * the specific language governing rights and limitations.
      29             :  *
      30             :  * The Original Code is the cairo graphics library.
      31             :  *
      32             :  * The Initial Developer of the Original Code is University of Southern
      33             :  * California.
      34             :  *
      35             :  * Contributor(s):
      36             :  *      Carl D. Worth <cworth@cworth.org>
      37             :  *      Chris Wilson <chris@chris-wilson.co.uk>
      38             :  */
      39             : 
      40             : #include "cairoint.h"
      41             : 
      42             : #include "cairo-boxes-private.h"
      43             : #include "cairo-clip-private.h"
      44             : #include "cairo-composite-rectangles-private.h"
      45             : #include "cairo-error-private.h"
      46             : #include "cairo-region-private.h"
      47             : #include "cairo-scaled-font-private.h"
      48             : #include "cairo-surface-snapshot-private.h"
      49             : #include "cairo-surface-subsurface-private.h"
      50             : 
      51             : /* Limit on the width / height of an image surface in pixels.  This is
      52             :  * mainly determined by coordinates of things sent to pixman at the
      53             :  * moment being in 16.16 format. */
      54             : #define MAX_IMAGE_SIZE 32767
      55             : #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
      56             : 
      57             : /**
      58             :  * SECTION:cairo-image
      59             :  * @Title: Image Surfaces
      60             :  * @Short_Description: Rendering to memory buffers
      61             :  * @See_Also: #cairo_surface_t
      62             :  *
      63             :  * Image surfaces provide the ability to render to memory buffers
      64             :  * either allocated by cairo or by the calling code.  The supported
      65             :  * image formats are those defined in #cairo_format_t.
      66             :  */
      67             : 
      68             : /**
      69             :  * CAIRO_HAS_IMAGE_SURFACE:
      70             :  *
      71             :  * Defined if the image surface backend is available.
      72             :  * The image surface backend is always built in.
      73             :  * This macro was added for completeness in cairo 1.8.
      74             :  *
      75             :  * @Since: 1.8
      76             :  */
      77             : 
      78             : static cairo_int_status_t
      79             : _cairo_image_surface_fill (void *dst,
      80             :                            cairo_operator_t              op,
      81             :                            const cairo_pattern_t        *source,
      82             :                            cairo_path_fixed_t   *path,
      83             :                            cairo_fill_rule_t             fill_rule,
      84             :                            double                        tolerance,
      85             :                            cairo_antialias_t             antialias,
      86             :                            cairo_clip_t         *clip);
      87             : 
      88             : static pixman_image_t *
      89             : _pixman_image_for_solid (const cairo_solid_pattern_t *pattern);
      90             : 
      91             : static cairo_bool_t
      92           6 : _cairo_image_surface_is_size_valid (int width, int height)
      93             : {
      94           6 :     return 0 <= width  &&  width <= MAX_IMAGE_SIZE &&
      95          12 :            0 <= height && height <= MAX_IMAGE_SIZE;
      96             : }
      97             : 
      98             : cairo_format_t
      99           3 : _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
     100             : {
     101           3 :     switch (pixman_format) {
     102             :     case PIXMAN_a8r8g8b8:
     103           3 :         return CAIRO_FORMAT_ARGB32;
     104             :     case PIXMAN_x8r8g8b8:
     105           0 :         return CAIRO_FORMAT_RGB24;
     106             :     case PIXMAN_a8:
     107           0 :         return CAIRO_FORMAT_A8;
     108             :     case PIXMAN_a1:
     109           0 :         return CAIRO_FORMAT_A1;
     110             :     case PIXMAN_r5g6b5:
     111           0 :         return CAIRO_FORMAT_RGB16_565;
     112             :     case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8:
     113             :     case PIXMAN_b8g8r8:   case PIXMAN_b5g6r5:
     114             :     case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5:
     115             :     case PIXMAN_x1b5g5r5: case PIXMAN_a4r4g4b4: case PIXMAN_x4r4g4b4:
     116             :     case PIXMAN_a4b4g4r4: case PIXMAN_x4b4g4r4: case PIXMAN_r3g3b2:
     117             :     case PIXMAN_b2g3r3:   case PIXMAN_a2r2g2b2: case PIXMAN_a2b2g2r2:
     118             :     case PIXMAN_c8:       case PIXMAN_g8:       case PIXMAN_x4a4:
     119             :     case PIXMAN_a4:       case PIXMAN_r1g2b1:   case PIXMAN_b1g2r1:
     120             :     case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4:
     121             :     case PIXMAN_g4:       case PIXMAN_g1:
     122             :     case PIXMAN_yuy2:     case PIXMAN_yv12:
     123             :     case PIXMAN_b8g8r8x8:
     124             :     case PIXMAN_b8g8r8a8:
     125             :     case PIXMAN_x2b10g10r10:
     126             :     case PIXMAN_a2b10g10r10:
     127             :     case PIXMAN_x2r10g10b10:
     128             :     case PIXMAN_a2r10g10b10:
     129             :     default:
     130           0 :         return CAIRO_FORMAT_INVALID;
     131             :     }
     132             : 
     133             :     return CAIRO_FORMAT_INVALID;
     134             : }
     135             : 
     136             : cairo_content_t
     137           3 : _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
     138             : {
     139             :     cairo_content_t content;
     140             : 
     141           3 :     content = 0;
     142           3 :     if (PIXMAN_FORMAT_RGB (pixman_format))
     143           3 :         content |= CAIRO_CONTENT_COLOR;
     144           3 :     if (PIXMAN_FORMAT_A (pixman_format))
     145           3 :         content |= CAIRO_CONTENT_ALPHA;
     146             : 
     147           3 :     return content;
     148             : }
     149             : 
     150             : cairo_surface_t *
     151           3 : _cairo_image_surface_create_for_pixman_image (pixman_image_t            *pixman_image,
     152             :                                               pixman_format_code_t       pixman_format)
     153             : {
     154             :     cairo_image_surface_t *surface;
     155           3 :     int width = pixman_image_get_width (pixman_image);
     156           3 :     int height = pixman_image_get_height (pixman_image);
     157             : 
     158           3 :     surface = malloc (sizeof (cairo_image_surface_t));
     159           3 :     if (unlikely (surface == NULL))
     160           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     161             : 
     162           3 :     _cairo_surface_init (&surface->base,
     163             :                          &_cairo_image_surface_backend,
     164             :                          NULL, /* device */
     165             :                          _cairo_content_from_pixman_format (pixman_format));
     166             : 
     167           3 :     surface->pixman_image = pixman_image;
     168             : 
     169           3 :     surface->pixman_format = pixman_format;
     170           3 :     surface->format = _cairo_format_from_pixman_format (pixman_format);
     171           3 :     surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
     172           3 :     surface->owns_data = FALSE;
     173           3 :     surface->transparency = CAIRO_IMAGE_UNKNOWN;
     174             : 
     175           3 :     surface->width = width;
     176           3 :     surface->height = height;
     177           3 :     surface->stride = pixman_image_get_stride (pixman_image);
     178           3 :     surface->depth = pixman_image_get_depth (pixman_image);
     179             : 
     180           3 :     return &surface->base;
     181             : }
     182             : 
     183             : cairo_bool_t
     184           0 : _pixman_format_from_masks (cairo_format_masks_t *masks,
     185             :                            pixman_format_code_t *format_ret)
     186             : {
     187             :     pixman_format_code_t format;
     188             :     int format_type;
     189             :     int a, r, g, b;
     190             :     cairo_format_masks_t format_masks;
     191             : 
     192           0 :     a = _cairo_popcount (masks->alpha_mask);
     193           0 :     r = _cairo_popcount (masks->red_mask);
     194           0 :     g = _cairo_popcount (masks->green_mask);
     195           0 :     b = _cairo_popcount (masks->blue_mask);
     196             : 
     197           0 :     if (masks->red_mask) {
     198           0 :         if (masks->red_mask > masks->blue_mask)
     199           0 :             format_type = PIXMAN_TYPE_ARGB;
     200             :         else
     201           0 :             format_type = PIXMAN_TYPE_ABGR;
     202           0 :     } else if (masks->alpha_mask) {
     203           0 :         format_type = PIXMAN_TYPE_A;
     204             :     } else {
     205           0 :         return FALSE;
     206             :     }
     207             : 
     208           0 :     format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b);
     209             : 
     210           0 :     if (! pixman_format_supported_destination (format))
     211           0 :         return FALSE;
     212             : 
     213             :     /* Sanity check that we got out of PIXMAN_FORMAT exactly what we
     214             :      * expected. This avoid any problems from something bizarre like
     215             :      * alpha in the least-significant bits, or insane channel order,
     216             :      * or whatever. */
     217           0 :      if (!_pixman_format_to_masks (format, &format_masks) ||
     218           0 :          masks->bpp        != format_masks.bpp            ||
     219           0 :          masks->red_mask   != format_masks.red_mask       ||
     220           0 :          masks->green_mask != format_masks.green_mask     ||
     221           0 :          masks->blue_mask  != format_masks.blue_mask)
     222             :      {
     223           0 :          return FALSE;
     224             :      }
     225             : 
     226           0 :     *format_ret = format;
     227           0 :     return TRUE;
     228             : }
     229             : 
     230             : /* A mask consisting of N bits set to 1. */
     231             : #define MASK(N) ((1UL << (N))-1)
     232             : 
     233             : cairo_bool_t
     234           0 : _pixman_format_to_masks (pixman_format_code_t    format,
     235             :                          cairo_format_masks_t   *masks)
     236             : {
     237             :     int a, r, g, b;
     238             : 
     239           0 :     masks->bpp = PIXMAN_FORMAT_BPP (format);
     240             : 
     241             :     /* Number of bits in each channel */
     242           0 :     a = PIXMAN_FORMAT_A (format);
     243           0 :     r = PIXMAN_FORMAT_R (format);
     244           0 :     g = PIXMAN_FORMAT_G (format);
     245           0 :     b = PIXMAN_FORMAT_B (format);
     246             : 
     247           0 :     switch (PIXMAN_FORMAT_TYPE (format)) {
     248             :     case PIXMAN_TYPE_ARGB:
     249           0 :         masks->alpha_mask = MASK (a) << (r + g + b);
     250           0 :         masks->red_mask   = MASK (r) << (g + b);
     251           0 :         masks->green_mask = MASK (g) << (b);
     252           0 :         masks->blue_mask  = MASK (b);
     253           0 :         return TRUE;
     254             :     case PIXMAN_TYPE_ABGR:
     255           0 :         masks->alpha_mask = MASK (a) << (b + g + r);
     256           0 :         masks->blue_mask  = MASK (b) << (g + r);
     257           0 :         masks->green_mask = MASK (g) << (r);
     258           0 :         masks->red_mask   = MASK (r);
     259           0 :         return TRUE;
     260             : #ifdef PIXMAN_TYPE_BGRA
     261             :     case PIXMAN_TYPE_BGRA:
     262           0 :         masks->blue_mask  = MASK (b) << (masks->bpp - b);
     263           0 :         masks->green_mask = MASK (g) << (masks->bpp - b - g);
     264           0 :         masks->red_mask   = MASK (r) << (masks->bpp - b - g - r);
     265           0 :         masks->alpha_mask = MASK (a);
     266           0 :         return TRUE;
     267             : #endif
     268             :     case PIXMAN_TYPE_A:
     269           0 :         masks->alpha_mask = MASK (a);
     270           0 :         masks->red_mask   = 0;
     271           0 :         masks->green_mask = 0;
     272           0 :         masks->blue_mask  = 0;
     273           0 :         return TRUE;
     274             :     case PIXMAN_TYPE_OTHER:
     275             :     case PIXMAN_TYPE_COLOR:
     276             :     case PIXMAN_TYPE_GRAY:
     277             :     case PIXMAN_TYPE_YUY2:
     278             :     case PIXMAN_TYPE_YV12:
     279             :     default:
     280           0 :         masks->alpha_mask = 0;
     281           0 :         masks->red_mask   = 0;
     282           0 :         masks->green_mask = 0;
     283           0 :         masks->blue_mask  = 0;
     284           0 :         return FALSE;
     285             :     }
     286             : }
     287             : 
     288             : pixman_format_code_t
     289           3 : _cairo_format_to_pixman_format_code (cairo_format_t format)
     290             : {
     291             :     pixman_format_code_t ret;
     292           3 :     switch (format) {
     293             :     case CAIRO_FORMAT_A1:
     294           0 :         ret = PIXMAN_a1;
     295           0 :         break;
     296             :     case CAIRO_FORMAT_A8:
     297           0 :         ret = PIXMAN_a8;
     298           0 :         break;
     299             :     case CAIRO_FORMAT_RGB24:
     300           0 :         ret = PIXMAN_x8r8g8b8;
     301           0 :         break;
     302             :     case CAIRO_FORMAT_RGB16_565:
     303           0 :         ret = PIXMAN_r5g6b5;
     304           0 :         break;
     305             :     case CAIRO_FORMAT_ARGB32:
     306             :     case CAIRO_FORMAT_INVALID:
     307             :     default:
     308           3 :         ret = PIXMAN_a8r8g8b8;
     309           3 :         break;
     310             :     }
     311           3 :     return ret;
     312             : }
     313             : 
     314             : cairo_surface_t *
     315           3 : _cairo_image_surface_create_with_pixman_format (unsigned char           *data,
     316             :                                                 pixman_format_code_t     pixman_format,
     317             :                                                 int                      width,
     318             :                                                 int                      height,
     319             :                                                 int                      stride)
     320             : {
     321             :     cairo_surface_t *surface;
     322             :     pixman_image_t *pixman_image;
     323             : 
     324           3 :     if (! _cairo_image_surface_is_size_valid (width, height))
     325             :     {
     326           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
     327             :     }
     328             : 
     329           3 :     pixman_image = pixman_image_create_bits (pixman_format, width, height,
     330             :                                              (uint32_t *) data, stride ? stride : 4);
     331             : 
     332           3 :     if (unlikely (pixman_image == NULL))
     333           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     334             : 
     335           3 :     surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
     336             :                                                             pixman_format);
     337           3 :     if (unlikely (surface->status)) {
     338           0 :         pixman_image_unref (pixman_image);
     339           0 :         return surface;
     340             :     }
     341             : 
     342             :     /* we can not make any assumptions about the initial state of user data */
     343           3 :     surface->is_clear = data == NULL;
     344           3 :     return surface;
     345             : }
     346             : 
     347             : /**
     348             :  * cairo_image_surface_create:
     349             :  * @format: format of pixels in the surface to create
     350             :  * @width: width of the surface, in pixels
     351             :  * @height: height of the surface, in pixels
     352             :  *
     353             :  * Creates an image surface of the specified format and
     354             :  * dimensions. Initially the surface contents are all
     355             :  * 0. (Specifically, within each pixel, each color or alpha channel
     356             :  * belonging to format will be 0. The contents of bits within a pixel,
     357             :  * but not belonging to the given format are undefined).
     358             :  *
     359             :  * Return value: a pointer to the newly created surface. The caller
     360             :  * owns the surface and should call cairo_surface_destroy() when done
     361             :  * with it.
     362             :  *
     363             :  * This function always returns a valid pointer, but it will return a
     364             :  * pointer to a "nil" surface if an error such as out of memory
     365             :  * occurs. You can use cairo_surface_status() to check for this.
     366             :  **/
     367             : cairo_surface_t *
     368           0 : cairo_image_surface_create (cairo_format_t      format,
     369             :                             int                 width,
     370             :                             int                 height)
     371             : {
     372             :     pixman_format_code_t pixman_format;
     373             : 
     374           0 :     if (! CAIRO_FORMAT_VALID (format))
     375           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
     376             : 
     377           0 :     pixman_format = _cairo_format_to_pixman_format_code (format);
     378             : 
     379           0 :     return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format,
     380             :                                                            width, height, -1);
     381             : }
     382             : slim_hidden_def (cairo_image_surface_create);
     383             : 
     384             : cairo_surface_t *
     385           0 : _cairo_image_surface_create_with_content (cairo_content_t       content,
     386             :                                           int                   width,
     387             :                                           int                   height)
     388             : {
     389           0 :     return cairo_image_surface_create (_cairo_format_from_content (content),
     390             :                                        width, height);
     391             : }
     392             : 
     393             : /**
     394             :  * cairo_format_stride_for_width:
     395             :  * @format: A #cairo_format_t value
     396             :  * @width: The desired width of an image surface to be created.
     397             :  *
     398             :  * This function provides a stride value that will respect all
     399             :  * alignment requirements of the accelerated image-rendering code
     400             :  * within cairo. Typical usage will be of the form:
     401             :  *
     402             :  * <informalexample><programlisting>
     403             :  * int stride;
     404             :  * unsigned char *data;
     405             :  * #cairo_surface_t *surface;
     406             :  *
     407             :  * stride = cairo_format_stride_for_width (format, width);
     408             :  * data = malloc (stride * height);
     409             :  * surface = cairo_image_surface_create_for_data (data, format,
     410             :  *                                                width, height,
     411             :  *                                                stride);
     412             :  * </programlisting></informalexample>
     413             :  *
     414             :  * Return value: the appropriate stride to use given the desired
     415             :  * format and width, or -1 if either the format is invalid or the width
     416             :  * too large.
     417             :  *
     418             :  * Since: 1.6
     419             :  **/
     420             : int
     421           3 : cairo_format_stride_for_width (cairo_format_t   format,
     422             :                                int              width)
     423             : {
     424             :     int bpp;
     425             : 
     426           3 :     if (! CAIRO_FORMAT_VALID (format)) {
     427           0 :         _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
     428           0 :         return -1;
     429             :     }
     430             : 
     431           3 :     bpp = _cairo_format_bits_per_pixel (format);
     432           3 :     if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp))
     433           0 :         return -1;
     434             : 
     435           3 :     return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp);
     436             : }
     437             : slim_hidden_def (cairo_format_stride_for_width);
     438             : 
     439             : /**
     440             :  * cairo_image_surface_create_for_data:
     441             :  * @data: a pointer to a buffer supplied by the application in which
     442             :  *     to write contents. This pointer must be suitably aligned for any
     443             :  *     kind of variable, (for example, a pointer returned by malloc).
     444             :  * @format: the format of pixels in the buffer
     445             :  * @width: the width of the image to be stored in the buffer
     446             :  * @height: the height of the image to be stored in the buffer
     447             :  * @stride: the number of bytes between the start of rows in the
     448             :  *     buffer as allocated. This value should always be computed by
     449             :  *     cairo_format_stride_for_width() before allocating the data
     450             :  *     buffer.
     451             :  *
     452             :  * Creates an image surface for the provided pixel data. The output
     453             :  * buffer must be kept around until the #cairo_surface_t is destroyed
     454             :  * or cairo_surface_finish() is called on the surface.  The initial
     455             :  * contents of @data will be used as the initial image contents; you
     456             :  * must explicitly clear the buffer, using, for example,
     457             :  * cairo_rectangle() and cairo_fill() if you want it cleared.
     458             :  *
     459             :  * Note that the stride may be larger than
     460             :  * width*bytes_per_pixel to provide proper alignment for each pixel
     461             :  * and row. This alignment is required to allow high-performance rendering
     462             :  * within cairo. The correct way to obtain a legal stride value is to
     463             :  * call cairo_format_stride_for_width() with the desired format and
     464             :  * maximum image width value, and then use the resulting stride value
     465             :  * to allocate the data and to create the image surface. See
     466             :  * cairo_format_stride_for_width() for example code.
     467             :  *
     468             :  * Return value: a pointer to the newly created surface. The caller
     469             :  * owns the surface and should call cairo_surface_destroy() when done
     470             :  * with it.
     471             :  *
     472             :  * This function always returns a valid pointer, but it will return a
     473             :  * pointer to a "nil" surface in the case of an error such as out of
     474             :  * memory or an invalid stride value. In case of invalid stride value
     475             :  * the error status of the returned surface will be
     476             :  * %CAIRO_STATUS_INVALID_STRIDE.  You can use
     477             :  * cairo_surface_status() to check for this.
     478             :  *
     479             :  * See cairo_surface_set_user_data() for a means of attaching a
     480             :  * destroy-notification fallback to the surface if necessary.
     481             :  **/
     482             : cairo_surface_t *
     483           3 : cairo_image_surface_create_for_data (unsigned char     *data,
     484             :                                      cairo_format_t     format,
     485             :                                      int                width,
     486             :                                      int                height,
     487             :                                      int                stride)
     488             : {
     489             :     pixman_format_code_t pixman_format;
     490             :     int minstride;
     491             : 
     492           3 :     if (! CAIRO_FORMAT_VALID (format))
     493           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
     494             : 
     495           3 :     if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0)
     496           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
     497             : 
     498           3 :     if (! _cairo_image_surface_is_size_valid (width, height))
     499           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
     500             : 
     501           3 :     minstride = cairo_format_stride_for_width (format, width);
     502           3 :     if (stride < 0) {
     503           0 :         if (stride > -minstride) {
     504           0 :             return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
     505             :         }
     506             :     } else {
     507           3 :         if (stride < minstride) {
     508           0 :             return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
     509             :         }
     510             :     }
     511             : 
     512           3 :     pixman_format = _cairo_format_to_pixman_format_code (format);
     513           3 :     return _cairo_image_surface_create_with_pixman_format (data,
     514             :                                                            pixman_format,
     515             :                                                            width, height,
     516             :                                                            stride);
     517             : }
     518             : slim_hidden_def (cairo_image_surface_create_for_data);
     519             : 
     520             : /**
     521             :  * cairo_image_surface_get_data:
     522             :  * @surface: a #cairo_image_surface_t
     523             :  *
     524             :  * Get a pointer to the data of the image surface, for direct
     525             :  * inspection or modification.
     526             :  *
     527             :  * Return value: a pointer to the image data of this surface or %NULL
     528             :  * if @surface is not an image surface, or if cairo_surface_finish()
     529             :  * has been called.
     530             :  *
     531             :  * Since: 1.2
     532             :  **/
     533             : unsigned char *
     534           0 : cairo_image_surface_get_data (cairo_surface_t *surface)
     535             : {
     536           0 :     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
     537             : 
     538           0 :     if (! _cairo_surface_is_image (surface)) {
     539           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
     540           0 :         return NULL;
     541             :     }
     542             : 
     543           0 :     return image_surface->data;
     544             : }
     545             : slim_hidden_def (cairo_image_surface_get_data);
     546             : 
     547             : /**
     548             :  * cairo_image_surface_get_format:
     549             :  * @surface: a #cairo_image_surface_t
     550             :  *
     551             :  * Get the format of the surface.
     552             :  *
     553             :  * Return value: the format of the surface
     554             :  *
     555             :  * Since: 1.2
     556             :  **/
     557             : cairo_format_t
     558           0 : cairo_image_surface_get_format (cairo_surface_t *surface)
     559             : {
     560           0 :     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
     561             : 
     562           0 :     if (! _cairo_surface_is_image (surface)) {
     563           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
     564           0 :         return CAIRO_FORMAT_INVALID;
     565             :     }
     566             : 
     567           0 :     return image_surface->format;
     568             : }
     569             : slim_hidden_def (cairo_image_surface_get_format);
     570             : 
     571             : /**
     572             :  * cairo_image_surface_get_width:
     573             :  * @surface: a #cairo_image_surface_t
     574             :  *
     575             :  * Get the width of the image surface in pixels.
     576             :  *
     577             :  * Return value: the width of the surface in pixels.
     578             :  **/
     579             : int
     580           0 : cairo_image_surface_get_width (cairo_surface_t *surface)
     581             : {
     582           0 :     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
     583             : 
     584           0 :     if (! _cairo_surface_is_image (surface)) {
     585           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
     586           0 :         return 0;
     587             :     }
     588             : 
     589           0 :     return image_surface->width;
     590             : }
     591             : slim_hidden_def (cairo_image_surface_get_width);
     592             : 
     593             : /**
     594             :  * cairo_image_surface_get_height:
     595             :  * @surface: a #cairo_image_surface_t
     596             :  *
     597             :  * Get the height of the image surface in pixels.
     598             :  *
     599             :  * Return value: the height of the surface in pixels.
     600             :  **/
     601             : int
     602           0 : cairo_image_surface_get_height (cairo_surface_t *surface)
     603             : {
     604           0 :     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
     605             : 
     606           0 :     if (! _cairo_surface_is_image (surface)) {
     607           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
     608           0 :         return 0;
     609             :     }
     610             : 
     611           0 :     return image_surface->height;
     612             : }
     613             : slim_hidden_def (cairo_image_surface_get_height);
     614             : 
     615             : /**
     616             :  * cairo_image_surface_get_stride:
     617             :  * @surface: a #cairo_image_surface_t
     618             :  *
     619             :  * Get the stride of the image surface in bytes
     620             :  *
     621             :  * Return value: the stride of the image surface in bytes (or 0 if
     622             :  * @surface is not an image surface). The stride is the distance in
     623             :  * bytes from the beginning of one row of the image data to the
     624             :  * beginning of the next row.
     625             :  *
     626             :  * Since: 1.2
     627             :  **/
     628             : int
     629           0 : cairo_image_surface_get_stride (cairo_surface_t *surface)
     630             : {
     631             : 
     632           0 :     cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
     633             : 
     634           0 :     if (! _cairo_surface_is_image (surface)) {
     635           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
     636           0 :         return 0;
     637             :     }
     638             : 
     639           0 :     return image_surface->stride;
     640             : }
     641             : slim_hidden_def (cairo_image_surface_get_stride);
     642             : 
     643             : cairo_format_t
     644           0 : _cairo_format_from_content (cairo_content_t content)
     645             : {
     646           0 :     switch (content) {
     647             :     case CAIRO_CONTENT_COLOR:
     648           0 :         return CAIRO_FORMAT_RGB24;
     649             :     case CAIRO_CONTENT_ALPHA:
     650           0 :         return CAIRO_FORMAT_A8;
     651             :     case CAIRO_CONTENT_COLOR_ALPHA:
     652           0 :         return CAIRO_FORMAT_ARGB32;
     653             :     }
     654             : 
     655           0 :     ASSERT_NOT_REACHED;
     656           0 :     return CAIRO_FORMAT_INVALID;
     657             : }
     658             : 
     659             : cairo_content_t
     660           0 : _cairo_content_from_format (cairo_format_t format)
     661             : {
     662           0 :     switch (format) {
     663             :     case CAIRO_FORMAT_ARGB32:
     664           0 :         return CAIRO_CONTENT_COLOR_ALPHA;
     665             :     case CAIRO_FORMAT_RGB24:
     666           0 :         return CAIRO_CONTENT_COLOR;
     667             :     case CAIRO_FORMAT_RGB16_565:
     668           0 :         return CAIRO_CONTENT_COLOR;
     669             :     case CAIRO_FORMAT_A8:
     670             :     case CAIRO_FORMAT_A1:
     671           0 :         return CAIRO_CONTENT_ALPHA;
     672             :     case CAIRO_FORMAT_INVALID:
     673           0 :         break;
     674             :     }
     675             : 
     676           0 :     ASSERT_NOT_REACHED;
     677           0 :     return CAIRO_CONTENT_COLOR_ALPHA;
     678             : }
     679             : 
     680             : int
     681           3 : _cairo_format_bits_per_pixel (cairo_format_t format)
     682             : {
     683           3 :     switch (format) {
     684             :     case CAIRO_FORMAT_ARGB32:
     685           3 :         return 32;
     686             :     case CAIRO_FORMAT_RGB24:
     687           0 :         return 32;
     688             :     case CAIRO_FORMAT_RGB16_565:
     689           0 :         return 16;
     690             :     case CAIRO_FORMAT_A8:
     691           0 :         return 8;
     692             :     case CAIRO_FORMAT_A1:
     693           0 :         return 1;
     694             :     case CAIRO_FORMAT_INVALID:
     695             :     default:
     696           0 :         ASSERT_NOT_REACHED;
     697           0 :         return 0;
     698             :     }
     699             : }
     700             : 
     701             : static cairo_surface_t *
     702           0 : _cairo_image_surface_create_similar (void              *abstract_other,
     703             :                                      cairo_content_t    content,
     704             :                                      int                width,
     705             :                                      int                height)
     706             : {
     707           0 :     cairo_image_surface_t *other = abstract_other;
     708             : 
     709           0 :     if (! _cairo_image_surface_is_size_valid (width, height))
     710           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
     711             : 
     712           0 :     if (content == other->base.content) {
     713           0 :         return _cairo_image_surface_create_with_pixman_format (NULL,
     714             :                                                                other->pixman_format,
     715             :                                                                width, height,
     716             :                                                                0);
     717             :     }
     718             : 
     719           0 :     return _cairo_image_surface_create_with_content (content,
     720             :                                                      width, height);
     721             : }
     722             : 
     723             : static cairo_status_t
     724           0 : _cairo_image_surface_finish (void *abstract_surface)
     725             : {
     726           0 :     cairo_image_surface_t *surface = abstract_surface;
     727             : 
     728           0 :     if (surface->pixman_image) {
     729           0 :         pixman_image_unref (surface->pixman_image);
     730           0 :         surface->pixman_image = NULL;
     731             :     }
     732             : 
     733           0 :     if (surface->owns_data) {
     734           0 :         free (surface->data);
     735           0 :         surface->data = NULL;
     736             :     }
     737             : 
     738           0 :     return CAIRO_STATUS_SUCCESS;
     739             : }
     740             : 
     741             : void
     742           0 : _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
     743             : {
     744           0 :     surface->owns_data = TRUE;
     745           0 : }
     746             : 
     747             : static cairo_status_t
     748           0 : _cairo_image_surface_acquire_source_image (void                    *abstract_surface,
     749             :                                            cairo_image_surface_t  **image_out,
     750             :                                            void                   **image_extra)
     751             : {
     752           0 :     *image_out = abstract_surface;
     753           0 :     *image_extra = NULL;
     754             : 
     755           0 :     return CAIRO_STATUS_SUCCESS;
     756             : }
     757             : 
     758             : static void
     759           0 : _cairo_image_surface_release_source_image (void                   *abstract_surface,
     760             :                                            cairo_image_surface_t  *image,
     761             :                                            void                   *image_extra)
     762             : {
     763           0 : }
     764             : 
     765             : /* XXX: I think we should fix pixman to match the names/order of the
     766             :  * cairo operators, but that will likely be better done at the same
     767             :  * time the X server is ported to pixman, (which will change a lot of
     768             :  * things in pixman I think).
     769             :  */
     770             : static pixman_op_t
     771           0 : _pixman_operator (cairo_operator_t op)
     772             : {
     773           0 :     switch (op) {
     774             :     case CAIRO_OPERATOR_CLEAR:
     775           0 :         return PIXMAN_OP_CLEAR;
     776             : 
     777             :     case CAIRO_OPERATOR_SOURCE:
     778           0 :         return PIXMAN_OP_SRC;
     779             :     case CAIRO_OPERATOR_OVER:
     780           0 :         return PIXMAN_OP_OVER;
     781             :     case CAIRO_OPERATOR_IN:
     782           0 :         return PIXMAN_OP_IN;
     783             :     case CAIRO_OPERATOR_OUT:
     784           0 :         return PIXMAN_OP_OUT;
     785             :     case CAIRO_OPERATOR_ATOP:
     786           0 :         return PIXMAN_OP_ATOP;
     787             : 
     788             :     case CAIRO_OPERATOR_DEST:
     789           0 :         return PIXMAN_OP_DST;
     790             :     case CAIRO_OPERATOR_DEST_OVER:
     791           0 :         return PIXMAN_OP_OVER_REVERSE;
     792             :     case CAIRO_OPERATOR_DEST_IN:
     793           0 :         return PIXMAN_OP_IN_REVERSE;
     794             :     case CAIRO_OPERATOR_DEST_OUT:
     795           0 :         return PIXMAN_OP_OUT_REVERSE;
     796             :     case CAIRO_OPERATOR_DEST_ATOP:
     797           0 :         return PIXMAN_OP_ATOP_REVERSE;
     798             : 
     799             :     case CAIRO_OPERATOR_XOR:
     800           0 :         return PIXMAN_OP_XOR;
     801             :     case CAIRO_OPERATOR_ADD:
     802           0 :         return PIXMAN_OP_ADD;
     803             :     case CAIRO_OPERATOR_SATURATE:
     804           0 :         return PIXMAN_OP_SATURATE;
     805             : 
     806             :     case CAIRO_OPERATOR_MULTIPLY:
     807           0 :         return PIXMAN_OP_MULTIPLY;
     808             :     case CAIRO_OPERATOR_SCREEN:
     809           0 :         return PIXMAN_OP_SCREEN;
     810             :     case CAIRO_OPERATOR_OVERLAY:
     811           0 :         return PIXMAN_OP_OVERLAY;
     812             :     case CAIRO_OPERATOR_DARKEN:
     813           0 :         return PIXMAN_OP_DARKEN;
     814             :     case CAIRO_OPERATOR_LIGHTEN:
     815           0 :         return PIXMAN_OP_LIGHTEN;
     816             :     case CAIRO_OPERATOR_COLOR_DODGE:
     817           0 :         return PIXMAN_OP_COLOR_DODGE;
     818             :     case CAIRO_OPERATOR_COLOR_BURN:
     819           0 :         return PIXMAN_OP_COLOR_BURN;
     820             :     case CAIRO_OPERATOR_HARD_LIGHT:
     821           0 :         return PIXMAN_OP_HARD_LIGHT;
     822             :     case CAIRO_OPERATOR_SOFT_LIGHT:
     823           0 :         return PIXMAN_OP_SOFT_LIGHT;
     824             :     case CAIRO_OPERATOR_DIFFERENCE:
     825           0 :         return PIXMAN_OP_DIFFERENCE;
     826             :     case CAIRO_OPERATOR_EXCLUSION:
     827           0 :         return PIXMAN_OP_EXCLUSION;
     828             :     case CAIRO_OPERATOR_HSL_HUE:
     829           0 :         return PIXMAN_OP_HSL_HUE;
     830             :     case CAIRO_OPERATOR_HSL_SATURATION:
     831           0 :         return PIXMAN_OP_HSL_SATURATION;
     832             :     case CAIRO_OPERATOR_HSL_COLOR:
     833           0 :         return PIXMAN_OP_HSL_COLOR;
     834             :     case CAIRO_OPERATOR_HSL_LUMINOSITY:
     835           0 :         return PIXMAN_OP_HSL_LUMINOSITY;
     836             : 
     837             :     default:
     838           0 :         ASSERT_NOT_REACHED;
     839           0 :         return PIXMAN_OP_OVER;
     840             :     }
     841             : }
     842             : 
     843             : static cairo_status_t
     844           0 : _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
     845             :                                       cairo_region_t *region)
     846             : {
     847           0 :     if (! pixman_image_set_clip_region32 (surface->pixman_image, &region->rgn))
     848           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     849             : 
     850           0 :     return CAIRO_STATUS_SUCCESS;
     851             : }
     852             : 
     853             : static void
     854           0 : _cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
     855             : {
     856           0 :     pixman_image_set_clip_region32 (surface->pixman_image, NULL);
     857           0 : }
     858             : 
     859             : static double
     860           0 : _pixman_nearest_sample (double d)
     861             : {
     862           0 :     return ceil (d - .5);
     863             : }
     864             : 
     865             : static cairo_bool_t
     866           0 : _nearest_sample (cairo_filter_t filter, double *tx, double *ty)
     867             : {
     868           0 :     if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
     869           0 :         *tx = _pixman_nearest_sample (*tx);
     870           0 :         *ty = _pixman_nearest_sample (*ty);
     871             :     } else {
     872           0 :         if (*tx != floor (*tx) || *ty != floor (*ty))
     873           0 :             return FALSE;
     874             :     }
     875           0 :     return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
     876             : }
     877             : 
     878             : #if PIXMAN_HAS_ATOMIC_OPS
     879             : static pixman_image_t *__pixman_transparent_image;
     880             : static pixman_image_t *__pixman_black_image;
     881             : static pixman_image_t *__pixman_white_image;
     882             : 
     883             : static pixman_image_t *
     884             : _pixman_transparent_image (void)
     885             : {
     886             :     pixman_image_t *image;
     887             : 
     888             :     image = __pixman_transparent_image;
     889             :     if (unlikely (image == NULL)) {
     890             :         pixman_color_t color;
     891             : 
     892             :         color.red   = 0x00;
     893             :         color.green = 0x00;
     894             :         color.blue  = 0x00;
     895             :         color.alpha = 0x00;
     896             : 
     897             :         image = pixman_image_create_solid_fill (&color);
     898             :         if (unlikely (image == NULL))
     899             :             return NULL;
     900             : 
     901             :         if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
     902             :                                        NULL, image))
     903             :         {
     904             :             pixman_image_ref (image);
     905             :         }
     906             :     } else {
     907             :         pixman_image_ref (image);
     908             :     }
     909             : 
     910             :     return image;
     911             : }
     912             : 
     913             : static pixman_image_t *
     914             : _pixman_black_image (void)
     915             : {
     916             :     pixman_image_t *image;
     917             : 
     918             :     image = __pixman_black_image;
     919             :     if (unlikely (image == NULL)) {
     920             :         pixman_color_t color;
     921             : 
     922             :         color.red   = 0x00;
     923             :         color.green = 0x00;
     924             :         color.blue  = 0x00;
     925             :         color.alpha = 0xffff;
     926             : 
     927             :         image = pixman_image_create_solid_fill (&color);
     928             :         if (unlikely (image == NULL))
     929             :             return NULL;
     930             : 
     931             :         if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
     932             :                                        NULL, image))
     933             :         {
     934             :             pixman_image_ref (image);
     935             :         }
     936             :     } else {
     937             :         pixman_image_ref (image);
     938             :     }
     939             : 
     940             :     return image;
     941             : }
     942             : 
     943             : static pixman_image_t *
     944             : _pixman_white_image (void)
     945             : {
     946             :     pixman_image_t *image;
     947             : 
     948             :     image = __pixman_white_image;
     949             :     if (unlikely (image == NULL)) {
     950             :         pixman_color_t color;
     951             : 
     952             :         color.red   = 0xffff;
     953             :         color.green = 0xffff;
     954             :         color.blue  = 0xffff;
     955             :         color.alpha = 0xffff;
     956             : 
     957             :         image = pixman_image_create_solid_fill (&color);
     958             :         if (unlikely (image == NULL))
     959             :             return NULL;
     960             : 
     961             :         if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
     962             :                                        NULL, image))
     963             :         {
     964             :             pixman_image_ref (image);
     965             :         }
     966             :     } else {
     967             :         pixman_image_ref (image);
     968             :     }
     969             : 
     970             :     return image;
     971             : }
     972             : 
     973             : static uint32_t
     974             : hars_petruska_f54_1_random (void)
     975             : {
     976             : #define rol(x,k) ((x << k) | (x >> (32-k)))
     977             :     static uint32_t x;
     978             :     return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
     979             : #undef rol
     980             : }
     981             : 
     982             : static struct {
     983             :     cairo_color_t color;
     984             :     pixman_image_t *image;
     985             : } cache[16];
     986             : static int n_cached;
     987             : 
     988             : #else  /* !PIXMAN_HAS_ATOMIC_OPS */
     989             : static pixman_image_t *
     990           0 : _pixman_transparent_image (void)
     991             : {
     992           0 :     return _pixman_image_for_solid (&_cairo_pattern_clear);
     993             : }
     994             : 
     995             : static pixman_image_t *
     996           0 : _pixman_black_image (void)
     997             : {
     998           0 :     return _pixman_image_for_solid (&_cairo_pattern_black);
     999             : }
    1000             : 
    1001             : static pixman_image_t *
    1002           0 : _pixman_white_image (void)
    1003             : {
    1004           0 :     return _pixman_image_for_solid (&_cairo_pattern_white);
    1005             : }
    1006             : #endif /* !PIXMAN_HAS_ATOMIC_OPS */
    1007             : 
    1008             : void
    1009           0 : _cairo_image_reset_static_data (void)
    1010             : {
    1011             : #if PIXMAN_HAS_ATOMIC_OPS
    1012             :     while (n_cached)
    1013             :         pixman_image_unref (cache[--n_cached].image);
    1014             : 
    1015             :     if (__pixman_transparent_image) {
    1016             :         pixman_image_unref (__pixman_transparent_image);
    1017             :         __pixman_transparent_image = NULL;
    1018             :     }
    1019             : 
    1020             :     if (__pixman_black_image) {
    1021             :         pixman_image_unref (__pixman_black_image);
    1022             :         __pixman_black_image = NULL;
    1023             :     }
    1024             : 
    1025             :     if (__pixman_white_image) {
    1026             :         pixman_image_unref (__pixman_white_image);
    1027             :         __pixman_white_image = NULL;
    1028             :     }
    1029             : #endif
    1030           0 : }
    1031             : 
    1032             : static pixman_image_t *
    1033           0 : _pixman_image_for_solid (const cairo_solid_pattern_t *pattern)
    1034             : {
    1035             :     pixman_color_t color;
    1036             :     pixman_image_t *image;
    1037             : 
    1038             : #if PIXMAN_HAS_ATOMIC_OPS
    1039             :     int i;
    1040             : 
    1041             :     if (pattern->color.alpha_short <= 0x00ff)
    1042             :         return _pixman_transparent_image ();
    1043             : 
    1044             :     if (pattern->color.alpha_short >= 0xff00) {
    1045             :         if (pattern->color.red_short <= 0x00ff &&
    1046             :             pattern->color.green_short <= 0x00ff &&
    1047             :             pattern->color.blue_short <= 0x00ff)
    1048             :         {
    1049             :             return _pixman_black_image ();
    1050             :         }
    1051             : 
    1052             :         if (pattern->color.red_short >= 0xff00 &&
    1053             :             pattern->color.green_short >= 0xff00 &&
    1054             :             pattern->color.blue_short >= 0xff00)
    1055             :         {
    1056             :             return _pixman_white_image ();
    1057             :         }
    1058             :     }
    1059             : 
    1060             :     CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
    1061             :     for (i = 0; i < n_cached; i++) {
    1062             :         if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
    1063             :             image = pixman_image_ref (cache[i].image);
    1064             :             goto UNLOCK;
    1065             :         }
    1066             :     }
    1067             : #endif
    1068             : 
    1069           0 :     color.red   = pattern->color.red_short;
    1070           0 :     color.green = pattern->color.green_short;
    1071           0 :     color.blue  = pattern->color.blue_short;
    1072           0 :     color.alpha = pattern->color.alpha_short;
    1073             : 
    1074           0 :     image = pixman_image_create_solid_fill (&color);
    1075             : #if PIXMAN_HAS_ATOMIC_OPS
    1076             :     if (image == NULL)
    1077             :         goto UNLOCK;
    1078             : 
    1079             :     if (n_cached < ARRAY_LENGTH (cache)) {
    1080             :         i = n_cached++;
    1081             :     } else {
    1082             :         i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
    1083             :         pixman_image_unref (cache[i].image);
    1084             :     }
    1085             :     cache[i].image = pixman_image_ref (image);
    1086             :     cache[i].color = pattern->color;
    1087             : 
    1088             : UNLOCK:
    1089             :     CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
    1090             : #endif
    1091           0 :     return image;
    1092             : }
    1093             : 
    1094             : static double
    1095           0 : clamp (double val, double min, double max)
    1096             : {
    1097           0 :     return val < min ? min : (val > max ? max : val);
    1098             : }
    1099             : 
    1100             : static pixman_image_t *
    1101           0 : _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
    1102             :                             const cairo_rectangle_int_t *extents,
    1103             :                             int *ix, int *iy)
    1104             : {
    1105             :     pixman_image_t        *pixman_image;
    1106             :     pixman_gradient_stop_t pixman_stops_static[2];
    1107           0 :     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
    1108           0 :     cairo_matrix_t matrix = pattern->base.matrix;
    1109             :     double tx, ty;
    1110             :     unsigned int i;
    1111             : 
    1112           0 :     if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
    1113           0 :         pixman_stops = _cairo_malloc_ab (pattern->n_stops,
    1114             :                                          sizeof(pixman_gradient_stop_t));
    1115           0 :         if (unlikely (pixman_stops == NULL))
    1116           0 :             return NULL;
    1117             :     }
    1118             : 
    1119           0 :     for (i = 0; i < pattern->n_stops; i++) {
    1120           0 :         pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
    1121           0 :         pixman_stops[i].color.red   = pattern->stops[i].color.red_short;
    1122           0 :         pixman_stops[i].color.green = pattern->stops[i].color.green_short;
    1123           0 :         pixman_stops[i].color.blue  = pattern->stops[i].color.blue_short;
    1124           0 :         pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
    1125             :     }
    1126             : 
    1127           0 :     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
    1128           0 :         cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
    1129             :         pixman_point_fixed_t p1, p2;
    1130             :         double x0, y0, x1, y1, maxabs;
    1131             : 
    1132             :         /*
    1133             :          * Transform the matrix to avoid overflow when converting between
    1134             :          * cairo_fixed_t and pixman_fixed_t (without incurring performance
    1135             :          * loss when the transformation is unnecessary).
    1136             :          *
    1137             :          * Having a function to compute the required transformation to
    1138             :          * "normalize" a given bounding box would be generally useful -
    1139             :          * cf linear patterns, gradient patterns, surface patterns...
    1140             :          */
    1141           0 :         x0 = _cairo_fixed_to_double (linear->p1.x);
    1142           0 :         y0 = _cairo_fixed_to_double (linear->p1.y);
    1143           0 :         x1 = _cairo_fixed_to_double (linear->p2.x);
    1144           0 :         y1 = _cairo_fixed_to_double (linear->p2.y);
    1145           0 :         cairo_matrix_transform_point (&matrix, &x0, &y0);
    1146           0 :         cairo_matrix_transform_point (&matrix, &x1, &y1);
    1147           0 :         maxabs = MAX (MAX (fabs (x0), fabs (x1)), MAX (fabs (y0), fabs (y1)));
    1148             : 
    1149           0 :         if (maxabs > PIXMAN_MAX_INT)
    1150             :         {
    1151             :             double sf;
    1152             :             cairo_matrix_t scale;
    1153             : 
    1154           0 :             sf = PIXMAN_MAX_INT / maxabs;
    1155             : 
    1156           0 :             p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
    1157           0 :             p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
    1158           0 :             p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
    1159           0 :             p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
    1160             : 
    1161             :             /* cairo_matrix_scale does a pre-scale, we want a post-scale */
    1162           0 :             cairo_matrix_init_scale (&scale, sf, sf);
    1163           0 :             cairo_matrix_multiply (&matrix, &matrix, &scale);
    1164             :         }
    1165             :         else
    1166             :         {
    1167           0 :             p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
    1168           0 :             p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
    1169           0 :             p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
    1170           0 :             p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
    1171             :         }
    1172             : 
    1173           0 :         pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
    1174             :                                                             pixman_stops,
    1175           0 :                                                             pattern->n_stops);
    1176             :     } else {
    1177           0 :         cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
    1178             :         pixman_point_fixed_t c1, c2;
    1179             :         pixman_fixed_t r1, r2;
    1180             : 
    1181           0 :         c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
    1182           0 :         c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
    1183           0 :         r1   = _cairo_fixed_to_16_16 (radial->r1);
    1184             : 
    1185           0 :         c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
    1186           0 :         c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
    1187           0 :         r2   = _cairo_fixed_to_16_16 (radial->r2);
    1188             : 
    1189           0 :         pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
    1190             :                                                             pixman_stops,
    1191           0 :                                                             pattern->n_stops);
    1192             :     }
    1193             : 
    1194           0 :     if (pixman_stops != pixman_stops_static)
    1195           0 :         free (pixman_stops);
    1196             : 
    1197           0 :     if (unlikely (pixman_image == NULL))
    1198           0 :         return NULL;
    1199             : 
    1200           0 :     tx = matrix.x0;
    1201           0 :     ty = matrix.y0;
    1202           0 :     if (! _cairo_matrix_is_translation (&matrix) ||
    1203           0 :         ! _nearest_sample (pattern->base.filter, &tx, &ty))
    1204             :     {
    1205             :         pixman_transform_t pixman_transform;
    1206             : 
    1207           0 :         if (tx != 0. || ty != 0.) {
    1208             :             cairo_matrix_t m, inv;
    1209             :             cairo_status_t status;
    1210             :             double x, y, max_x, max_y;
    1211             : 
    1212             :             /* Pixman also limits the [xy]_offset to 16 bits. We try to evenly
    1213             :              * spread the bits between the two, but we need to ensure that
    1214             :              * fabs (tx + extents->x + extents->width) < PIXMAN_MAX_INT &&
    1215             :              * fabs (ty + extents->y + extents->height) < PIXMAN_MAX_INT,
    1216             :              * otherwise the gradient won't render.
    1217             :              */
    1218           0 :             inv = matrix;
    1219           0 :             status = cairo_matrix_invert (&inv);
    1220           0 :             assert (status == CAIRO_STATUS_SUCCESS);
    1221             : 
    1222           0 :             x = _cairo_lround (inv.x0 / 2);
    1223           0 :             y = _cairo_lround (inv.y0 / 2);
    1224             : 
    1225           0 :             max_x = PIXMAN_MAX_INT - 1 - fabs (extents->x + extents->width);
    1226           0 :             x = clamp(x, -max_x, max_x);
    1227           0 :             max_y = PIXMAN_MAX_INT - 1 - fabs (extents->y + extents->height);
    1228           0 :             y = clamp(y, -max_y, max_y);
    1229             : 
    1230           0 :             tx = -x;
    1231           0 :             ty = -y;
    1232           0 :             cairo_matrix_init_translate (&inv, x, y);
    1233           0 :             cairo_matrix_multiply (&m, &inv, &matrix);
    1234           0 :             _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
    1235           0 :                                             extents->x + extents->width/2.,
    1236           0 :                                             extents->y + extents->height/2.);
    1237             :         } else {
    1238           0 :             tx = ty = 0;
    1239           0 :             _cairo_matrix_to_pixman_matrix (&pattern->base.matrix,
    1240             :                                             &pixman_transform,
    1241           0 :                                             extents->x + extents->width/2.,
    1242           0 :                                             extents->y + extents->height/2.);
    1243             :         }
    1244             : 
    1245           0 :         if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
    1246           0 :             pixman_image_unref (pixman_image);
    1247           0 :             return NULL;
    1248             :         }
    1249             :     }
    1250           0 :     *ix = tx;
    1251           0 :     *iy = ty;
    1252             : 
    1253             :     {
    1254             :         pixman_repeat_t pixman_repeat;
    1255             : 
    1256           0 :         switch (pattern->base.extend) {
    1257             :         default:
    1258             :         case CAIRO_EXTEND_NONE:
    1259           0 :             pixman_repeat = PIXMAN_REPEAT_NONE;
    1260           0 :             break;
    1261             :         case CAIRO_EXTEND_REPEAT:
    1262           0 :             pixman_repeat = PIXMAN_REPEAT_NORMAL;
    1263           0 :             break;
    1264             :         case CAIRO_EXTEND_REFLECT:
    1265           0 :             pixman_repeat = PIXMAN_REPEAT_REFLECT;
    1266           0 :             break;
    1267             :         case CAIRO_EXTEND_PAD:
    1268           0 :             pixman_repeat = PIXMAN_REPEAT_PAD;
    1269           0 :             break;
    1270             :         }
    1271             : 
    1272           0 :         pixman_image_set_repeat (pixman_image, pixman_repeat);
    1273             :     }
    1274             : 
    1275           0 :     return pixman_image;
    1276             : }
    1277             : 
    1278             : struct acquire_source_cleanup {
    1279             :     cairo_surface_t *surface;
    1280             :     cairo_image_surface_t *image;
    1281             :     void *image_extra;
    1282             : };
    1283             : 
    1284             : static void
    1285           0 : _acquire_source_cleanup (pixman_image_t *pixman_image,
    1286             :                          void *closure)
    1287             : {
    1288           0 :     struct acquire_source_cleanup *data = closure;
    1289             : 
    1290           0 :     _cairo_surface_release_source_image (data->surface,
    1291             :                                          data->image,
    1292             :                                          data->image_extra);
    1293           0 :     free (data);
    1294           0 : }
    1295             : 
    1296             : static cairo_filter_t
    1297           0 : sampled_area (const cairo_surface_pattern_t *pattern,
    1298             :               const cairo_rectangle_int_t *extents,
    1299             :               cairo_rectangle_int_t *sample)
    1300             : {
    1301             :     cairo_filter_t filter;
    1302             :     double x1, x2, y1, y2;
    1303             :     double pad;
    1304             : 
    1305           0 :     x1 = extents->x;
    1306           0 :     y1 = extents->y;
    1307           0 :     x2 = extents->x + (int) extents->width;
    1308           0 :     y2 = extents->y + (int) extents->height;
    1309             : 
    1310           0 :     _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
    1311             :                                           &x1, &y1, &x2, &y2,
    1312             :                                           NULL);
    1313             : 
    1314           0 :     filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
    1315           0 :     sample->x = floor (x1 - pad);
    1316           0 :     sample->y = floor (y1 - pad);
    1317           0 :     sample->width  = ceil (x2 + pad) - sample->x;
    1318           0 :     sample->height = ceil (y2 + pad) - sample->y;
    1319             : 
    1320           0 :     return filter;
    1321             : }
    1322             : 
    1323             : static uint16_t
    1324           0 : expand_channel (uint16_t v, uint32_t bits)
    1325             : {
    1326           0 :     int offset = 16 - bits;
    1327           0 :     while (offset > 0) {
    1328           0 :         v |= v >> bits;
    1329           0 :         offset -= bits;
    1330           0 :         bits += bits;
    1331             :     }
    1332           0 :     return v;
    1333             : }
    1334             : 
    1335             : static pixman_image_t *
    1336           0 : _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
    1337             : {
    1338             :     uint32_t pixel;
    1339             :     pixman_color_t color;
    1340             : 
    1341           0 :     switch (image->format) {
    1342             :     default:
    1343             :     case CAIRO_FORMAT_INVALID:
    1344           0 :         ASSERT_NOT_REACHED;
    1345           0 :         return NULL;
    1346             : 
    1347             :     case CAIRO_FORMAT_A1:
    1348           0 :         pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
    1349           0 :         return pixel & (1 << (x&7)) ? _pixman_white_image () : _pixman_transparent_image ();
    1350             : 
    1351             :     case CAIRO_FORMAT_A8:
    1352           0 :         color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
    1353           0 :         color.alpha |= color.alpha << 8;
    1354           0 :         if (color.alpha == 0)
    1355           0 :             return _pixman_transparent_image ();
    1356             : 
    1357           0 :         color.red = color.green = color.blue = 0;
    1358           0 :         return pixman_image_create_solid_fill (&color);
    1359             : 
    1360             :     case CAIRO_FORMAT_RGB16_565:
    1361           0 :         pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
    1362           0 :         if (pixel == 0)
    1363           0 :             return _pixman_black_image ();
    1364           0 :         if (pixel == 0xffff)
    1365           0 :             return _pixman_white_image ();
    1366             : 
    1367           0 :         color.alpha = 0xffff;
    1368           0 :         color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
    1369           0 :         color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
    1370           0 :         color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
    1371           0 :         return pixman_image_create_solid_fill (&color);
    1372             : 
    1373             :     case CAIRO_FORMAT_ARGB32:
    1374             :     case CAIRO_FORMAT_RGB24:
    1375           0 :         pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
    1376           0 :         color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
    1377           0 :         if (color.alpha == 0)
    1378           0 :             return _pixman_transparent_image ();
    1379           0 :         if (pixel == 0xffffffff)
    1380           0 :             return _pixman_white_image ();
    1381           0 :         if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
    1382           0 :             return _pixman_black_image ();
    1383             : 
    1384           0 :         color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
    1385           0 :         color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
    1386           0 :         color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
    1387           0 :         return pixman_image_create_solid_fill (&color);
    1388             :     }
    1389             : }
    1390             : 
    1391             : static pixman_image_t *
    1392           0 : _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
    1393             :                            cairo_bool_t is_mask,
    1394             :                            const cairo_rectangle_int_t *extents,
    1395             :                            int *ix, int *iy)
    1396             : {
    1397             :     pixman_image_t *pixman_image;
    1398             :     cairo_rectangle_int_t sample;
    1399             :     cairo_extend_t extend;
    1400             :     cairo_filter_t filter;
    1401             :     double tx, ty;
    1402             : 
    1403           0 :     tx = pattern->base.matrix.x0;
    1404           0 :     ty = pattern->base.matrix.y0;
    1405             : 
    1406           0 :     extend = pattern->base.extend;
    1407           0 :     filter = sampled_area (pattern, extents, &sample);
    1408             : 
    1409           0 :     pixman_image = NULL;
    1410           0 :     if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
    1411           0 :         (! is_mask || ! pattern->base.has_component_alpha ||
    1412           0 :          (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
    1413             :     {
    1414           0 :         cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
    1415             :         cairo_surface_type_t type;
    1416             : 
    1417           0 :         if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
    1418           0 :             source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
    1419             : 
    1420           0 :         type = source->base.backend->type;
    1421           0 :         if (type == CAIRO_SURFACE_TYPE_IMAGE) {
    1422           0 :             if (sample.width == 1 && sample.height == 1) {
    1423           0 :                 if (sample.x < 0 ||
    1424           0 :                     sample.y < 0 ||
    1425           0 :                     sample.x >= source->width ||
    1426           0 :                     sample.y >= source->height)
    1427             :                 {
    1428           0 :                     if (extend == CAIRO_EXTEND_NONE)
    1429           0 :                         return _pixman_transparent_image ();
    1430             :                 }
    1431             :                 else
    1432             :                 {
    1433           0 :                     return _pixel_to_solid (source, sample.x, sample.y);
    1434             :                 }
    1435             :             }
    1436             : 
    1437             : #if PIXMAN_HAS_ATOMIC_OPS
    1438             :             /* avoid allocating a 'pattern' image if we can reuse the original */
    1439             :             if (extend == CAIRO_EXTEND_NONE &&
    1440             :                 _cairo_matrix_is_translation (&pattern->base.matrix) &&
    1441             :                 _nearest_sample (filter, &tx, &ty))
    1442             :             {
    1443             :                 *ix = tx;
    1444             :                 *iy = ty;
    1445             :                 return pixman_image_ref (source->pixman_image);
    1446             :             }
    1447             : #endif
    1448             : 
    1449           0 :             pixman_image = pixman_image_create_bits (source->pixman_format,
    1450             :                                                      source->width,
    1451             :                                                      source->height,
    1452           0 :                                                      (uint32_t *) source->data,
    1453             :                                                      source->stride);
    1454           0 :             if (unlikely (pixman_image == NULL))
    1455           0 :                 return NULL;
    1456           0 :         } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
    1457             :             cairo_surface_subsurface_t *sub;
    1458           0 :             cairo_bool_t is_contained = FALSE;
    1459             : 
    1460           0 :             sub = (cairo_surface_subsurface_t *) source;
    1461           0 :             source = (cairo_image_surface_t *) sub->target;
    1462             : 
    1463           0 :             if (sample.x >= 0 &&
    1464           0 :                 sample.y >= 0 &&
    1465           0 :                 sample.x + sample.width  <= sub->extents.width &&
    1466           0 :                 sample.y + sample.height <= sub->extents.height)
    1467             :             {
    1468           0 :                 is_contained = TRUE;
    1469             :             }
    1470             : 
    1471           0 :             if (sample.width == 1 && sample.height == 1) {
    1472           0 :                 if (is_contained) {
    1473           0 :                     return _pixel_to_solid (source,
    1474           0 :                                             sub->extents.x + sample.x,
    1475           0 :                                             sub->extents.y + sample.y);
    1476             :                 } else {
    1477           0 :                     if (extend == CAIRO_EXTEND_NONE)
    1478           0 :                         return _pixman_transparent_image ();
    1479             :                 }
    1480             :             }
    1481             : 
    1482             : #if PIXMAN_HAS_ATOMIC_OPS
    1483             :             if (is_contained &&
    1484             :                 _cairo_matrix_is_translation (&pattern->base.matrix) &&
    1485             :                 _nearest_sample (filter, &tx, &ty))
    1486             :             {
    1487             :                 *ix = tx + sub->extents.x;
    1488             :                 *iy = ty + sub->extents.y;
    1489             :                 return pixman_image_ref (source->pixman_image);
    1490             :             }
    1491             : #endif
    1492             : 
    1493             :             /* Avoid sub-byte offsets, force a copy in that case. */
    1494           0 :             if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
    1495           0 :                 void *data = source->data
    1496           0 :                     + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
    1497           0 :                     + sub->extents.y * source->stride;
    1498           0 :                 pixman_image = pixman_image_create_bits (source->pixman_format,
    1499             :                                                          sub->extents.width,
    1500             :                                                          sub->extents.height,
    1501             :                                                          data,
    1502             :                                                          source->stride);
    1503           0 :                 if (unlikely (pixman_image == NULL))
    1504           0 :                     return NULL;
    1505             :             }
    1506             :         }
    1507             :     }
    1508             : 
    1509           0 :     if (pixman_image == NULL) {
    1510             :         struct acquire_source_cleanup *cleanup;
    1511             :         cairo_image_surface_t *image;
    1512             :         void *extra;
    1513             :         cairo_status_t status;
    1514             : 
    1515           0 :         status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
    1516           0 :         if (unlikely (status))
    1517           0 :             return NULL;
    1518             : 
    1519           0 :         if (sample.width == 1 && sample.height == 1) {
    1520           0 :             if (sample.x < 0 ||
    1521           0 :                 sample.y < 0 ||
    1522           0 :                 sample.x >= image->width ||
    1523           0 :                 sample.y >= image->height)
    1524             :             {
    1525           0 :                 if (extend == CAIRO_EXTEND_NONE) {
    1526           0 :                     pixman_image = _pixman_transparent_image ();
    1527           0 :                     _cairo_surface_release_source_image (pattern->surface, image, extra);
    1528           0 :                     return pixman_image;
    1529             :                 }
    1530             :             }
    1531             :             else
    1532             :             {
    1533           0 :                 pixman_image = _pixel_to_solid (image, sample.x, sample.y);
    1534           0 :                 _cairo_surface_release_source_image (pattern->surface, image, extra);
    1535           0 :                 return pixman_image;
    1536             :             }
    1537             :         }
    1538             : 
    1539           0 :         pixman_image = pixman_image_create_bits (image->pixman_format,
    1540           0 :                                                  image->width,
    1541           0 :                                                  image->height,
    1542           0 :                                                  (uint32_t *) image->data,
    1543           0 :                                                  image->stride);
    1544           0 :         if (unlikely (pixman_image == NULL)) {
    1545           0 :             _cairo_surface_release_source_image (pattern->surface, image, extra);
    1546           0 :             return NULL;
    1547             :         }
    1548             : 
    1549           0 :         cleanup = malloc (sizeof (*cleanup));
    1550           0 :         if (unlikely (cleanup == NULL)) {
    1551           0 :             _cairo_surface_release_source_image (pattern->surface, image, extra);
    1552           0 :             pixman_image_unref (pixman_image);
    1553           0 :             return NULL;
    1554             :         }
    1555             : 
    1556           0 :         cleanup->surface = pattern->surface;
    1557           0 :         cleanup->image = image;
    1558           0 :         cleanup->image_extra = extra;
    1559           0 :         pixman_image_set_destroy_function (pixman_image,
    1560             :                                            _acquire_source_cleanup, cleanup);
    1561             :     }
    1562             : 
    1563           0 :     if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
    1564           0 :         ! _nearest_sample (filter, &tx, &ty))
    1565             :     {
    1566             :         pixman_transform_t pixman_transform;
    1567             :         cairo_matrix_t m;
    1568             : 
    1569           0 :         m = pattern->base.matrix;
    1570           0 :         if (m.x0 != 0. || m.y0 != 0.) {
    1571             :             cairo_matrix_t inv;
    1572             :             cairo_status_t status;
    1573             :             double x, y;
    1574             : 
    1575             :             /* pixman also limits the [xy]_offset to 16 bits so evenly
    1576             :              * spread the bits between the two.
    1577             :              */
    1578           0 :             inv = m;
    1579           0 :             status = cairo_matrix_invert (&inv);
    1580           0 :             assert (status == CAIRO_STATUS_SUCCESS);
    1581             : 
    1582           0 :             x = floor (inv.x0 / 2);
    1583           0 :             y = floor (inv.y0 / 2);
    1584           0 :             tx = -x;
    1585           0 :             ty = -y;
    1586           0 :             cairo_matrix_init_translate (&inv, x, y);
    1587           0 :             cairo_matrix_multiply (&m, &inv, &m);
    1588             :         } else {
    1589           0 :             tx = ty = 0;
    1590             :         }
    1591             : 
    1592           0 :         _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
    1593           0 :                                         extents->x + extents->width/2.,
    1594           0 :                                         extents->y + extents->height/2.);
    1595           0 :         if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
    1596           0 :             pixman_image_unref (pixman_image);
    1597           0 :             return NULL;
    1598             :         }
    1599             :     }
    1600           0 :     *ix = tx;
    1601           0 :     *iy = ty;
    1602             : 
    1603           0 :     if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
    1604           0 :         tx == pattern->base.matrix.x0 &&
    1605           0 :         ty == pattern->base.matrix.y0)
    1606             :     {
    1607           0 :         pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
    1608             :     }
    1609             :     else
    1610             :     {
    1611             :         pixman_filter_t pixman_filter;
    1612             : 
    1613           0 :         switch (filter) {
    1614             :         case CAIRO_FILTER_FAST:
    1615           0 :             pixman_filter = PIXMAN_FILTER_FAST;
    1616           0 :             break;
    1617             :         case CAIRO_FILTER_GOOD:
    1618           0 :             pixman_filter = PIXMAN_FILTER_GOOD;
    1619           0 :             break;
    1620             :         case CAIRO_FILTER_BEST:
    1621           0 :             pixman_filter = PIXMAN_FILTER_BEST;
    1622           0 :             break;
    1623             :         case CAIRO_FILTER_NEAREST:
    1624           0 :             pixman_filter = PIXMAN_FILTER_NEAREST;
    1625           0 :             break;
    1626             :         case CAIRO_FILTER_BILINEAR:
    1627           0 :             pixman_filter = PIXMAN_FILTER_BILINEAR;
    1628           0 :             break;
    1629             :         case CAIRO_FILTER_GAUSSIAN:
    1630             :             /* XXX: The GAUSSIAN value has no implementation in cairo
    1631             :              * whatsoever, so it was really a mistake to have it in the
    1632             :              * API. We could fix this by officially deprecating it, or
    1633             :              * else inventing semantics and providing an actual
    1634             :              * implementation for it. */
    1635             :         default:
    1636           0 :             pixman_filter = PIXMAN_FILTER_BEST;
    1637             :         }
    1638             : 
    1639           0 :         pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
    1640             :     }
    1641             : 
    1642             :     {
    1643             :         pixman_repeat_t pixman_repeat;
    1644             : 
    1645           0 :         switch (extend) {
    1646             :         default:
    1647             :         case CAIRO_EXTEND_NONE:
    1648           0 :             pixman_repeat = PIXMAN_REPEAT_NONE;
    1649           0 :             break;
    1650             :         case CAIRO_EXTEND_REPEAT:
    1651           0 :             pixman_repeat = PIXMAN_REPEAT_NORMAL;
    1652           0 :             break;
    1653             :         case CAIRO_EXTEND_REFLECT:
    1654           0 :             pixman_repeat = PIXMAN_REPEAT_REFLECT;
    1655           0 :             break;
    1656             :         case CAIRO_EXTEND_PAD:
    1657           0 :             pixman_repeat = PIXMAN_REPEAT_PAD;
    1658           0 :             break;
    1659             :         }
    1660             : 
    1661           0 :         pixman_image_set_repeat (pixman_image, pixman_repeat);
    1662             :     }
    1663             : 
    1664           0 :     if (pattern->base.has_component_alpha)
    1665           0 :         pixman_image_set_component_alpha (pixman_image, TRUE);
    1666             : 
    1667           0 :     return pixman_image;
    1668             : }
    1669             : 
    1670             : static pixman_image_t *
    1671           0 : _pixman_image_for_pattern (const cairo_pattern_t *pattern,
    1672             :                            cairo_bool_t is_mask,
    1673             :                            const cairo_rectangle_int_t *extents,
    1674             :                            int *tx, int *ty)
    1675             : {
    1676           0 :     *tx = *ty = 0;
    1677             : 
    1678           0 :     if (pattern == NULL)
    1679           0 :         return _pixman_white_image ();
    1680             : 
    1681           0 :     switch (pattern->type) {
    1682             :     default:
    1683           0 :         ASSERT_NOT_REACHED;
    1684             :     case CAIRO_PATTERN_TYPE_SOLID:
    1685           0 :         return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
    1686             : 
    1687             :     case CAIRO_PATTERN_TYPE_RADIAL:
    1688             :     case CAIRO_PATTERN_TYPE_LINEAR:
    1689           0 :         return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
    1690             :                                            extents, tx, ty);
    1691             : 
    1692             :     case CAIRO_PATTERN_TYPE_SURFACE:
    1693           0 :         return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern,
    1694             :                                           is_mask, extents, tx, ty);
    1695             :     }
    1696             : }
    1697             : 
    1698             : static cairo_status_t
    1699           0 : _cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
    1700             :                                       const cairo_composite_rectangles_t *rects,
    1701             :                                       cairo_clip_t *clip)
    1702             : {
    1703           0 :     pixman_image_t *mask = NULL;
    1704             :     pixman_box32_t boxes[4];
    1705           0 :     int i, mask_x = 0, mask_y = 0, n_boxes = 0;
    1706             : 
    1707           0 :     if (clip != NULL) {
    1708             :         cairo_surface_t *clip_surface;
    1709             :         int clip_x, clip_y;
    1710             : 
    1711           0 :         clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
    1712           0 :         if (unlikely (clip_surface->status))
    1713           0 :             return clip_surface->status;
    1714             : 
    1715           0 :         mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
    1716           0 :         mask_x = -clip_x;
    1717           0 :         mask_y = -clip_y;
    1718             :     } else {
    1719           0 :         if (rects->bounded.width  == rects->unbounded.width &&
    1720           0 :             rects->bounded.height == rects->unbounded.height)
    1721             :         {
    1722           0 :             return CAIRO_STATUS_SUCCESS;
    1723             :         }
    1724             :     }
    1725             : 
    1726             :     /* wholly unbounded? */
    1727           0 :     if (rects->bounded.width == 0 || rects->bounded.height == 0) {
    1728           0 :         int x = rects->unbounded.x;
    1729           0 :         int y = rects->unbounded.y;
    1730           0 :         int width = rects->unbounded.width;
    1731           0 :         int height = rects->unbounded.height;
    1732             : 
    1733           0 :         if (mask != NULL) {
    1734           0 :             pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
    1735             :                                       mask, NULL, dst->pixman_image,
    1736             :                                       x + mask_x, y + mask_y,
    1737             :                                       0, 0,
    1738             :                                       x, y,
    1739             :                                       width, height);
    1740             :         } else {
    1741           0 :             pixman_color_t color = { 0, };
    1742           0 :             pixman_box32_t box = { x, y, x + width, y + height };
    1743             : 
    1744           0 :             if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
    1745             :                                            dst->pixman_image,
    1746             :                                            &color,
    1747             :                                            1, &box))
    1748           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1749             :         }
    1750             : 
    1751           0 :         return CAIRO_STATUS_SUCCESS;
    1752             :     }
    1753             : 
    1754             :     /* top */
    1755           0 :     if (rects->bounded.y != rects->unbounded.y) {
    1756           0 :         boxes[n_boxes].x1 = rects->unbounded.x;
    1757           0 :         boxes[n_boxes].y1 = rects->unbounded.y;
    1758           0 :         boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
    1759           0 :         boxes[n_boxes].y2 = rects->bounded.y;
    1760           0 :         n_boxes++;
    1761             :     }
    1762             : 
    1763             :     /* left */
    1764           0 :     if (rects->bounded.x != rects->unbounded.x) {
    1765           0 :         boxes[n_boxes].x1 = rects->unbounded.x;
    1766           0 :         boxes[n_boxes].y1 = rects->bounded.y;
    1767           0 :         boxes[n_boxes].x2 = rects->bounded.x;
    1768           0 :         boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
    1769           0 :         n_boxes++;
    1770             :     }
    1771             : 
    1772             :     /* right */
    1773           0 :     if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
    1774           0 :         boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width;
    1775           0 :         boxes[n_boxes].y1 = rects->bounded.y;
    1776           0 :         boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
    1777           0 :         boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
    1778           0 :         n_boxes++;
    1779             :     }
    1780             : 
    1781             :     /* bottom */
    1782           0 :     if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
    1783           0 :         boxes[n_boxes].x1 = rects->unbounded.x;
    1784           0 :         boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height;
    1785           0 :         boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
    1786           0 :         boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height;
    1787           0 :         n_boxes++;
    1788             :     }
    1789             : 
    1790           0 :     if (mask != NULL) {
    1791           0 :         for (i = 0; i < n_boxes; i++) {
    1792           0 :             pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
    1793             :                                       mask, NULL, dst->pixman_image,
    1794           0 :                                       boxes[i].x1 + mask_x, boxes[i].y1 + mask_y,
    1795             :                                       0, 0,
    1796             :                                       boxes[i].x1, boxes[i].y1,
    1797           0 :                                       boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1);
    1798             :         }
    1799             :     } else {
    1800           0 :         pixman_color_t color = { 0, };
    1801             : 
    1802           0 :         if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
    1803             :                                        dst->pixman_image,
    1804             :                                        &color,
    1805             :                                        n_boxes,
    1806             :                                        boxes))
    1807             :         {
    1808           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1809             :         }
    1810             :     }
    1811             : 
    1812           0 :     return CAIRO_STATUS_SUCCESS;
    1813             : }
    1814             : 
    1815             : static cairo_status_t
    1816           0 : _cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst,
    1817             :                                             const cairo_composite_rectangles_t *extents,
    1818             :                                             cairo_region_t *clip_region,
    1819             :                                             cairo_boxes_t *boxes)
    1820             : {
    1821             :     cairo_boxes_t clear;
    1822             :     cairo_box_t box;
    1823             :     cairo_status_t status;
    1824             :     struct _cairo_boxes_chunk *chunk;
    1825             :     int i;
    1826             : 
    1827             :     // If we have no boxes then we need to clear the entire extents
    1828             :     // because we have nothing to draw.
    1829           0 :     if (boxes->num_boxes < 1 && clip_region == NULL) {
    1830           0 :         int x = extents->unbounded.x;
    1831           0 :         int y = extents->unbounded.y;
    1832           0 :         int width = extents->unbounded.width;
    1833           0 :         int height = extents->unbounded.height;
    1834             : 
    1835           0 :         pixman_color_t color = { 0 };
    1836           0 :         pixman_box32_t box = { x, y, x + width, y + height };
    1837             : 
    1838           0 :         if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
    1839             :                                        dst->pixman_image,
    1840             :                                        &color,
    1841             :                                        1, &box)) {
    1842           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1843             :         }
    1844           0 :         return CAIRO_STATUS_SUCCESS;
    1845             :     }
    1846             : 
    1847           0 :     _cairo_boxes_init (&clear);
    1848             : 
    1849           0 :     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
    1850           0 :     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
    1851           0 :     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
    1852           0 :     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
    1853             : 
    1854           0 :     if (clip_region == NULL) {
    1855             :         cairo_boxes_t tmp;
    1856             : 
    1857           0 :         _cairo_boxes_init (&tmp);
    1858             : 
    1859           0 :         status = _cairo_boxes_add (&tmp, &box);
    1860           0 :         assert (status == CAIRO_STATUS_SUCCESS);
    1861             : 
    1862           0 :         tmp.chunks.next = &boxes->chunks;
    1863           0 :         tmp.num_boxes += boxes->num_boxes;
    1864             : 
    1865           0 :         status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
    1866             :                                                           CAIRO_FILL_RULE_WINDING,
    1867             :                                                           &clear);
    1868             : 
    1869           0 :         tmp.chunks.next = NULL;
    1870             :     } else {
    1871             :         pixman_box32_t *pbox;
    1872             : 
    1873           0 :         pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
    1874           0 :         _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
    1875             : 
    1876           0 :         status = _cairo_boxes_add (&clear, &box);
    1877           0 :         assert (status == CAIRO_STATUS_SUCCESS);
    1878             : 
    1879           0 :         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
    1880           0 :             for (i = 0; i < chunk->count; i++) {
    1881           0 :                 status = _cairo_boxes_add (&clear, &chunk->base[i]);
    1882           0 :                 if (unlikely (status)) {
    1883           0 :                     _cairo_boxes_fini (&clear);
    1884           0 :                     return status;
    1885             :                 }
    1886             :             }
    1887             :         }
    1888             : 
    1889           0 :         status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
    1890             :                                                           CAIRO_FILL_RULE_WINDING,
    1891             :                                                           &clear);
    1892             :     }
    1893             : 
    1894           0 :     if (likely (status == CAIRO_STATUS_SUCCESS)) {
    1895           0 :         for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
    1896           0 :             for (i = 0; i < chunk->count; i++) {
    1897           0 :                 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
    1898           0 :                 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
    1899           0 :                 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
    1900           0 :                 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
    1901             : 
    1902           0 :                 x1 = (x1 < 0 ? 0 : x1);
    1903           0 :                 y1 = (y1 < 0 ? 0 : y1);
    1904           0 :                 if (x2 <= x1 || y2 <= y1)
    1905           0 :                     continue;
    1906           0 :                 pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
    1907           0 :                              PIXMAN_FORMAT_BPP (dst->pixman_format),
    1908             :                              x1, y1, x2 - x1, y2 - y1,
    1909             :                              0);
    1910             :             }
    1911             :         }
    1912             :     }
    1913             : 
    1914           0 :     _cairo_boxes_fini (&clear);
    1915             : 
    1916           0 :     return status;
    1917             : }
    1918             : 
    1919             : static cairo_bool_t
    1920           0 : can_reduce_alpha_op (cairo_operator_t op)
    1921             : {
    1922           0 :     int iop = op;
    1923           0 :     switch (iop) {
    1924             :     case CAIRO_OPERATOR_OVER:
    1925             :     case CAIRO_OPERATOR_SOURCE:
    1926             :     case CAIRO_OPERATOR_ADD:
    1927           0 :         return TRUE;
    1928             :     default:
    1929           0 :         return FALSE;
    1930             :     }
    1931             : }
    1932             : 
    1933             : static cairo_bool_t
    1934           0 : reduce_alpha_op (cairo_image_surface_t *dst,
    1935             :                  cairo_operator_t op,
    1936             :                  const cairo_pattern_t *pattern)
    1937             : {
    1938           0 :     return dst->base.is_clear &&
    1939           0 :            dst->base.content == CAIRO_CONTENT_ALPHA &&
    1940           0 :            _cairo_pattern_is_opaque_solid (pattern) &&
    1941           0 :            can_reduce_alpha_op (op);
    1942             : }
    1943             : 
    1944             : /* low level compositor */
    1945             : typedef cairo_status_t
    1946             : (*image_draw_func_t) (void                              *closure,
    1947             :                       pixman_image_t                    *dst,
    1948             :                       pixman_format_code_t               dst_format,
    1949             :                       cairo_operator_t                   op,
    1950             :                       const cairo_pattern_t             *src,
    1951             :                       int                                dst_x,
    1952             :                       int                                dst_y,
    1953             :                       const cairo_rectangle_int_t       *extents,
    1954             :                       cairo_region_t                    *clip_region);
    1955             : 
    1956             : static pixman_image_t *
    1957           0 : _create_composite_mask_pattern (cairo_clip_t                  *clip,
    1958             :                                 image_draw_func_t              draw_func,
    1959             :                                 void                          *draw_closure,
    1960             :                                 cairo_image_surface_t         *dst,
    1961             :                                 const cairo_rectangle_int_t   *extents)
    1962             : {
    1963           0 :     cairo_region_t *clip_region = NULL;
    1964             :     pixman_image_t *mask;
    1965             :     cairo_status_t status;
    1966           0 :     cairo_bool_t need_clip_surface = FALSE;
    1967             : 
    1968           0 :     if (clip != NULL) {
    1969           0 :         status = _cairo_clip_get_region (clip, &clip_region);
    1970           0 :         assert (! _cairo_status_is_error (status));
    1971             : 
    1972             :         /* The all-clipped state should never propagate this far. */
    1973           0 :         assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
    1974             : 
    1975           0 :         need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
    1976             : 
    1977           0 :         if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
    1978           0 :             clip_region = NULL;
    1979             :     }
    1980             : 
    1981           0 :     mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height,
    1982             :                                      NULL, 0);
    1983           0 :     if (unlikely (mask == NULL))
    1984           0 :         return NULL;
    1985             : 
    1986             :     /* Is it worth setting the clip region here? */
    1987           0 :     if (clip_region != NULL) {
    1988             :         pixman_bool_t ret;
    1989             : 
    1990           0 :         pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y);
    1991           0 :         ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
    1992           0 :         pixman_region32_translate (&clip_region->rgn, extents->x, extents->y);
    1993             : 
    1994           0 :         if (! ret) {
    1995           0 :             pixman_image_unref (mask);
    1996           0 :             return NULL;
    1997             :         }
    1998             :     }
    1999             : 
    2000           0 :     status = draw_func (draw_closure,
    2001             :                         mask, PIXMAN_a8,
    2002             :                         CAIRO_OPERATOR_ADD, NULL,
    2003             :                         extents->x, extents->y,
    2004             :                         extents, NULL);
    2005           0 :     if (unlikely (status)) {
    2006           0 :         pixman_image_unref (mask);
    2007           0 :         return NULL;
    2008             :     }
    2009             : 
    2010           0 :     if (need_clip_surface) {
    2011             :         cairo_surface_t *tmp;
    2012             : 
    2013           0 :         tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
    2014           0 :         if (unlikely (tmp->status)) {
    2015           0 :             pixman_image_unref (mask);
    2016           0 :             return NULL;
    2017             :         }
    2018             : 
    2019           0 :         pixman_image_ref (mask);
    2020             : 
    2021           0 :         status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y);
    2022           0 :         cairo_surface_destroy (tmp);
    2023           0 :         if (unlikely (status)) {
    2024           0 :             pixman_image_unref (mask);
    2025           0 :             return NULL;
    2026             :         }
    2027             :     }
    2028             : 
    2029           0 :     if (clip_region != NULL)
    2030           0 :         pixman_image_set_clip_region (mask, NULL);
    2031             : 
    2032           0 :     return mask;
    2033             : }
    2034             : 
    2035             : /* Handles compositing with a clip surface when the operator allows
    2036             :  * us to combine the clip with the mask
    2037             :  */
    2038             : static cairo_status_t
    2039           0 : _clip_and_composite_with_mask (cairo_clip_t                  *clip,
    2040             :                                cairo_operator_t               op,
    2041             :                                const cairo_pattern_t         *pattern,
    2042             :                                image_draw_func_t              draw_func,
    2043             :                                void                          *draw_closure,
    2044             :                                cairo_image_surface_t         *dst,
    2045             :                                const cairo_rectangle_int_t   *extents)
    2046             : {
    2047             :     pixman_image_t *mask;
    2048             : 
    2049           0 :     mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
    2050           0 :     if (unlikely (mask == NULL))
    2051           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2052             : 
    2053           0 :     if (pattern == NULL) {
    2054           0 :         if (dst->pixman_format == PIXMAN_a8) {
    2055           0 :             pixman_image_composite32 (_pixman_operator (op),
    2056             :                                       mask, NULL, dst->pixman_image,
    2057             :                                       0, 0, 0, 0,
    2058             :                                       extents->x,      extents->y,
    2059             :                                       extents->width,  extents->height);
    2060             :         } else {
    2061             :             pixman_image_t *src;
    2062             : 
    2063           0 :             src = _pixman_white_image ();
    2064           0 :             if (unlikely (src == NULL)) {
    2065           0 :                 pixman_image_unref (mask);
    2066           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2067             :             }
    2068             : 
    2069           0 :             pixman_image_composite32 (_pixman_operator (op),
    2070             :                                       src, mask, dst->pixman_image,
    2071             :                                       0, 0, 0, 0,
    2072             :                                       extents->x,      extents->y,
    2073             :                                       extents->width,  extents->height);
    2074           0 :             pixman_image_unref (src);
    2075             :         }
    2076             :     } else {
    2077             :         pixman_image_t *src;
    2078             :         int src_x, src_y;
    2079             : 
    2080           0 :         src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
    2081           0 :         if (unlikely (src == NULL)) {
    2082           0 :             pixman_image_unref (mask);
    2083           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2084             :         }
    2085             : 
    2086           0 :         pixman_image_composite32 (_pixman_operator (op),
    2087             :                                   src, mask, dst->pixman_image,
    2088           0 :                                   extents->x + src_x,  extents->y + src_y,
    2089             :                                   0, 0,
    2090             :                                   extents->x,          extents->y,
    2091             :                                   extents->width,      extents->height);
    2092           0 :         pixman_image_unref (src);
    2093             :     }
    2094             : 
    2095           0 :     pixman_image_unref (mask);
    2096             : 
    2097           0 :     return CAIRO_STATUS_SUCCESS;
    2098             : }
    2099             : 
    2100             : /* Handles compositing with a clip surface when we have to do the operation
    2101             :  * in two pieces and combine them together.
    2102             :  */
    2103             : static cairo_status_t
    2104           0 : _clip_and_composite_combine (cairo_clip_t                  *clip,
    2105             :                              cairo_operator_t               op,
    2106             :                              const cairo_pattern_t         *src,
    2107             :                              image_draw_func_t              draw_func,
    2108             :                              void                          *draw_closure,
    2109             :                              cairo_image_surface_t               *dst,
    2110             :                              const cairo_rectangle_int_t   *extents)
    2111             : {
    2112             :     pixman_image_t *tmp;
    2113             :     cairo_surface_t *clip_surface;
    2114             :     int clip_x, clip_y;
    2115             :     cairo_status_t status;
    2116             : 
    2117           0 :     tmp  = pixman_image_create_bits (dst->pixman_format,
    2118             :                                      extents->width, extents->height,
    2119             :                                      NULL, 0);
    2120           0 :     if (unlikely (tmp == NULL))
    2121           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2122             : 
    2123           0 :     if (src == NULL) {
    2124           0 :         status = (*draw_func) (draw_closure,
    2125             :                                tmp, dst->pixman_format,
    2126             :                                CAIRO_OPERATOR_ADD, NULL,
    2127             :                                extents->x, extents->y,
    2128             :                                extents, NULL);
    2129             :     } else {
    2130             :         /* Initialize the temporary surface from the destination surface */
    2131           0 :         if (! dst->base.is_clear) {
    2132           0 :             pixman_image_composite32 (PIXMAN_OP_SRC,
    2133             :                                       dst->pixman_image, NULL, tmp,
    2134             :                                       extents->x, extents->y,
    2135             :                                       0, 0,
    2136             :                                       0, 0,
    2137             :                                       extents->width, extents->height);
    2138             :         }
    2139             : 
    2140           0 :         status = (*draw_func) (draw_closure,
    2141             :                                tmp, dst->pixman_format,
    2142             :                                op, src,
    2143             :                                extents->x, extents->y,
    2144             :                                extents, NULL);
    2145             :     }
    2146           0 :     if (unlikely (status))
    2147           0 :         goto CLEANUP_SURFACE;
    2148             : 
    2149           0 :     assert (clip->path != NULL);
    2150           0 :     clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
    2151           0 :     if (unlikely (clip_surface->status))
    2152           0 :         goto CLEANUP_SURFACE;
    2153             : 
    2154           0 :     if (! dst->base.is_clear) {
    2155             : #if PIXMAN_HAS_OP_LERP
    2156             :         pixman_image_composite32 (PIXMAN_OP_LERP,
    2157             :                                   tmp,
    2158             :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
    2159             :                                   dst->pixman_image,
    2160             :                                   0, 0,
    2161             :                                   extents->x - clip_x,
    2162             :                                   extents->y - clip_y,
    2163             :                                   extents->x, extents->y,
    2164             :                                   extents->width, extents->height);
    2165             : #else
    2166             :         /* Punch the clip out of the destination */
    2167           0 :         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
    2168             :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
    2169             :                                   NULL, dst->pixman_image,
    2170           0 :                                   extents->x - clip_x,
    2171           0 :                                   extents->y - clip_y,
    2172             :                                   0, 0,
    2173             :                                   extents->x, extents->y,
    2174             :                                   extents->width, extents->height);
    2175             : 
    2176             :         /* Now add the two results together */
    2177           0 :         pixman_image_composite32 (PIXMAN_OP_ADD,
    2178             :                                   tmp,
    2179             :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
    2180             :                                   dst->pixman_image,
    2181             :                                   0, 0,
    2182           0 :                                   extents->x - clip_x,
    2183           0 :                                   extents->y - clip_y,
    2184             :                                   extents->x, extents->y,
    2185             :                                   extents->width, extents->height);
    2186             : #endif
    2187             :     } else {
    2188           0 :         pixman_image_composite32 (PIXMAN_OP_SRC,
    2189             :                                   tmp,
    2190             :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
    2191             :                                   dst->pixman_image,
    2192             :                                   0, 0,
    2193           0 :                                   extents->x - clip_x,
    2194           0 :                                   extents->y - clip_y,
    2195             :                                   extents->x, extents->y,
    2196             :                                   extents->width, extents->height);
    2197             :     }
    2198             : 
    2199             :  CLEANUP_SURFACE:
    2200           0 :     pixman_image_unref (tmp);
    2201             : 
    2202           0 :     return status;
    2203             : }
    2204             : 
    2205             : /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
    2206             :  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
    2207             :  */
    2208             : static cairo_status_t
    2209           0 : _clip_and_composite_source (cairo_clip_t                  *clip,
    2210             :                             const cairo_pattern_t         *pattern,
    2211             :                             image_draw_func_t              draw_func,
    2212             :                             void                          *draw_closure,
    2213             :                             cairo_image_surface_t         *dst,
    2214             :                             const cairo_rectangle_int_t   *extents)
    2215             : {
    2216             :     pixman_image_t *mask, *src;
    2217             :     int src_x, src_y;
    2218             : 
    2219           0 :     if (pattern == NULL) {
    2220             :         cairo_region_t *clip_region;
    2221             :         cairo_status_t status;
    2222             : 
    2223           0 :         status = draw_func (draw_closure,
    2224             :                             dst->pixman_image, dst->pixman_format,
    2225             :                             CAIRO_OPERATOR_SOURCE, NULL,
    2226             :                             extents->x, extents->y,
    2227             :                             extents, NULL);
    2228           0 :         if (unlikely (status))
    2229           0 :             return status;
    2230             : 
    2231           0 :         if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED)
    2232           0 :             status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0);
    2233             : 
    2234           0 :         return status;
    2235             :     }
    2236             : 
    2237             :     /* Create a surface that is mask IN clip */
    2238           0 :     mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
    2239           0 :     if (unlikely (mask == NULL))
    2240           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2241             : 
    2242           0 :     src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
    2243           0 :     if (unlikely (src == NULL)) {
    2244           0 :         pixman_image_unref (mask);
    2245           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2246             :     }
    2247             : 
    2248           0 :     if (! dst->base.is_clear) {
    2249             : #if PIXMAN_HAS_OP_LERP
    2250             :         pixman_image_composite32 (PIXMAN_OP_LERP,
    2251             :                                   src, mask, dst->pixman_image,
    2252             :                                   extents->x + src_x, extents->y + src_y,
    2253             :                                   0, 0,
    2254             :                                   extents->x,     extents->y,
    2255             :                                   extents->width, extents->height);
    2256             : #else
    2257             :         /* Compute dest' = dest OUT (mask IN clip) */
    2258           0 :         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
    2259             :                                   mask, NULL, dst->pixman_image,
    2260             :                                   0, 0, 0, 0,
    2261             :                                   extents->x,     extents->y,
    2262             :                                   extents->width, extents->height);
    2263             : 
    2264             :         /* Now compute (src IN (mask IN clip)) ADD dest' */
    2265           0 :         pixman_image_composite32 (PIXMAN_OP_ADD,
    2266             :                                   src, mask, dst->pixman_image,
    2267           0 :                                   extents->x + src_x, extents->y + src_y,
    2268             :                                   0, 0,
    2269             :                                   extents->x,     extents->y,
    2270             :                                   extents->width, extents->height);
    2271             : #endif
    2272             :     } else {
    2273           0 :         pixman_image_composite32 (PIXMAN_OP_SRC,
    2274             :                                   src, mask, dst->pixman_image,
    2275           0 :                                   extents->x + src_x, extents->y + src_y,
    2276             :                                   0, 0,
    2277             :                                   extents->x,     extents->y,
    2278             :                                   extents->width, extents->height);
    2279             :     }
    2280             : 
    2281           0 :     pixman_image_unref (src);
    2282           0 :     pixman_image_unref (mask);
    2283             : 
    2284           0 :     return CAIRO_STATUS_SUCCESS;
    2285             : }
    2286             : 
    2287             : static cairo_status_t
    2288           0 : _clip_and_composite (cairo_image_surface_t      *dst,
    2289             :                      cairo_operator_t            op,
    2290             :                      const cairo_pattern_t      *src,
    2291             :                      image_draw_func_t           draw_func,
    2292             :                      void                       *draw_closure,
    2293             :                      cairo_composite_rectangles_t*extents,
    2294             :                      cairo_clip_t               *clip)
    2295             : {
    2296             :     cairo_status_t status;
    2297           0 :     cairo_region_t *clip_region = NULL;
    2298           0 :     cairo_bool_t need_clip_surface = FALSE;
    2299             : 
    2300           0 :     if (clip != NULL) {
    2301           0 :         status = _cairo_clip_get_region (clip, &clip_region);
    2302           0 :         if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
    2303           0 :             return CAIRO_STATUS_SUCCESS;
    2304           0 :         if (unlikely (_cairo_status_is_error (status)))
    2305           0 :             return status;
    2306             : 
    2307           0 :         need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
    2308             : 
    2309           0 :         if (clip_region != NULL) {
    2310             :             cairo_rectangle_int_t rect;
    2311             :             cairo_bool_t is_empty;
    2312             : 
    2313           0 :             cairo_region_get_extents (clip_region, &rect);
    2314           0 :             is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect);
    2315           0 :             if (unlikely (is_empty))
    2316           0 :                 return CAIRO_STATUS_SUCCESS;
    2317             : 
    2318           0 :             is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect);
    2319           0 :             if (unlikely (is_empty && extents->is_bounded))
    2320           0 :                 return CAIRO_STATUS_SUCCESS;
    2321             : 
    2322           0 :             if (cairo_region_num_rectangles (clip_region) == 1)
    2323           0 :                 clip_region = NULL;
    2324             :         }
    2325             :     }
    2326             : 
    2327           0 :     if (clip_region != NULL) {
    2328           0 :         status = _cairo_image_surface_set_clip_region (dst, clip_region);
    2329           0 :         if (unlikely (status))
    2330           0 :             return status;
    2331             :     }
    2332             : 
    2333           0 :     if (reduce_alpha_op (dst, op, src)) {
    2334           0 :         op = CAIRO_OPERATOR_ADD;
    2335           0 :         src = NULL;
    2336             :     }
    2337             : 
    2338           0 :     if (op == CAIRO_OPERATOR_SOURCE) {
    2339           0 :         status = _clip_and_composite_source (clip, src,
    2340             :                                              draw_func, draw_closure,
    2341           0 :                                              dst, &extents->bounded);
    2342             :     } else {
    2343           0 :         if (op == CAIRO_OPERATOR_CLEAR) {
    2344           0 :             src = NULL;
    2345           0 :             op = CAIRO_OPERATOR_DEST_OUT;
    2346             :         }
    2347             : 
    2348           0 :         if (need_clip_surface) {
    2349           0 :             if (extents->is_bounded) {
    2350           0 :                 status = _clip_and_composite_with_mask (clip, op, src,
    2351             :                                                         draw_func, draw_closure,
    2352           0 :                                                         dst, &extents->bounded);
    2353             :             } else {
    2354           0 :                 status = _clip_and_composite_combine (clip, op, src,
    2355             :                                                       draw_func, draw_closure,
    2356           0 :                                                       dst, &extents->bounded);
    2357             :             }
    2358             :         } else {
    2359           0 :             status = draw_func (draw_closure,
    2360             :                                 dst->pixman_image, dst->pixman_format,
    2361             :                                 op, src,
    2362             :                                 0, 0,
    2363           0 :                                 &extents->bounded,
    2364             :                                 clip_region);
    2365             :         }
    2366             :     }
    2367             : 
    2368           0 :     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
    2369           0 :         status = _cairo_image_surface_fixup_unbounded (dst, extents,
    2370             :                                                        need_clip_surface ? clip : NULL);
    2371             :     }
    2372             : 
    2373           0 :     if (clip_region != NULL)
    2374           0 :         _cairo_image_surface_unset_clip_region (dst);
    2375             : 
    2376           0 :     return status;
    2377             : }
    2378             : 
    2379             : #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
    2380             : #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
    2381             : 
    2382             : static cairo_bool_t
    2383           0 : _line_exceeds_16_16 (const cairo_line_t *line)
    2384             : {
    2385             :     return
    2386           0 :         line->p1.x <= CAIRO_FIXED_16_16_MIN ||
    2387           0 :         line->p1.x >= CAIRO_FIXED_16_16_MAX ||
    2388             : 
    2389           0 :         line->p2.x <= CAIRO_FIXED_16_16_MIN ||
    2390           0 :         line->p2.x >= CAIRO_FIXED_16_16_MAX ||
    2391             : 
    2392           0 :         line->p1.y <= CAIRO_FIXED_16_16_MIN ||
    2393           0 :         line->p1.y >= CAIRO_FIXED_16_16_MAX ||
    2394             : 
    2395           0 :         line->p2.y <= CAIRO_FIXED_16_16_MIN ||
    2396           0 :         line->p2.y >= CAIRO_FIXED_16_16_MAX;
    2397             : }
    2398             : 
    2399             : static void
    2400           0 : _project_line_x_onto_16_16 (const cairo_line_t *line,
    2401             :                             cairo_fixed_t top,
    2402             :                             cairo_fixed_t bottom,
    2403             :                             pixman_line_fixed_t *out)
    2404             : {
    2405             :     cairo_point_double_t p1, p2;
    2406             :     double m;
    2407             : 
    2408           0 :     p1.x = _cairo_fixed_to_double (line->p1.x);
    2409           0 :     p1.y = _cairo_fixed_to_double (line->p1.y);
    2410             : 
    2411           0 :     p2.x = _cairo_fixed_to_double (line->p2.x);
    2412           0 :     p2.y = _cairo_fixed_to_double (line->p2.y);
    2413             : 
    2414           0 :     m = (p2.x - p1.x) / (p2.y - p1.y);
    2415           0 :     out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
    2416           0 :     out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
    2417           0 : }
    2418             : 
    2419             : 
    2420             : typedef struct {
    2421             :     cairo_trapezoid_t *traps;
    2422             :     int num_traps;
    2423             :     cairo_antialias_t antialias;
    2424             : } composite_traps_info_t;
    2425             : 
    2426             : static void
    2427           0 : _pixman_image_add_traps (pixman_image_t *image,
    2428             :                          int dst_x, int dst_y,
    2429             :                          composite_traps_info_t *info)
    2430             : {
    2431           0 :     cairo_trapezoid_t *t = info->traps;
    2432           0 :     int num_traps = info->num_traps;
    2433           0 :     while (num_traps--) {
    2434             :         pixman_trapezoid_t trap;
    2435             : 
    2436             :         /* top/bottom will be clamped to surface bounds */
    2437           0 :         trap.top = _cairo_fixed_to_16_16 (t->top);
    2438           0 :         trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
    2439             : 
    2440             :         /* However, all the other coordinates will have been left untouched so
    2441             :          * as not to introduce numerical error. Recompute them if they
    2442             :          * exceed the 16.16 limits.
    2443             :          */
    2444           0 :         if (unlikely (_line_exceeds_16_16 (&t->left))) {
    2445           0 :             _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
    2446           0 :             trap.left.p1.y = trap.top;
    2447           0 :             trap.left.p2.y = trap.bottom;
    2448             :         } else {
    2449           0 :             trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
    2450           0 :             trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
    2451           0 :             trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
    2452           0 :             trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
    2453             :         }
    2454             : 
    2455           0 :         if (unlikely (_line_exceeds_16_16 (&t->right))) {
    2456           0 :             _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
    2457           0 :             trap.right.p1.y = trap.top;
    2458           0 :             trap.right.p2.y = trap.bottom;
    2459             :         } else {
    2460           0 :             trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
    2461           0 :             trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
    2462           0 :             trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
    2463           0 :             trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
    2464             :         }
    2465             : 
    2466           0 :         pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
    2467             : 
    2468           0 :         t++;
    2469             :     }
    2470           0 : }
    2471             : 
    2472             : static cairo_status_t
    2473           0 : _composite_traps (void                          *closure,
    2474             :                   pixman_image_t                *dst,
    2475             :                   pixman_format_code_t           dst_format,
    2476             :                   cairo_operator_t               op,
    2477             :                   const cairo_pattern_t         *pattern,
    2478             :                   int                            dst_x,
    2479             :                   int                            dst_y,
    2480             :                   const cairo_rectangle_int_t   *extents,
    2481             :                   cairo_region_t                *clip_region)
    2482             : {
    2483           0 :     composite_traps_info_t *info = closure;
    2484             :     pixman_image_t *src, *mask;
    2485             :     pixman_format_code_t format;
    2486           0 :     int src_x = 0, src_y = 0;
    2487             :     cairo_status_t status;
    2488             : 
    2489             :     /* Special case adding trapezoids onto a mask surface; we want to avoid
    2490             :      * creating an intermediate temporary mask unnecessarily.
    2491             :      *
    2492             :      * We make the assumption here that the portion of the trapezoids
    2493             :      * contained within the surface is bounded by [dst_x,dst_y,width,height];
    2494             :      * the Cairo core code passes bounds based on the trapezoid extents.
    2495             :      */
    2496           0 :     format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
    2497           0 :     if (dst_format == format &&
    2498           0 :         (pattern == NULL ||
    2499           0 :          (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
    2500             :     {
    2501           0 :         _pixman_image_add_traps (dst, dst_x, dst_y, info);
    2502           0 :         return CAIRO_STATUS_SUCCESS;
    2503             :     }
    2504             : 
    2505           0 :     src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
    2506           0 :     if (unlikely (src == NULL))
    2507           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2508             : 
    2509           0 :     mask = pixman_image_create_bits (format, extents->width, extents->height,
    2510             :                                      NULL, 0);
    2511           0 :     if (unlikely (mask == NULL)) {
    2512           0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2513           0 :         goto CLEANUP_SOURCE;
    2514             :     }
    2515             : 
    2516           0 :     _pixman_image_add_traps (mask, extents->x, extents->y, info);
    2517           0 :     pixman_image_composite32 (_pixman_operator (op),
    2518             :                               src, mask, dst,
    2519           0 :                               extents->x + src_x, extents->y + src_y,
    2520             :                               0, 0,
    2521           0 :                               extents->x - dst_x, extents->y - dst_y,
    2522             :                               extents->width, extents->height);
    2523             : 
    2524           0 :     pixman_image_unref (mask);
    2525             : 
    2526           0 :     status = CAIRO_STATUS_SUCCESS;
    2527             :  CLEANUP_SOURCE:
    2528           0 :     pixman_image_unref (src);
    2529             : 
    2530           0 :     return status;
    2531             : }
    2532             : 
    2533             : static inline uint32_t
    2534           0 : color_to_uint32 (const cairo_color_t *color)
    2535             : {
    2536             :     return
    2537           0 :         (color->alpha_short >> 8 << 24) |
    2538           0 :         (color->red_short >> 8 << 16)   |
    2539           0 :         (color->green_short & 0xff00)   |
    2540           0 :         (color->blue_short >> 8);
    2541             : }
    2542             : 
    2543             : static inline cairo_bool_t
    2544           0 : color_to_pixel (const cairo_color_t     *color,
    2545             :                 pixman_format_code_t     format,
    2546             :                 uint32_t                *pixel)
    2547             : {
    2548             :     uint32_t c;
    2549             : 
    2550           0 :     if (!(format == PIXMAN_a8r8g8b8     ||
    2551           0 :           format == PIXMAN_x8r8g8b8     ||
    2552           0 :           format == PIXMAN_a8b8g8r8     ||
    2553           0 :           format == PIXMAN_x8b8g8r8     ||
    2554           0 :           format == PIXMAN_b8g8r8a8     ||
    2555           0 :           format == PIXMAN_b8g8r8x8     ||
    2556           0 :           format == PIXMAN_r5g6b5       ||
    2557             :           format == PIXMAN_b5g6r5       ||
    2558             :           format == PIXMAN_a8))
    2559             :     {
    2560           0 :         return FALSE;
    2561             :     }
    2562             : 
    2563           0 :     c = color_to_uint32 (color);
    2564             : 
    2565           0 :     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
    2566           0 :         c = ((c & 0xff000000) >>  0) |
    2567           0 :             ((c & 0x00ff0000) >> 16) |
    2568           0 :             ((c & 0x0000ff00) >>  0) |
    2569           0 :             ((c & 0x000000ff) << 16);
    2570             :     }
    2571             : 
    2572           0 :     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
    2573           0 :         c = ((c & 0xff000000) >> 24) |
    2574           0 :             ((c & 0x00ff0000) >>  8) |
    2575           0 :             ((c & 0x0000ff00) <<  8) |
    2576           0 :             ((c & 0x000000ff) << 24);
    2577             :     }
    2578             : 
    2579           0 :     if (format == PIXMAN_a8) {
    2580           0 :         c = c >> 24;
    2581           0 :     } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
    2582           0 :         c = ((((c) >> 3) & 0x001f) |
    2583           0 :              (((c) >> 5) & 0x07e0) |
    2584           0 :              (((c) >> 8) & 0xf800));
    2585             :     }
    2586             : 
    2587           0 :     *pixel = c;
    2588           0 :     return TRUE;
    2589             : }
    2590             : 
    2591             : static inline cairo_bool_t
    2592           0 : pattern_to_pixel (const cairo_solid_pattern_t *solid,
    2593             :                   cairo_operator_t op,
    2594             :                   pixman_format_code_t format,
    2595             :                   uint32_t *pixel)
    2596             : {
    2597           0 :     if (op == CAIRO_OPERATOR_CLEAR) {
    2598           0 :         *pixel = 0;
    2599           0 :         return TRUE;
    2600             :     }
    2601             : 
    2602           0 :     if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
    2603           0 :         return FALSE;
    2604             : 
    2605           0 :     if (op == CAIRO_OPERATOR_OVER) {
    2606           0 :         if (solid->color.alpha_short >= 0xff00)
    2607           0 :             op = CAIRO_OPERATOR_SOURCE;
    2608             :     }
    2609             : 
    2610           0 :     if (op != CAIRO_OPERATOR_SOURCE)
    2611           0 :         return FALSE;
    2612             : 
    2613           0 :     return color_to_pixel (&solid->color, format, pixel);
    2614             : }
    2615             : 
    2616             : typedef struct _fill_span {
    2617             :     cairo_span_renderer_t base;
    2618             : 
    2619             :     uint8_t *mask_data;
    2620             :     pixman_image_t *src, *dst, *mask;
    2621             : } fill_span_renderer_t;
    2622             : 
    2623             : static cairo_status_t
    2624           0 : _fill_span (void *abstract_renderer,
    2625             :             int y, int height,
    2626             :             const cairo_half_open_span_t *spans,
    2627             :             unsigned num_spans)
    2628             : {
    2629           0 :     fill_span_renderer_t *renderer = abstract_renderer;
    2630             :     uint8_t *row;
    2631             :     unsigned i;
    2632             : 
    2633           0 :     if (num_spans == 0)
    2634           0 :         return CAIRO_STATUS_SUCCESS;
    2635             : 
    2636           0 :     row = renderer->mask_data - spans[0].x;
    2637           0 :     for (i = 0; i < num_spans - 1; i++) {
    2638             :         /* We implement setting the most common single pixel wide
    2639             :          * span case to avoid the overhead of a memset call.
    2640             :          * Open coding setting longer spans didn't show a
    2641             :          * noticeable improvement over memset.
    2642             :          */
    2643           0 :         if (spans[i+1].x == spans[i].x + 1) {
    2644           0 :             row[spans[i].x] = spans[i].coverage;
    2645             :         } else {
    2646           0 :             memset (row + spans[i].x,
    2647           0 :                     spans[i].coverage,
    2648           0 :                     spans[i+1].x - spans[i].x);
    2649             :         }
    2650             :     }
    2651             : 
    2652             :     do {
    2653           0 :         pixman_image_composite32 (PIXMAN_OP_OVER,
    2654             :                                   renderer->src, renderer->mask, renderer->dst,
    2655             :                                   0, 0, 0, 0,
    2656             :                                   spans[0].x, y++,
    2657           0 :                                   spans[i].x - spans[0].x, 1);
    2658           0 :     } while (--height);
    2659             : 
    2660           0 :     return CAIRO_STATUS_SUCCESS;
    2661             : }
    2662             : 
    2663             : /* avoid using region code to re-validate boxes */
    2664             : static cairo_status_t
    2665           0 : _fill_unaligned_boxes (cairo_image_surface_t *dst,
    2666             :                        const cairo_pattern_t *pattern,
    2667             :                        uint32_t pixel,
    2668             :                        const cairo_boxes_t *boxes,
    2669             :                        const cairo_composite_rectangles_t *extents)
    2670             : {
    2671             :     uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
    2672             :     fill_span_renderer_t renderer;
    2673             :     cairo_rectangular_scan_converter_t converter;
    2674             :     const struct _cairo_boxes_chunk *chunk;
    2675             :     cairo_status_t status;
    2676             :     int i;
    2677             : 
    2678             :     /* XXX
    2679             :      * using composite for fill:
    2680             :      *   spiral-box-nonalign-evenodd-fill.512    2201957    2.202
    2681             :      *   spiral-box-nonalign-nonzero-fill.512     336726    0.337
    2682             :      *   spiral-box-pixalign-evenodd-fill.512     352256    0.352
    2683             :      *   spiral-box-pixalign-nonzero-fill.512     147056    0.147
    2684             :      * using fill:
    2685             :      *   spiral-box-nonalign-evenodd-fill.512    3174565    3.175
    2686             :      *   spiral-box-nonalign-nonzero-fill.512     182710    0.183
    2687             :      *   spiral-box-pixalign-evenodd-fill.512     353863    0.354
    2688             :      *   spiral-box-pixalign-nonzero-fill.512     147402    0.147
    2689             :      *
    2690             :      * cairo-perf-trace seems to favour using fill.
    2691             :      */
    2692             : 
    2693           0 :     renderer.base.render_rows = _fill_span;
    2694           0 :     renderer.dst = dst->pixman_image;
    2695             : 
    2696           0 :     if ((unsigned) extents->bounded.width <= sizeof (buf)) {
    2697           0 :         renderer.mask = pixman_image_create_bits (PIXMAN_a8,
    2698             :                                                   extents->bounded.width, 1,
    2699             :                                                   (uint32_t *) buf,
    2700             :                                                   sizeof (buf));
    2701             :     } else {
    2702           0 :         renderer.mask = pixman_image_create_bits (PIXMAN_a8,
    2703             :                                                   extents->bounded.width, 1,
    2704             :                                                   NULL,  0);
    2705             :     }
    2706           0 :     if (unlikely (renderer.mask == NULL))
    2707           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2708             : 
    2709           0 :     renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
    2710             : 
    2711           0 :     renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
    2712           0 :     if (unlikely (renderer.src == NULL)) {
    2713           0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2714           0 :         goto CLEANUP_MASK;
    2715             :     }
    2716             : 
    2717           0 :     _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
    2718             : 
    2719             :     /* first blit any aligned part of the boxes */
    2720           0 :     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
    2721           0 :         const cairo_box_t *box = chunk->base;
    2722             : 
    2723           0 :         for (i = 0; i < chunk->count; i++) {
    2724           0 :             int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
    2725           0 :             int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
    2726           0 :             int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
    2727           0 :             int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
    2728             : 
    2729           0 :             x1 = (x1 < 0 ? 0 : x1);
    2730           0 :             y1 = (y1 < 0 ? 0 : y1);
    2731           0 :             if (x2 > x1 && y2 > y1) {
    2732             :                 cairo_box_t b;
    2733             : 
    2734           0 :                 pixman_fill ((uint32_t *) dst->data,
    2735           0 :                              dst->stride / sizeof (uint32_t),
    2736           0 :                              PIXMAN_FORMAT_BPP (dst->pixman_format),
    2737             :                              x1, y1, x2 - x1, y2 - y1,
    2738             :                              pixel);
    2739             : 
    2740             :                 /* top */
    2741           0 :                 if (! _cairo_fixed_is_integer (box[i].p1.y)) {
    2742           0 :                     b.p1.x = box[i].p1.x;
    2743           0 :                     b.p1.y = box[i].p1.y;
    2744           0 :                     b.p2.x = box[i].p2.x;
    2745           0 :                     b.p2.y = _cairo_fixed_from_int (y1);
    2746             : 
    2747           0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
    2748           0 :                     if (unlikely (status))
    2749           0 :                         goto CLEANUP_CONVERTER;
    2750             :                 }
    2751             : 
    2752             :                 /* left */
    2753           0 :                 if (! _cairo_fixed_is_integer (box[i].p1.x)) {
    2754           0 :                     b.p1.x = box[i].p1.x;
    2755           0 :                     b.p1.y = box[i].p1.y;
    2756           0 :                     b.p2.x = _cairo_fixed_from_int (x1);
    2757           0 :                     b.p2.y = box[i].p2.y;
    2758             : 
    2759           0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
    2760           0 :                     if (unlikely (status))
    2761           0 :                         goto CLEANUP_CONVERTER;
    2762             :                 }
    2763             : 
    2764             :                 /* right */
    2765           0 :                 if (! _cairo_fixed_is_integer (box[i].p2.x)) {
    2766           0 :                     b.p1.x = _cairo_fixed_from_int (x2);
    2767           0 :                     b.p1.y = box[i].p1.y;
    2768           0 :                     b.p2.x = box[i].p2.x;
    2769           0 :                     b.p2.y = box[i].p2.y;
    2770             : 
    2771           0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
    2772           0 :                     if (unlikely (status))
    2773           0 :                         goto CLEANUP_CONVERTER;
    2774             :                 }
    2775             : 
    2776             :                 /* bottom */
    2777           0 :                 if (! _cairo_fixed_is_integer (box[i].p2.y)) {
    2778           0 :                     b.p1.x = box[i].p1.x;
    2779           0 :                     b.p1.y = _cairo_fixed_from_int (y2);
    2780           0 :                     b.p2.x = box[i].p2.x;
    2781           0 :                     b.p2.y = box[i].p2.y;
    2782             : 
    2783           0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
    2784           0 :                     if (unlikely (status))
    2785           0 :                         goto CLEANUP_CONVERTER;
    2786             :                 }
    2787             :             } else {
    2788           0 :                 status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
    2789           0 :                 if (unlikely (status))
    2790           0 :                     goto CLEANUP_CONVERTER;
    2791             :             }
    2792             :         }
    2793             :     }
    2794             : 
    2795           0 :     status = converter.base.generate (&converter.base, &renderer.base);
    2796             : 
    2797             :   CLEANUP_CONVERTER:
    2798           0 :     converter.base.destroy (&converter.base);
    2799           0 :     pixman_image_unref (renderer.src);
    2800             :   CLEANUP_MASK:
    2801           0 :     pixman_image_unref (renderer.mask);
    2802             : 
    2803           0 :     return status;
    2804             : }
    2805             : 
    2806             : typedef struct _cairo_image_surface_span_renderer {
    2807             :     cairo_span_renderer_t base;
    2808             : 
    2809             :     uint8_t *mask_data;
    2810             :     uint32_t mask_stride;
    2811             : } cairo_image_surface_span_renderer_t;
    2812             : 
    2813             : cairo_status_t
    2814           0 : _cairo_image_surface_span (void *abstract_renderer,
    2815             :                            int y, int height,
    2816             :                            const cairo_half_open_span_t *spans,
    2817             :                            unsigned num_spans)
    2818             : {
    2819           0 :     cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
    2820             :     uint8_t *row;
    2821             :     unsigned i;
    2822             : 
    2823           0 :     if (num_spans == 0)
    2824           0 :         return CAIRO_STATUS_SUCCESS;
    2825             : 
    2826             :     /* XXX will it be quicker to repeat the sparse memset,
    2827             :      * or perform a simpler memcpy?
    2828             :      * The fairly dense spiral benchmarks suggests that the sparse
    2829             :      * memset is a win there as well.
    2830             :      */
    2831           0 :     row = renderer->mask_data + y * renderer->mask_stride;
    2832             :     do {
    2833           0 :         for (i = 0; i < num_spans - 1; i++) {
    2834           0 :             if (! spans[i].coverage)
    2835           0 :                 continue;
    2836             : 
    2837             :             /* We implement setting rendering the most common single
    2838             :              * pixel wide span case to avoid the overhead of a memset
    2839             :              * call.  Open coding setting longer spans didn't show a
    2840             :              * noticeable improvement over memset. */
    2841           0 :             if (spans[i+1].x == spans[i].x + 1) {
    2842           0 :                 row[spans[i].x] = spans[i].coverage;
    2843             :             } else {
    2844           0 :                 memset (row + spans[i].x,
    2845           0 :                         spans[i].coverage,
    2846           0 :                         spans[i+1].x - spans[i].x);
    2847             :             }
    2848             :         }
    2849           0 :         row += renderer->mask_stride;
    2850           0 :     } while (--height);
    2851             : 
    2852           0 :     return CAIRO_STATUS_SUCCESS;
    2853             : }
    2854             : 
    2855             : static cairo_status_t
    2856           0 : _composite_unaligned_boxes (cairo_image_surface_t *dst,
    2857             :                             cairo_operator_t op,
    2858             :                             const cairo_pattern_t *pattern,
    2859             :                             const cairo_boxes_t *boxes,
    2860             :                             const cairo_composite_rectangles_t *extents)
    2861             : {
    2862             :     uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
    2863             :     cairo_image_surface_span_renderer_t renderer;
    2864             :     cairo_rectangular_scan_converter_t converter;
    2865             :     pixman_image_t *mask, *src;
    2866             :     cairo_status_t status;
    2867             :     const struct _cairo_boxes_chunk *chunk;
    2868             :     int i, src_x, src_y;
    2869             : 
    2870           0 :     i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
    2871           0 :     if ((unsigned) i <= sizeof (buf)) {
    2872           0 :         mask = pixman_image_create_bits (PIXMAN_a8,
    2873             :                                          extents->bounded.width,
    2874             :                                          extents->bounded.height,
    2875             :                                          (uint32_t *) buf,
    2876           0 :                                          CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
    2877           0 :         memset (buf, 0, i);
    2878             :     } else {
    2879           0 :         mask = pixman_image_create_bits (PIXMAN_a8,
    2880             :                                          extents->bounded.width,
    2881             :                                          extents->bounded.height,
    2882             :                                          NULL,  0);
    2883             :     }
    2884           0 :     if (unlikely (mask == NULL))
    2885           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2886             : 
    2887           0 :     renderer.base.render_rows = _cairo_image_surface_span;
    2888           0 :     renderer.mask_stride = pixman_image_get_stride (mask);
    2889           0 :     renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
    2890           0 :     renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
    2891             : 
    2892           0 :     _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
    2893             : 
    2894           0 :     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
    2895           0 :         const cairo_box_t *box = chunk->base;
    2896             : 
    2897           0 :         for (i = 0; i < chunk->count; i++) {
    2898           0 :             status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
    2899           0 :             if (unlikely (status))
    2900           0 :                 goto CLEANUP;
    2901             :         }
    2902             :     }
    2903             : 
    2904           0 :     status = converter.base.generate (&converter.base, &renderer.base);
    2905           0 :     if (unlikely (status))
    2906           0 :         goto CLEANUP;
    2907             : 
    2908           0 :     src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
    2909           0 :     if (unlikely (src == NULL)) {
    2910           0 :         status =  _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2911           0 :         goto CLEANUP;
    2912             :     }
    2913             : 
    2914           0 :     pixman_image_composite32 (_pixman_operator (op),
    2915             :                               src, mask, dst->pixman_image,
    2916           0 :                               extents->bounded.x + src_x, extents->bounded.y + src_y,
    2917             :                               0, 0,
    2918             :                               extents->bounded.x, extents->bounded.y,
    2919             :                               extents->bounded.width, extents->bounded.height);
    2920           0 :     pixman_image_unref (src);
    2921             : 
    2922             :   CLEANUP:
    2923           0 :     converter.base.destroy (&converter.base);
    2924           0 :     pixman_image_unref (mask);
    2925             : 
    2926           0 :     return status;
    2927             : }
    2928             : 
    2929             : static cairo_status_t
    2930           0 : _composite_boxes (cairo_image_surface_t *dst,
    2931             :                   cairo_operator_t op,
    2932             :                   const cairo_pattern_t *pattern,
    2933             :                   cairo_boxes_t *boxes,
    2934             :                   cairo_antialias_t antialias,
    2935             :                   cairo_clip_t *clip,
    2936             :                   const cairo_composite_rectangles_t *extents)
    2937             : {
    2938           0 :     cairo_region_t *clip_region = NULL;
    2939           0 :     cairo_bool_t need_clip_mask = FALSE;
    2940             :     cairo_status_t status;
    2941             :     struct _cairo_boxes_chunk *chunk;
    2942             :     uint32_t pixel;
    2943             :     int i;
    2944             : 
    2945           0 :     if (clip != NULL) {
    2946           0 :         status = _cairo_clip_get_region (clip, &clip_region);
    2947           0 :         if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
    2948           0 :             return CAIRO_STATUS_SUCCESS;
    2949           0 :         need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
    2950           0 :         if (need_clip_mask &&
    2951           0 :             (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
    2952             :         {
    2953           0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
    2954             :         }
    2955             : 
    2956           0 :         if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
    2957           0 :             clip_region = NULL;
    2958             :     }
    2959             : 
    2960           0 :     if (antialias != CAIRO_ANTIALIAS_NONE) {
    2961           0 :         if (! boxes->is_pixel_aligned) {
    2962           0 :             if (need_clip_mask)
    2963           0 :                 return CAIRO_INT_STATUS_UNSUPPORTED;
    2964             : 
    2965           0 :             if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
    2966             :                                   dst->pixman_format, &pixel))
    2967             :             {
    2968           0 :                 return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
    2969             :             }
    2970             :             else
    2971             :             {
    2972           0 :                 return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
    2973             :             }
    2974             :         }
    2975             :     }
    2976             : 
    2977           0 :     status = CAIRO_STATUS_SUCCESS;
    2978           0 :     if (! need_clip_mask &&
    2979           0 :         pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
    2980             :                           &pixel))
    2981             :     {
    2982           0 :         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
    2983           0 :             cairo_box_t *box = chunk->base;
    2984             : 
    2985           0 :             for (i = 0; i < chunk->count; i++) {
    2986           0 :                 int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
    2987           0 :                 int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
    2988           0 :                 int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
    2989           0 :                 int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
    2990             : 
    2991           0 :                 x1 = (x1 < 0 ? 0 : x1);
    2992           0 :                 y1 = (y1 < 0 ? 0 : y1);
    2993           0 :                 if (x2 <= x1 || y2 <= y1)
    2994           0 :                     continue;
    2995             : 
    2996           0 :                 pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
    2997           0 :                              PIXMAN_FORMAT_BPP (dst->pixman_format),
    2998             :                              x1, y1, x2 - x1, y2 - y1,
    2999             :                              pixel);
    3000             :             }
    3001             :         }
    3002             :     }
    3003             :     else
    3004             :     {
    3005           0 :         pixman_image_t *src = NULL, *mask = NULL;
    3006           0 :         int src_x, src_y, mask_x = 0, mask_y = 0;
    3007           0 :         pixman_op_t pixman_op = _pixman_operator (op);
    3008             : 
    3009           0 :         if (need_clip_mask) {
    3010             :             cairo_surface_t *clip_surface;
    3011             :             int clip_x, clip_y;
    3012             : 
    3013           0 :             clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
    3014           0 :             if (unlikely (clip_surface->status))
    3015           0 :                 return clip_surface->status;
    3016             : 
    3017           0 :             mask_x = -clip_x;
    3018           0 :             mask_y = -clip_y;
    3019             : 
    3020           0 :             if (op == CAIRO_OPERATOR_CLEAR) {
    3021           0 :                 pattern = NULL;
    3022           0 :                 pixman_op = PIXMAN_OP_OUT_REVERSE;
    3023             :             }
    3024             : 
    3025           0 :             mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
    3026             :         }
    3027             : 
    3028           0 :         if (pattern != NULL) {
    3029           0 :             src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
    3030           0 :             if (unlikely (src == NULL))
    3031           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3032             :         } else {
    3033           0 :             src = mask;
    3034           0 :             src_x = mask_x;
    3035           0 :             src_y = mask_y;
    3036           0 :             mask = NULL;
    3037             :         }
    3038             : 
    3039           0 :         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
    3040           0 :             const cairo_box_t *box = chunk->base;
    3041             : 
    3042           0 :             for (i = 0; i < chunk->count; i++) {
    3043           0 :                 int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
    3044           0 :                 int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
    3045           0 :                 int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
    3046           0 :                 int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
    3047             : 
    3048           0 :                 if (x2 == x1 || y2 == y1)
    3049           0 :                     continue;
    3050             : 
    3051           0 :                 pixman_image_composite32 (pixman_op,
    3052             :                                           src, mask, dst->pixman_image,
    3053             :                                           x1 + src_x,  y1 + src_y,
    3054             :                                           x1 + mask_x, y1 + mask_y,
    3055             :                                           x1, y1,
    3056             :                                           x2 - x1, y2 - y1);
    3057             :             }
    3058             :         }
    3059             : 
    3060           0 :         if (pattern != NULL)
    3061           0 :             pixman_image_unref (src);
    3062             : 
    3063           0 :         if (! extents->is_bounded) {
    3064           0 :             status =
    3065           0 :                 _cairo_image_surface_fixup_unbounded_boxes (dst, extents,
    3066             :                                                             clip_region, boxes);
    3067             :         }
    3068             :     }
    3069             : 
    3070           0 :     return status;
    3071             : }
    3072             : 
    3073             : static cairo_status_t
    3074           0 : _clip_and_composite_boxes (cairo_image_surface_t *dst,
    3075             :                            cairo_operator_t op,
    3076             :                            const cairo_pattern_t *src,
    3077             :                            cairo_boxes_t *boxes,
    3078             :                            cairo_antialias_t antialias,
    3079             :                            cairo_composite_rectangles_t *extents,
    3080             :                            cairo_clip_t *clip)
    3081             : {
    3082             :     cairo_traps_t traps;
    3083             :     cairo_status_t status;
    3084             :     composite_traps_info_t info;
    3085             : 
    3086           0 :     if (boxes->num_boxes == 0 && extents->is_bounded)
    3087           0 :         return CAIRO_STATUS_SUCCESS;
    3088             : 
    3089             :     /* Use a fast path if the boxes are pixel aligned */
    3090           0 :     status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
    3091           0 :     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    3092           0 :         return status;
    3093             : 
    3094             :     /* Otherwise render via a mask and composite in the usual fashion.  */
    3095           0 :     status = _cairo_traps_init_boxes (&traps, boxes);
    3096           0 :     if (unlikely (status))
    3097           0 :         return status;
    3098             : 
    3099           0 :     info.num_traps = traps.num_traps;
    3100           0 :     info.traps = traps.traps;
    3101           0 :     info.antialias = antialias;
    3102           0 :     status = _clip_and_composite (dst, op, src,
    3103             :                                   _composite_traps, &info,
    3104             :                                   extents, clip);
    3105             : 
    3106           0 :     _cairo_traps_fini (&traps);
    3107           0 :     return status;
    3108             : }
    3109             : 
    3110             : static cairo_bool_t
    3111           0 : _mono_edge_is_vertical (const cairo_line_t *line)
    3112             : {
    3113           0 :     return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
    3114             : }
    3115             : 
    3116             : static cairo_bool_t
    3117           0 : _traps_are_pixel_aligned (cairo_traps_t *traps,
    3118             :                           cairo_antialias_t antialias)
    3119             : {
    3120             :     int i;
    3121             : 
    3122           0 :     if (antialias == CAIRO_ANTIALIAS_NONE) {
    3123           0 :         for (i = 0; i < traps->num_traps; i++) {
    3124           0 :             if (! _mono_edge_is_vertical (&traps->traps[i].left)   ||
    3125           0 :                 ! _mono_edge_is_vertical (&traps->traps[i].right))
    3126             :             {
    3127           0 :                 traps->maybe_region = FALSE;
    3128           0 :                 return FALSE;
    3129             :             }
    3130             :         }
    3131             :     } else {
    3132           0 :         for (i = 0; i < traps->num_traps; i++) {
    3133           0 :             if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
    3134           0 :                 traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
    3135           0 :                 ! _cairo_fixed_is_integer (traps->traps[i].top)          ||
    3136           0 :                 ! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
    3137           0 :                 ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
    3138           0 :                 ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
    3139             :             {
    3140           0 :                 traps->maybe_region = FALSE;
    3141           0 :                 return FALSE;
    3142             :             }
    3143             :         }
    3144             :     }
    3145             : 
    3146           0 :     return TRUE;
    3147             : }
    3148             : 
    3149             : static void
    3150           0 : _boxes_for_traps (cairo_boxes_t *boxes,
    3151             :                   cairo_traps_t *traps,
    3152             :                   cairo_antialias_t antialias)
    3153             : {
    3154             :     int i;
    3155             : 
    3156           0 :     _cairo_boxes_init (boxes);
    3157             : 
    3158           0 :     boxes->num_boxes    = traps->num_traps;
    3159           0 :     boxes->chunks.base  = (cairo_box_t *) traps->traps;
    3160           0 :     boxes->chunks.count = traps->num_traps;
    3161           0 :     boxes->chunks.size  = traps->num_traps;
    3162             : 
    3163           0 :     if (antialias != CAIRO_ANTIALIAS_NONE) {
    3164           0 :         for (i = 0; i < traps->num_traps; i++) {
    3165             :             /* Note the traps and boxes alias so we need to take the local copies first. */
    3166           0 :             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
    3167           0 :             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
    3168           0 :             cairo_fixed_t y1 = traps->traps[i].top;
    3169           0 :             cairo_fixed_t y2 = traps->traps[i].bottom;
    3170             : 
    3171           0 :             boxes->chunks.base[i].p1.x = x1;
    3172           0 :             boxes->chunks.base[i].p1.y = y1;
    3173           0 :             boxes->chunks.base[i].p2.x = x2;
    3174           0 :             boxes->chunks.base[i].p2.y = y2;
    3175             : 
    3176           0 :             if (boxes->is_pixel_aligned) {
    3177           0 :                 boxes->is_pixel_aligned =
    3178           0 :                     _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
    3179           0 :                     _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
    3180             :             }
    3181             :         }
    3182             :     } else {
    3183           0 :         boxes->is_pixel_aligned = TRUE;
    3184             : 
    3185           0 :         for (i = 0; i < traps->num_traps; i++) {
    3186             :             /* Note the traps and boxes alias so we need to take the local copies first. */
    3187           0 :             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
    3188           0 :             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
    3189           0 :             cairo_fixed_t y1 = traps->traps[i].top;
    3190           0 :             cairo_fixed_t y2 = traps->traps[i].bottom;
    3191             : 
    3192             :             /* round down here to match Pixman's behavior when using traps. */
    3193           0 :             boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
    3194           0 :             boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
    3195           0 :             boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
    3196           0 :             boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
    3197             :         }
    3198             :     }
    3199           0 : }
    3200             : 
    3201             : static cairo_status_t
    3202           0 : _clip_and_composite_trapezoids (cairo_image_surface_t *dst,
    3203             :                                 cairo_operator_t op,
    3204             :                                 const cairo_pattern_t *src,
    3205             :                                 cairo_traps_t *traps,
    3206             :                                 cairo_antialias_t antialias,
    3207             :                                 cairo_composite_rectangles_t *extents,
    3208             :                                 cairo_clip_t *clip)
    3209             : {
    3210             :     composite_traps_info_t info;
    3211           0 :     cairo_bool_t need_clip_surface = FALSE;
    3212             :     cairo_status_t status;
    3213             : 
    3214           0 :     if (traps->num_traps == 0 && extents->is_bounded)
    3215           0 :         return CAIRO_STATUS_SUCCESS;
    3216             : 
    3217           0 :     if (clip != NULL) {
    3218             :         cairo_region_t *clip_region;
    3219             : 
    3220           0 :         status = _cairo_clip_get_region (clip, &clip_region);
    3221           0 :         need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
    3222             :     }
    3223             : 
    3224           0 :     if (traps->has_intersections) {
    3225           0 :         if (traps->is_rectangular)
    3226           0 :             status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
    3227           0 :         else if (traps->is_rectilinear)
    3228           0 :             status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
    3229             :         else
    3230           0 :             status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
    3231           0 :         if (unlikely (status))
    3232           0 :             return status;
    3233             :     }
    3234             : 
    3235             :     /* Use a fast path if the trapezoids consist of a simple region,
    3236             :      * but we can only do this if we do not have a clip surface, or can
    3237             :      * substitute the mask with the clip.
    3238             :      */
    3239           0 :     if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
    3240           0 :         (! need_clip_surface ||
    3241           0 :          (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
    3242             :     {
    3243             :         cairo_boxes_t boxes;
    3244             : 
    3245           0 :         _boxes_for_traps (&boxes, traps, antialias);
    3246           0 :         return _clip_and_composite_boxes (dst, op, src,
    3247             :                                           &boxes, antialias,
    3248             :                                           extents, clip);
    3249             :     }
    3250             : 
    3251             :     /* No fast path, exclude self-intersections and clip trapezoids. */
    3252             :     /* Otherwise render the trapezoids to a mask and composite in the usual
    3253             :      * fashion.
    3254             :      */
    3255           0 :     info.traps = traps->traps;
    3256           0 :     info.num_traps = traps->num_traps;
    3257           0 :     info.antialias = antialias;
    3258           0 :     return _clip_and_composite (dst, op, src,
    3259             :                                 _composite_traps, &info,
    3260             :                                 extents, clip);
    3261             : }
    3262             : 
    3263             : static cairo_clip_path_t *
    3264           0 : _clip_get_single_path (cairo_clip_t *clip)
    3265             : {
    3266           0 :     if (clip->path->prev == NULL)
    3267           0 :       return clip->path;
    3268             : 
    3269           0 :     return NULL;
    3270             : }
    3271             : 
    3272             : /* high level image interface */
    3273             : 
    3274             : static cairo_int_status_t
    3275           0 : _cairo_image_surface_paint (void                        *abstract_surface,
    3276             :                             cairo_operator_t             op,
    3277             :                             const cairo_pattern_t       *source,
    3278             :                             cairo_clip_t                *clip)
    3279             : {
    3280           0 :     cairo_image_surface_t *surface = abstract_surface;
    3281             :     cairo_composite_rectangles_t extents;
    3282             :     cairo_clip_path_t *clip_path;
    3283             :     cairo_clip_t local_clip;
    3284           0 :     cairo_bool_t have_clip = FALSE;
    3285           0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
    3286           0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
    3287             :     cairo_status_t status;
    3288             : 
    3289             :     cairo_rectangle_int_t rect;
    3290           0 :     rect.x = rect.y = 0;
    3291           0 :     rect.width = surface->width;
    3292           0 :     rect.height = surface->height;
    3293             : 
    3294           0 :     status = _cairo_composite_rectangles_init_for_paint (&extents,
    3295             :                                                          &rect,
    3296             :                                                          op, source,
    3297             :                                                          clip);
    3298           0 :     if (unlikely (status))
    3299           0 :         return status;
    3300             : 
    3301           0 :     if (_cairo_clip_contains_extents (clip, &extents))
    3302           0 :         clip = NULL;
    3303             : 
    3304           0 :     if (clip != NULL) {
    3305           0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
    3306           0 :         have_clip = TRUE;
    3307             :     }
    3308             : 
    3309           0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
    3310           0 :     if (unlikely (status)) {
    3311           0 :         if (have_clip)
    3312           0 :             _cairo_clip_fini (&local_clip);
    3313             : 
    3314           0 :         return status;
    3315             :     }
    3316             : 
    3317             :     /* If the clip cannot be reduced to a set of boxes, we will need to
    3318             :      * use a clipmask. Paint is special as it is the only operation that
    3319             :      * does not implicitly use a mask, so we may be able to reduce this
    3320             :      * operation to a fill...
    3321             :      */
    3322           0 :     if (clip != NULL &&
    3323           0 :         extents.is_bounded &&
    3324           0 :         (clip_path = _clip_get_single_path (clip)) != NULL)
    3325             :     {
    3326           0 :         status = _cairo_image_surface_fill (surface, op, source,
    3327             :                                             &clip_path->path,
    3328             :                                             clip_path->fill_rule,
    3329             :                                             clip_path->tolerance,
    3330             :                                             clip_path->antialias,
    3331             :                                             NULL);
    3332             :     }
    3333             :     else
    3334             :     {
    3335             :         cairo_boxes_t boxes;
    3336             : 
    3337           0 :         _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
    3338           0 :         status = _clip_and_composite_boxes (surface, op, source,
    3339             :                                             &boxes, CAIRO_ANTIALIAS_DEFAULT,
    3340             :                                             &extents, clip);
    3341             :     }
    3342             : 
    3343           0 :     if (clip_boxes != boxes_stack)
    3344           0 :         free (clip_boxes);
    3345             : 
    3346           0 :     if (have_clip)
    3347           0 :         _cairo_clip_fini (&local_clip);
    3348             : 
    3349           0 :     return status;
    3350             : }
    3351             : 
    3352             : static cairo_status_t
    3353           0 : _composite_mask (void                           *closure,
    3354             :                  pixman_image_t                 *dst,
    3355             :                  pixman_format_code_t            dst_format,
    3356             :                  cairo_operator_t                op,
    3357             :                  const cairo_pattern_t          *src_pattern,
    3358             :                  int                             dst_x,
    3359             :                  int                             dst_y,
    3360             :                  const cairo_rectangle_int_t    *extents,
    3361             :                  cairo_region_t                 *clip_region)
    3362             : {
    3363           0 :     const cairo_pattern_t *mask_pattern = closure;
    3364           0 :     pixman_image_t *src, *mask = NULL;
    3365           0 :     int src_x = 0, src_y = 0;
    3366           0 :     int mask_x = 0, mask_y = 0;
    3367             : 
    3368           0 :     if (src_pattern != NULL) {
    3369           0 :         src = _pixman_image_for_pattern (src_pattern, FALSE, extents, &src_x, &src_y);
    3370           0 :         if (unlikely (src == NULL))
    3371           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3372             : 
    3373           0 :         mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, &mask_x, &mask_y);
    3374           0 :         if (unlikely (mask == NULL)) {
    3375           0 :             pixman_image_unref (src);
    3376           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3377             :         }
    3378             : 
    3379           0 :         if (mask_pattern->has_component_alpha)
    3380           0 :             pixman_image_set_component_alpha (mask, TRUE);
    3381             :     } else {
    3382           0 :         src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, &src_x, &src_y);
    3383           0 :         if (unlikely (src == NULL))
    3384           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3385             :     }
    3386             : 
    3387           0 :     pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
    3388           0 :                               extents->x + src_x,  extents->y + src_y,
    3389           0 :                               extents->x + mask_x, extents->y + mask_y,
    3390           0 :                               extents->x - dst_x,  extents->y - dst_y,
    3391             :                               extents->width,      extents->height);
    3392             : 
    3393           0 :     if (mask != NULL)
    3394           0 :         pixman_image_unref (mask);
    3395           0 :     pixman_image_unref (src);
    3396             : 
    3397           0 :     return CAIRO_STATUS_SUCCESS;
    3398             : }
    3399             : 
    3400             : static cairo_int_status_t
    3401           0 : _cairo_image_surface_mask (void                         *abstract_surface,
    3402             :                            cairo_operator_t              op,
    3403             :                            const cairo_pattern_t        *source,
    3404             :                            const cairo_pattern_t        *mask,
    3405             :                            cairo_clip_t                 *clip)
    3406             : {
    3407           0 :     cairo_image_surface_t *surface = abstract_surface;
    3408             :     cairo_composite_rectangles_t extents;
    3409             :     cairo_clip_t local_clip;
    3410           0 :     cairo_bool_t have_clip = FALSE;
    3411             :     cairo_status_t status;
    3412             : 
    3413             :     cairo_rectangle_int_t rect;
    3414           0 :     rect.x = rect.y = 0;
    3415           0 :     rect.width = surface->width;
    3416           0 :     rect.height = surface->height;
    3417             : 
    3418           0 :     status = _cairo_composite_rectangles_init_for_mask (&extents,
    3419             :                                                         &rect,
    3420             :                                                         op, source, mask, clip);
    3421           0 :     if (unlikely (status))
    3422           0 :         return status;
    3423             : 
    3424           0 :     if (_cairo_clip_contains_extents (clip, &extents))
    3425           0 :         clip = NULL;
    3426             : 
    3427           0 :     if (clip != NULL && extents.is_bounded) {
    3428           0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
    3429           0 :         status = _cairo_clip_rectangle (clip, &extents.bounded);
    3430           0 :         if (unlikely (status)) {
    3431           0 :             _cairo_clip_fini (&local_clip);
    3432           0 :             return status;
    3433             :         }
    3434             : 
    3435           0 :         have_clip = TRUE;
    3436             :     }
    3437             : 
    3438           0 :     status = _clip_and_composite (surface, op, source,
    3439             :                                   _composite_mask, (void *) mask,
    3440             :                                   &extents, clip);
    3441             : 
    3442           0 :     if (have_clip)
    3443           0 :         _cairo_clip_fini (&local_clip);
    3444             : 
    3445           0 :     return status;
    3446             : }
    3447             : 
    3448             : typedef struct {
    3449             :     cairo_polygon_t             *polygon;
    3450             :     cairo_fill_rule_t            fill_rule;
    3451             :     cairo_antialias_t            antialias;
    3452             : } composite_spans_info_t;
    3453             : 
    3454             : //#define USE_BOTOR_SCAN_CONVERTER
    3455             : static cairo_status_t
    3456           0 : _composite_spans (void                          *closure,
    3457             :                   pixman_image_t                *dst,
    3458             :                   pixman_format_code_t           dst_format,
    3459             :                   cairo_operator_t               op,
    3460             :                   const cairo_pattern_t         *pattern,
    3461             :                   int                            dst_x,
    3462             :                   int                            dst_y,
    3463             :                   const cairo_rectangle_int_t   *extents,
    3464             :                   cairo_region_t                *clip_region)
    3465             : {
    3466             :     uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
    3467           0 :     composite_spans_info_t *info = closure;
    3468             :     cairo_image_surface_span_renderer_t renderer;
    3469             : #if USE_BOTOR_SCAN_CONVERTER
    3470             :     cairo_box_t box;
    3471             :     cairo_botor_scan_converter_t converter;
    3472             : #else
    3473             :     cairo_scan_converter_t *converter;
    3474             : #endif
    3475             :     pixman_image_t *mask;
    3476             :     cairo_status_t status;
    3477             : 
    3478             : #if USE_BOTOR_SCAN_CONVERTER
    3479             :     box.p1.x = _cairo_fixed_from_int (extents->x);
    3480             :     box.p1.y = _cairo_fixed_from_int (extents->y);
    3481             :     box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
    3482             :     box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
    3483             :     _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
    3484             :     status = converter.base.add_polygon (&converter.base, info->polygon);
    3485             : #else
    3486           0 :     converter = _cairo_tor_scan_converter_create (extents->x, extents->y,
    3487           0 :                                                   extents->x + extents->width,
    3488           0 :                                                   extents->y + extents->height,
    3489             :                                                   info->fill_rule);
    3490           0 :     status = converter->add_polygon (converter, info->polygon);
    3491             : #endif
    3492           0 :     if (unlikely (status))
    3493           0 :         goto CLEANUP_CONVERTER;
    3494             : 
    3495             :     /* TODO: support rendering to A1 surfaces (or: go add span
    3496             :      * compositing to pixman.) */
    3497             : 
    3498           0 :     if (pattern == NULL &&
    3499           0 :         dst_format == PIXMAN_a8 &&
    3500             :         op == CAIRO_OPERATOR_SOURCE)
    3501             :     {
    3502           0 :         mask = dst;
    3503           0 :         dst = NULL;
    3504             :     }
    3505             :     else
    3506             :     {
    3507           0 :         int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8);
    3508           0 :         uint8_t *data = mask_buf;
    3509             : 
    3510           0 :         if (extents->height * stride <= (int) sizeof (mask_buf))
    3511           0 :             memset (data, 0, extents->height * stride);
    3512             :         else
    3513           0 :             data = NULL, stride = 0;
    3514             : 
    3515           0 :         mask = pixman_image_create_bits (PIXMAN_a8,
    3516             :                                          extents->width,
    3517             :                                          extents->height,
    3518             :                                          (uint32_t *) data,
    3519             :                                          stride);
    3520           0 :         if (unlikely (mask == NULL)) {
    3521           0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3522           0 :             goto CLEANUP_CONVERTER;
    3523             :         }
    3524             :     }
    3525             : 
    3526           0 :     renderer.base.render_rows = _cairo_image_surface_span;
    3527           0 :     renderer.mask_stride = pixman_image_get_stride (mask);
    3528           0 :     renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
    3529           0 :     if (dst != NULL)
    3530           0 :         renderer.mask_data -= extents->y * renderer.mask_stride + extents->x;
    3531             :     else
    3532           0 :         renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
    3533             : 
    3534             : #if USE_BOTOR_SCAN_CONVERTER
    3535             :     status = converter.base.generate (&converter.base, &renderer.base);
    3536             : #else
    3537           0 :     status = converter->generate (converter, &renderer.base);
    3538             : #endif
    3539           0 :     if (unlikely (status))
    3540           0 :         goto CLEANUP_RENDERER;
    3541             : 
    3542           0 :     if (dst != NULL) {
    3543             :         pixman_image_t *src;
    3544             :         int src_x, src_y;
    3545             : 
    3546           0 :         src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
    3547           0 :         if (unlikely (src == NULL)) {
    3548           0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3549           0 :             goto CLEANUP_RENDERER;
    3550             :         }
    3551             : 
    3552           0 :         pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
    3553           0 :                                   extents->x + src_x, extents->y + src_y,
    3554             :                                   0, 0, /* mask.x, mask.y */
    3555           0 :                                   extents->x - dst_x, extents->y - dst_y,
    3556             :                                   extents->width, extents->height);
    3557           0 :         pixman_image_unref (src);
    3558             :     }
    3559             : 
    3560             :  CLEANUP_RENDERER:
    3561           0 :     if (dst != NULL)
    3562           0 :         pixman_image_unref (mask);
    3563             :  CLEANUP_CONVERTER:
    3564             : #if USE_BOTOR_SCAN_CONVERTER
    3565             :     converter.base.destroy (&converter.base);
    3566             : #else
    3567           0 :     converter->destroy (converter);
    3568             : #endif
    3569           0 :     return status;
    3570             : }
    3571             : 
    3572             : static cairo_status_t
    3573           0 : _clip_and_composite_polygon (cairo_image_surface_t *dst,
    3574             :                              cairo_operator_t op,
    3575             :                              const cairo_pattern_t *src,
    3576             :                              cairo_polygon_t *polygon,
    3577             :                              cairo_fill_rule_t fill_rule,
    3578             :                              cairo_antialias_t antialias,
    3579             :                              cairo_composite_rectangles_t *extents,
    3580             :                              cairo_clip_t *clip)
    3581             : {
    3582             :     cairo_status_t status;
    3583             : 
    3584           0 :     if (polygon->num_edges == 0) {
    3585             :         cairo_traps_t traps;
    3586             : 
    3587           0 :         if (extents->is_bounded)
    3588           0 :             return CAIRO_STATUS_SUCCESS;
    3589             : 
    3590           0 :         _cairo_traps_init (&traps);
    3591           0 :         status = _clip_and_composite_trapezoids (dst, op, src,
    3592             :                                                  &traps, antialias,
    3593             :                                                  extents, clip);
    3594           0 :         _cairo_traps_fini (&traps);
    3595             : 
    3596           0 :         return status;
    3597             :     }
    3598             : 
    3599           0 :     if (_cairo_operator_bounded_by_mask(op)) {
    3600           0 :         _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
    3601           0 :         if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
    3602           0 :             return CAIRO_STATUS_SUCCESS;
    3603             :     }
    3604             : 
    3605           0 :     if (antialias != CAIRO_ANTIALIAS_NONE) {
    3606             :         composite_spans_info_t info;
    3607             : 
    3608           0 :         info.polygon = polygon;
    3609           0 :         info.fill_rule = fill_rule;
    3610           0 :         info.antialias = antialias;
    3611             : 
    3612           0 :         status = _clip_and_composite (dst, op, src,
    3613             :                                       _composite_spans, &info,
    3614             :                                       extents, clip);
    3615             :     } else {
    3616             :         cairo_traps_t traps;
    3617             : 
    3618           0 :         _cairo_traps_init (&traps);
    3619             : 
    3620             :         /* Fall back to trapezoid fills. */
    3621           0 :         status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
    3622             :                                                             polygon,
    3623             :                                                             fill_rule);
    3624           0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
    3625           0 :             status = _clip_and_composite_trapezoids (dst, op, src,
    3626             :                                                      &traps, antialias,
    3627             :                                                      extents, clip);
    3628             :         }
    3629             : 
    3630           0 :         _cairo_traps_fini (&traps);
    3631             :     }
    3632             : 
    3633           0 :     return status;
    3634             : }
    3635             : 
    3636             : static cairo_int_status_t
    3637           0 : _cairo_image_surface_stroke (void                       *abstract_surface,
    3638             :                              cairo_operator_t            op,
    3639             :                              const cairo_pattern_t      *source,
    3640             :                              cairo_path_fixed_t         *path,
    3641             :                              const cairo_stroke_style_t *style,
    3642             :                              const cairo_matrix_t       *ctm,
    3643             :                              const cairo_matrix_t       *ctm_inverse,
    3644             :                              double                      tolerance,
    3645             :                              cairo_antialias_t           antialias,
    3646             :                              cairo_clip_t               *clip)
    3647             : {
    3648           0 :     cairo_image_surface_t *surface = abstract_surface;
    3649             :     cairo_composite_rectangles_t extents;
    3650           0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
    3651           0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
    3652             :     cairo_clip_t local_clip;
    3653           0 :     cairo_bool_t have_clip = FALSE;
    3654             :     cairo_status_t status;
    3655             : 
    3656             :     cairo_rectangle_int_t rect;
    3657           0 :     rect.x = rect.y = 0;
    3658           0 :     rect.width = surface->width;
    3659           0 :     rect.height = surface->height;
    3660             : 
    3661           0 :     status = _cairo_composite_rectangles_init_for_stroke (&extents,
    3662             :                                                           &rect,
    3663             :                                                           op, source,
    3664             :                                                           path, style, ctm,
    3665             :                                                           clip);
    3666           0 :     if (unlikely (status))
    3667           0 :         return status;
    3668             : 
    3669           0 :     if (_cairo_clip_contains_extents (clip, &extents))
    3670           0 :         clip = NULL;
    3671             : 
    3672           0 :     if (clip != NULL) {
    3673           0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
    3674           0 :         have_clip = TRUE;
    3675             :     }
    3676             : 
    3677           0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
    3678           0 :     if (unlikely (status)) {
    3679           0 :         if (have_clip)
    3680           0 :             _cairo_clip_fini (&local_clip);
    3681             : 
    3682           0 :         return status;
    3683             :     }
    3684             : 
    3685           0 :     status = CAIRO_INT_STATUS_UNSUPPORTED;
    3686           0 :     if (path->is_rectilinear) {
    3687             :         cairo_boxes_t boxes;
    3688             : 
    3689           0 :         _cairo_boxes_init (&boxes);
    3690           0 :         _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
    3691             : 
    3692           0 :         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
    3693             :                                                                 style,
    3694             :                                                                 ctm,
    3695             :                                                                 &boxes);
    3696           0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
    3697           0 :             status = _clip_and_composite_boxes (surface, op, source,
    3698             :                                                 &boxes, antialias,
    3699             :                                                 &extents, clip);
    3700             :         }
    3701             : 
    3702           0 :         _cairo_boxes_fini (&boxes);
    3703             :     }
    3704             : 
    3705           0 :     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
    3706             :         cairo_polygon_t polygon;
    3707             : 
    3708           0 :         _cairo_polygon_init (&polygon);
    3709           0 :         _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
    3710             : 
    3711           0 :         status = _cairo_path_fixed_stroke_to_polygon (path,
    3712             :                                                       style,
    3713             :                                                       ctm, ctm_inverse,
    3714             :                                                       tolerance,
    3715             :                                                       &polygon);
    3716           0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
    3717           0 :             status = _clip_and_composite_polygon (surface, op, source, &polygon,
    3718             :                                                   CAIRO_FILL_RULE_WINDING, antialias,
    3719             :                                                   &extents, clip);
    3720             :         }
    3721             : 
    3722           0 :         _cairo_polygon_fini (&polygon);
    3723             :     }
    3724             : 
    3725           0 :     if (clip_boxes != boxes_stack)
    3726           0 :         free (clip_boxes);
    3727             : 
    3728           0 :     if (have_clip)
    3729           0 :         _cairo_clip_fini (&local_clip);
    3730             : 
    3731           0 :     return status;
    3732             : }
    3733             : 
    3734             : static cairo_int_status_t
    3735           0 : _cairo_image_surface_fill (void                         *abstract_surface,
    3736             :                            cairo_operator_t              op,
    3737             :                            const cairo_pattern_t        *source,
    3738             :                            cairo_path_fixed_t           *path,
    3739             :                            cairo_fill_rule_t             fill_rule,
    3740             :                            double                        tolerance,
    3741             :                            cairo_antialias_t             antialias,
    3742             :                            cairo_clip_t                 *clip)
    3743             : {
    3744           0 :     cairo_image_surface_t *surface = abstract_surface;
    3745             :     cairo_composite_rectangles_t extents;
    3746           0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
    3747             :     cairo_clip_t local_clip;
    3748           0 :     cairo_bool_t have_clip = FALSE;
    3749           0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
    3750             :     cairo_status_t status;
    3751             : 
    3752             :     cairo_rectangle_int_t rect;
    3753           0 :     rect.x = rect.y = 0;
    3754           0 :     rect.width = surface->width;
    3755           0 :     rect.height = surface->height;
    3756             : 
    3757           0 :     status = _cairo_composite_rectangles_init_for_fill (&extents,
    3758             :                                                         &rect,
    3759             :                                                         op, source, path,
    3760             :                                                         clip);
    3761           0 :     if (unlikely (status))
    3762           0 :         return status;
    3763             : 
    3764           0 :     if (_cairo_clip_contains_extents (clip, &extents))
    3765           0 :         clip = NULL;
    3766             : 
    3767           0 :     if (extents.is_bounded && clip != NULL) {
    3768             :         cairo_clip_path_t *clip_path;
    3769             : 
    3770           0 :         if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
    3771           0 :             _cairo_path_fixed_equal (&clip_path->path, path))
    3772             :         {
    3773           0 :             clip = NULL;
    3774             :         }
    3775             :     }
    3776             : 
    3777           0 :     if (clip != NULL) {
    3778           0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
    3779           0 :         have_clip = TRUE;
    3780             :     }
    3781             : 
    3782           0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
    3783           0 :     if (unlikely (status)) {
    3784           0 :         if (have_clip)
    3785           0 :             _cairo_clip_fini (&local_clip);
    3786             : 
    3787           0 :         return status;
    3788             :     }
    3789             : 
    3790           0 :     if (_cairo_path_fixed_is_rectilinear_fill (path)) {
    3791             :         cairo_boxes_t boxes;
    3792             : 
    3793           0 :         _cairo_boxes_init (&boxes);
    3794           0 :         _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
    3795             : 
    3796           0 :         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
    3797             :                                                               fill_rule,
    3798             :                                                               &boxes);
    3799           0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
    3800           0 :             status = _clip_and_composite_boxes (surface, op, source,
    3801             :                                                 &boxes, antialias,
    3802             :                                                 &extents, clip);
    3803             :         }
    3804             : 
    3805           0 :         _cairo_boxes_fini (&boxes);
    3806             :     } else {
    3807             :         cairo_polygon_t polygon;
    3808             : 
    3809           0 :         assert (! path->is_empty_fill);
    3810             : 
    3811           0 :         _cairo_polygon_init (&polygon);
    3812           0 :         _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
    3813             : 
    3814           0 :         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
    3815           0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
    3816           0 :             status = _clip_and_composite_polygon (surface, op, source, &polygon,
    3817             :                                                   fill_rule, antialias,
    3818             :                                                   &extents, clip);
    3819             :         }
    3820             : 
    3821           0 :         _cairo_polygon_fini (&polygon);
    3822             :     }
    3823             : 
    3824           0 :     if (clip_boxes != boxes_stack)
    3825           0 :         free (clip_boxes);
    3826             : 
    3827           0 :     if (have_clip)
    3828           0 :         _cairo_clip_fini (&local_clip);
    3829             : 
    3830           0 :     return status;
    3831             : }
    3832             : 
    3833             : typedef struct {
    3834             :     cairo_scaled_font_t *font;
    3835             :     cairo_glyph_t *glyphs;
    3836             :     int num_glyphs;
    3837             : } composite_glyphs_info_t;
    3838             : 
    3839             : static cairo_status_t
    3840           0 : _composite_glyphs_via_mask (void                        *closure,
    3841             :                             pixman_image_t              *dst,
    3842             :                             pixman_format_code_t         dst_format,
    3843             :                             cairo_operator_t             op,
    3844             :                             const cairo_pattern_t       *pattern,
    3845             :                             int                          dst_x,
    3846             :                             int                          dst_y,
    3847             :                             const cairo_rectangle_int_t *extents,
    3848             :                             cairo_region_t              *clip_region)
    3849             : {
    3850           0 :     composite_glyphs_info_t *info = closure;
    3851           0 :     cairo_scaled_font_t *font = info->font;
    3852           0 :     cairo_glyph_t *glyphs = info->glyphs;
    3853           0 :     int num_glyphs = info->num_glyphs;
    3854           0 :     pixman_image_t *mask = NULL;
    3855             :     pixman_image_t *src;
    3856             :     pixman_image_t *white;
    3857           0 :     pixman_format_code_t mask_format = 0; /* silence gcc */
    3858             :     cairo_status_t status;
    3859             :     int src_x, src_y;
    3860             :     int i;
    3861             : 
    3862           0 :     src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
    3863           0 :     if (unlikely (src == NULL))
    3864           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3865             : 
    3866           0 :     white = _pixman_white_image ();
    3867           0 :     if (unlikely (white == NULL)) {
    3868           0 :         pixman_image_unref (src);
    3869           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3870             :     }
    3871             : 
    3872           0 :     _cairo_scaled_font_freeze_cache (font);
    3873             : 
    3874           0 :     for (i = 0; i < num_glyphs; i++) {
    3875             :         int x, y;
    3876             :         cairo_image_surface_t *glyph_surface;
    3877             :         cairo_scaled_glyph_t *scaled_glyph;
    3878             : 
    3879           0 :         status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
    3880             :                                              CAIRO_SCALED_GLYPH_INFO_SURFACE,
    3881             :                                              &scaled_glyph);
    3882             : 
    3883           0 :         if (unlikely (status))
    3884           0 :             goto CLEANUP;
    3885             : 
    3886           0 :         glyph_surface = scaled_glyph->surface;
    3887             : 
    3888           0 :         if (glyph_surface->width == 0 || glyph_surface->height == 0)
    3889           0 :             continue;
    3890             : 
    3891             :         /* To start, create the mask using the format from the first
    3892             :          * glyph. Later we'll deal with different formats. */
    3893           0 :         if (mask == NULL) {
    3894           0 :             mask_format = glyph_surface->pixman_format;
    3895           0 :             mask = pixman_image_create_bits (mask_format,
    3896             :                                              extents->width, extents->height,
    3897             :                                              NULL, 0);
    3898           0 :             if (unlikely (mask == NULL)) {
    3899           0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3900           0 :                 goto CLEANUP;
    3901             :             }
    3902             : 
    3903           0 :             if (PIXMAN_FORMAT_RGB (mask_format))
    3904           0 :                 pixman_image_set_component_alpha (mask, TRUE);
    3905             :         }
    3906             : 
    3907             :         /* If we have glyphs of different formats, we "upgrade" the mask
    3908             :          * to the wider of the formats. */
    3909           0 :         if (glyph_surface->pixman_format != mask_format &&
    3910           0 :             PIXMAN_FORMAT_BPP (mask_format) <
    3911           0 :             PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
    3912             :         {
    3913             :             pixman_image_t *new_mask;
    3914             : 
    3915           0 :             mask_format = glyph_surface->pixman_format;
    3916           0 :             new_mask = pixman_image_create_bits (mask_format,
    3917             :                                                  extents->width, extents->height,
    3918             :                                                  NULL, 0);
    3919           0 :             if (unlikely (new_mask == NULL)) {
    3920           0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3921           0 :                 goto CLEANUP;
    3922             :             }
    3923             : 
    3924           0 :             pixman_image_composite32 (PIXMAN_OP_SRC,
    3925             :                                       white, mask, new_mask,
    3926             :                                       0, 0, 0, 0, 0, 0,
    3927             :                                       extents->width, extents->height);
    3928             : 
    3929           0 :             pixman_image_unref (mask);
    3930           0 :             mask = new_mask;
    3931           0 :             if (PIXMAN_FORMAT_RGB (mask_format))
    3932           0 :                 pixman_image_set_component_alpha (mask, TRUE);
    3933             :         }
    3934             : 
    3935             :         /* round glyph locations to the nearest pixel */
    3936             :         /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
    3937           0 :         x = _cairo_lround (glyphs[i].x -
    3938           0 :                            glyph_surface->base.device_transform.x0);
    3939           0 :         y = _cairo_lround (glyphs[i].y -
    3940           0 :                            glyph_surface->base.device_transform.y0);
    3941           0 :         if (glyph_surface->pixman_format == mask_format) {
    3942           0 :             pixman_image_composite32 (PIXMAN_OP_ADD,
    3943             :                                       glyph_surface->pixman_image, NULL, mask,
    3944             :                                       0, 0, 0, 0,
    3945           0 :                                       x - extents->x, y - extents->y,
    3946             :                                       glyph_surface->width,
    3947             :                                       glyph_surface->height);
    3948             :         } else {
    3949           0 :             pixman_image_composite32 (PIXMAN_OP_ADD,
    3950             :                                       white, glyph_surface->pixman_image, mask,
    3951             :                                       0, 0, 0, 0,
    3952           0 :                                       x - extents->x, y - extents->y,
    3953             :                                       glyph_surface->width,
    3954             :                                       glyph_surface->height);
    3955             :         }
    3956             :     }
    3957             : 
    3958           0 :     pixman_image_composite32 (_pixman_operator (op),
    3959             :                               src, mask, dst,
    3960           0 :                               extents->x + src_x, extents->y + src_y,
    3961             :                               0, 0,
    3962           0 :                               extents->x - dst_x, extents->y - dst_y,
    3963             :                               extents->width,     extents->height);
    3964             : 
    3965             : CLEANUP:
    3966           0 :     _cairo_scaled_font_thaw_cache (font);
    3967           0 :     if (mask != NULL)
    3968           0 :         pixman_image_unref (mask);
    3969           0 :     pixman_image_unref (src);
    3970           0 :     pixman_image_unref (white);
    3971             : 
    3972           0 :     return status;
    3973             : }
    3974             : 
    3975             : static cairo_status_t
    3976           0 : _composite_glyphs (void                         *closure,
    3977             :                    pixman_image_t               *dst,
    3978             :                    pixman_format_code_t          dst_format,
    3979             :                    cairo_operator_t              op,
    3980             :                    const cairo_pattern_t        *pattern,
    3981             :                    int                           dst_x,
    3982             :                    int                           dst_y,
    3983             :                    const cairo_rectangle_int_t  *extents,
    3984             :                    cairo_region_t               *clip_region)
    3985             : {
    3986           0 :     composite_glyphs_info_t *info = closure;
    3987             :     cairo_scaled_glyph_t *glyph_cache[64];
    3988           0 :     pixman_op_t pixman_op = _pixman_operator (op);
    3989           0 :     pixman_image_t *src = NULL;
    3990           0 :     int src_x = 0, src_y = 0;
    3991             :     cairo_status_t status;
    3992             :     int i;
    3993             : 
    3994           0 :     memset (glyph_cache, 0, sizeof (glyph_cache));
    3995           0 :     status = CAIRO_STATUS_SUCCESS;
    3996             : 
    3997           0 :     _cairo_scaled_font_freeze_cache (info->font);
    3998           0 :     for (i = 0; i < info->num_glyphs; i++) {
    3999             :         int x, y;
    4000             :         cairo_image_surface_t *glyph_surface;
    4001             :         cairo_scaled_glyph_t *scaled_glyph;
    4002           0 :         unsigned long glyph_index = info->glyphs[i].index;
    4003           0 :         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
    4004             : 
    4005           0 :         scaled_glyph = glyph_cache[cache_index];
    4006           0 :         if (scaled_glyph == NULL ||
    4007           0 :             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
    4008             :         {
    4009           0 :             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
    4010             :                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
    4011             :                                                  &scaled_glyph);
    4012             : 
    4013           0 :             if (unlikely (status))
    4014           0 :                 break;
    4015             : 
    4016           0 :             glyph_cache[cache_index] = scaled_glyph;
    4017             :         }
    4018             : 
    4019           0 :         glyph_surface = scaled_glyph->surface;
    4020           0 :         if (glyph_surface->width && glyph_surface->height) {
    4021             :             int x1, y1, x2, y2;
    4022             : 
    4023             :             /* round glyph locations to the nearest pixel */
    4024             :             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
    4025           0 :             x = _cairo_lround (info->glyphs[i].x -
    4026           0 :                                glyph_surface->base.device_transform.x0);
    4027           0 :             y = _cairo_lround (info->glyphs[i].y -
    4028           0 :                                glyph_surface->base.device_transform.y0);
    4029             : 
    4030           0 :             x1 = x;
    4031           0 :             if (x1 < extents->x)
    4032           0 :                 x1 = extents->x;
    4033           0 :             x2 = x + glyph_surface->width;
    4034           0 :             if (x2 > extents->x + extents->width)
    4035           0 :                 x2 = extents->x + extents->width;
    4036             : 
    4037           0 :             y1 = y;
    4038           0 :             if (y1 < extents->y)
    4039           0 :                 y1 = extents->y;
    4040           0 :             y2 = y + glyph_surface->height;
    4041           0 :             if (y2 > extents->y + extents->height)
    4042           0 :                 y2 = extents->y + extents->height;
    4043             : 
    4044           0 :             if (glyph_surface->format == CAIRO_FORMAT_A8 ||
    4045           0 :                 glyph_surface->format == CAIRO_FORMAT_A1 ||
    4046           0 :                 (glyph_surface->format == CAIRO_FORMAT_ARGB32 &&
    4047           0 :                  pixman_image_get_component_alpha (glyph_surface->pixman_image)))
    4048             :             {
    4049           0 :                 if (unlikely (src == NULL)) {
    4050           0 :                     if (pattern != NULL) {
    4051           0 :                         src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
    4052           0 :                         src_x -= dst_x;
    4053           0 :                         src_y -= dst_y;
    4054             :                     } else {
    4055           0 :                         src = _pixman_white_image ();
    4056             :                     }
    4057           0 :                     if (unlikely (src == NULL)) {
    4058           0 :                         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4059           0 :                         break;
    4060             :                     }
    4061             :                 }
    4062             : 
    4063           0 :                 pixman_image_composite32 (pixman_op,
    4064             :                                           src, glyph_surface->pixman_image, dst,
    4065             :                                           x1 + src_x, y1 + src_y,
    4066             :                                           x1 - x, y1 - y,
    4067             :                                           x1 - dst_x, y1 - dst_y,
    4068             :                                           x2 - x1, y2 - y1);
    4069             :             } else {
    4070           0 :                 pixman_image_composite32 (pixman_op,
    4071             :                                           glyph_surface->pixman_image, NULL, dst,
    4072             :                                           x1 - x, y1 - y,
    4073             :                                           0, 0,
    4074             :                                           x1 - dst_x, y1 - dst_y,
    4075             :                                           x2 - x1, y2 - y1);
    4076             :             }
    4077             :         }
    4078             :     }
    4079           0 :     _cairo_scaled_font_thaw_cache (info->font);
    4080             : 
    4081           0 :     if (src != NULL)
    4082           0 :         pixman_image_unref (src);
    4083             : 
    4084           0 :     return status;
    4085             : }
    4086             : 
    4087             : static cairo_int_status_t
    4088           0 : _cairo_image_surface_glyphs (void                       *abstract_surface,
    4089             :                              cairo_operator_t            op,
    4090             :                              const cairo_pattern_t      *source,
    4091             :                              cairo_glyph_t              *glyphs,
    4092             :                              int                         num_glyphs,
    4093             :                              cairo_scaled_font_t        *scaled_font,
    4094             :                              cairo_clip_t               *clip,
    4095             :                              int *num_remaining)
    4096             : {
    4097           0 :     cairo_image_surface_t *surface = abstract_surface;
    4098             :     cairo_composite_rectangles_t extents;
    4099             :     composite_glyphs_info_t glyph_info;
    4100             :     cairo_clip_t local_clip;
    4101           0 :     cairo_bool_t have_clip = FALSE;
    4102             : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    4103             :     // For performance reasons we don't want to use two passes for overlapping glyphs
    4104             :     // on mobile
    4105             :     cairo_bool_t overlap = FALSE;
    4106             : #else
    4107             :     cairo_bool_t overlap;
    4108             : #endif
    4109             :     cairo_status_t status;
    4110             : 
    4111             :     cairo_rectangle_int_t rect;
    4112           0 :     rect.x = rect.y = 0;
    4113           0 :     rect.width = surface->width;
    4114           0 :     rect.height = surface->height;
    4115             : 
    4116           0 :     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
    4117             :                                                           &rect,
    4118             :                                                           op, source,
    4119             :                                                           scaled_font,
    4120             :                                                           glyphs, num_glyphs,
    4121             :                                                           clip,
    4122             : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    4123             :                                                           NULL);
    4124             : #else
    4125             :                                                           &overlap);
    4126             : #endif
    4127             : 
    4128           0 :     if (unlikely (status))
    4129           0 :         return status;
    4130             : 
    4131           0 :     if (_cairo_clip_contains_rectangle (clip, &extents.mask))
    4132           0 :         clip = NULL;
    4133             : 
    4134           0 :     if (clip != NULL && extents.is_bounded) {
    4135           0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
    4136           0 :         status = _cairo_clip_rectangle (clip, &extents.bounded);
    4137           0 :         if (unlikely (status))
    4138           0 :             return status;
    4139             : 
    4140           0 :         have_clip = TRUE;
    4141             :     }
    4142             : 
    4143           0 :     glyph_info.font = scaled_font;
    4144           0 :     glyph_info.glyphs = glyphs;
    4145           0 :     glyph_info.num_glyphs = num_glyphs;
    4146             : 
    4147           0 :     status = _clip_and_composite (surface, op, source,
    4148           0 :                                   overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs,
    4149             :                                   &glyph_info,
    4150             :                                   &extents, clip);
    4151             : 
    4152           0 :     if (have_clip)
    4153           0 :         _cairo_clip_fini (&local_clip);
    4154             : 
    4155           0 :     *num_remaining = 0;
    4156           0 :     return status;
    4157             : }
    4158             : 
    4159             : static cairo_bool_t
    4160           0 : _cairo_image_surface_get_extents (void                    *abstract_surface,
    4161             :                                   cairo_rectangle_int_t   *rectangle)
    4162             : {
    4163           0 :     cairo_image_surface_t *surface = abstract_surface;
    4164             : 
    4165           0 :     rectangle->x = 0;
    4166           0 :     rectangle->y = 0;
    4167           0 :     rectangle->width  = surface->width;
    4168           0 :     rectangle->height = surface->height;
    4169             : 
    4170           0 :     return TRUE;
    4171             : }
    4172             : 
    4173             : static void
    4174           2 : _cairo_image_surface_get_font_options (void                  *abstract_surface,
    4175             :                                        cairo_font_options_t  *options)
    4176             : {
    4177           2 :     _cairo_font_options_init_default (options);
    4178             : 
    4179           2 :     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
    4180           2 :     _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
    4181           2 : }
    4182             : 
    4183             : /* legacy interface kept for compatibility until surface-fallback is removed */
    4184             : static cairo_status_t
    4185           0 : _cairo_image_surface_acquire_dest_image (void                    *abstract_surface,
    4186             :                                          cairo_rectangle_int_t   *interest_rect,
    4187             :                                          cairo_image_surface_t  **image_out,
    4188             :                                          cairo_rectangle_int_t   *image_rect_out,
    4189             :                                          void                   **image_extra)
    4190             : {
    4191           0 :     cairo_image_surface_t *surface = abstract_surface;
    4192             : 
    4193           0 :     image_rect_out->x = 0;
    4194           0 :     image_rect_out->y = 0;
    4195           0 :     image_rect_out->width = surface->width;
    4196           0 :     image_rect_out->height = surface->height;
    4197             : 
    4198           0 :     *image_out = surface;
    4199           0 :     *image_extra = NULL;
    4200             : 
    4201           0 :     return CAIRO_STATUS_SUCCESS;
    4202             : }
    4203             : 
    4204             : static void
    4205           0 : _cairo_image_surface_release_dest_image (void                    *abstract_surface,
    4206             :                                         cairo_rectangle_int_t   *interest_rect,
    4207             :                                         cairo_image_surface_t   *image,
    4208             :                                         cairo_rectangle_int_t   *image_rect,
    4209             :                                         void                    *image_extra)
    4210             : {
    4211           0 : }
    4212             : 
    4213             : static cairo_status_t
    4214           0 : _cairo_image_surface_clone_similar (void               *abstract_surface,
    4215             :                                     cairo_surface_t     *src,
    4216             :                                     int                  src_x,
    4217             :                                     int                  src_y,
    4218             :                                     int                  width,
    4219             :                                     int                  height,
    4220             :                                     int                 *clone_offset_x,
    4221             :                                     int                 *clone_offset_y,
    4222             :                                     cairo_surface_t    **clone_out)
    4223             : {
    4224           0 :     cairo_image_surface_t *surface = abstract_surface;
    4225             : 
    4226           0 :     if (src->backend == surface->base.backend) {
    4227           0 :         *clone_offset_x = *clone_offset_y = 0;
    4228           0 :         *clone_out = cairo_surface_reference (src);
    4229             : 
    4230           0 :         return CAIRO_STATUS_SUCCESS;
    4231             :     }
    4232             : 
    4233           0 :     return CAIRO_INT_STATUS_UNSUPPORTED;
    4234             : }
    4235             : 
    4236             : static cairo_int_status_t
    4237           0 : _cairo_image_surface_composite (cairo_operator_t         op,
    4238             :                                 const cairo_pattern_t   *src_pattern,
    4239             :                                 const cairo_pattern_t   *mask_pattern,
    4240             :                                 void                    *abstract_dst,
    4241             :                                 int                      src_x,
    4242             :                                 int                      src_y,
    4243             :                                 int                      mask_x,
    4244             :                                 int                      mask_y,
    4245             :                                 int                      dst_x,
    4246             :                                 int                      dst_y,
    4247             :                                 unsigned int             width,
    4248             :                                 unsigned int             height,
    4249             :                                 cairo_region_t          *clip_region)
    4250             : {
    4251           0 :     cairo_image_surface_t *dst = abstract_dst;
    4252             :     cairo_composite_rectangles_t extents;
    4253             :     pixman_image_t *src;
    4254             :     int src_offset_x, src_offset_y;
    4255             :     cairo_status_t status;
    4256             : 
    4257           0 :     if (clip_region != NULL) {
    4258           0 :         status = _cairo_image_surface_set_clip_region (dst, clip_region);
    4259           0 :         if (unlikely (status))
    4260           0 :             return status;
    4261             :     }
    4262             : 
    4263           0 :     extents.source.x = src_x;
    4264           0 :     extents.source.y = src_y;
    4265           0 :     extents.source.width  = width;
    4266           0 :     extents.source.height = height;
    4267             : 
    4268           0 :     extents.mask.x = mask_x;
    4269           0 :     extents.mask.y = mask_y;
    4270           0 :     extents.mask.width  = width;
    4271           0 :     extents.mask.height = height;
    4272             : 
    4273           0 :     extents.bounded.x = dst_x;
    4274           0 :     extents.bounded.y = dst_y;
    4275           0 :     extents.bounded.width  = width;
    4276           0 :     extents.bounded.height = height;
    4277             : 
    4278           0 :     extents.unbounded.x = 0;
    4279           0 :     extents.unbounded.y = 0;
    4280           0 :     extents.unbounded.width  = dst->width;
    4281           0 :     extents.unbounded.height = dst->height;
    4282             : 
    4283           0 :     if (clip_region != NULL) {
    4284             :         cairo_rectangle_int_t rect;
    4285             : 
    4286           0 :         cairo_region_get_extents (clip_region, &rect);
    4287           0 :         if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
    4288           0 :             return CAIRO_STATUS_SUCCESS;
    4289             :     }
    4290             : 
    4291           0 :     extents.is_bounded = _cairo_operator_bounded_by_either (op);
    4292             : 
    4293           0 :     src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, &src_offset_x, &src_offset_y);
    4294           0 :     if (unlikely (src == NULL))
    4295           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4296             : 
    4297           0 :     status = CAIRO_STATUS_SUCCESS;
    4298           0 :     if (mask_pattern != NULL) {
    4299             :         pixman_image_t *mask;
    4300             :         int mask_offset_x, mask_offset_y;
    4301             : 
    4302           0 :         mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, &mask_offset_x, &mask_offset_y);
    4303           0 :         if (unlikely (mask == NULL)) {
    4304           0 :             pixman_image_unref (src);
    4305           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4306             :         }
    4307             : 
    4308           0 :         pixman_image_composite32 (_pixman_operator (op),
    4309             :                                   src, mask, dst->pixman_image,
    4310             :                                   src_x + src_offset_x,
    4311             :                                   src_y + src_offset_y,
    4312             :                                   mask_x + mask_offset_x,
    4313             :                                   mask_y + mask_offset_y,
    4314             :                                   dst_x, dst_y, width, height);
    4315             : 
    4316           0 :         pixman_image_unref (mask);
    4317             :     } else {
    4318           0 :         pixman_image_composite32 (_pixman_operator (op),
    4319             :                                   src, NULL, dst->pixman_image,
    4320             :                                   src_x + src_offset_x,
    4321             :                                   src_y + src_offset_y,
    4322             :                                   0, 0,
    4323             :                                   dst_x, dst_y, width, height);
    4324             :     }
    4325             : 
    4326           0 :     pixman_image_unref (src);
    4327             : 
    4328           0 :     if (! extents.is_bounded)
    4329           0 :         status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
    4330             : 
    4331           0 :     if (clip_region != NULL)
    4332           0 :         _cairo_image_surface_unset_clip_region (dst);
    4333             : 
    4334           0 :     return status;
    4335             : }
    4336             : 
    4337             : static cairo_int_status_t
    4338           0 : _cairo_image_surface_fill_rectangles (void                    *abstract_surface,
    4339             :                                       cairo_operator_t         op,
    4340             :                                       const cairo_color_t     *color,
    4341             :                                       cairo_rectangle_int_t   *rects,
    4342             :                                       int                      num_rects)
    4343             : {
    4344           0 :     cairo_image_surface_t *surface = abstract_surface;
    4345             : 
    4346             :     pixman_color_t pixman_color;
    4347             :     pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
    4348           0 :     pixman_box32_t *pixman_boxes = stack_boxes;
    4349             :     int i;
    4350             : 
    4351             :     cairo_int_status_t status;
    4352             : 
    4353             :     if (CAIRO_INJECT_FAULT ())
    4354             :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4355             : 
    4356           0 :     pixman_color.red   = color->red_short;
    4357           0 :     pixman_color.green = color->green_short;
    4358           0 :     pixman_color.blue  = color->blue_short;
    4359           0 :     pixman_color.alpha = color->alpha_short;
    4360             : 
    4361           0 :     if (num_rects > ARRAY_LENGTH (stack_boxes)) {
    4362           0 :         pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t));
    4363           0 :         if (unlikely (pixman_boxes == NULL))
    4364           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4365             :     }
    4366             : 
    4367           0 :     for (i = 0; i < num_rects; i++) {
    4368           0 :         pixman_boxes[i].x1 = rects[i].x;
    4369           0 :         pixman_boxes[i].y1 = rects[i].y;
    4370           0 :         pixman_boxes[i].x2 = rects[i].x + rects[i].width;
    4371           0 :         pixman_boxes[i].y2 = rects[i].y + rects[i].height;
    4372             :     }
    4373             : 
    4374           0 :     status = CAIRO_STATUS_SUCCESS;
    4375           0 :     if (! pixman_image_fill_boxes (_pixman_operator (op),
    4376             :                                    surface->pixman_image,
    4377             :                                    &pixman_color,
    4378             :                                    num_rects,
    4379             :                                    pixman_boxes))
    4380             :     {
    4381           0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4382             :     }
    4383             : 
    4384           0 :     if (pixman_boxes != stack_boxes)
    4385           0 :         free (pixman_boxes);
    4386             : 
    4387           0 :     return status;
    4388             : }
    4389             : 
    4390             : static cairo_int_status_t
    4391           0 : _cairo_image_surface_composite_trapezoids (cairo_operator_t     op,
    4392             :                                            const cairo_pattern_t *pattern,
    4393             :                                            void                 *abstract_dst,
    4394             :                                            cairo_antialias_t    antialias,
    4395             :                                            int                  src_x,
    4396             :                                            int                  src_y,
    4397             :                                            int                  dst_x,
    4398             :                                            int                  dst_y,
    4399             :                                            unsigned int         width,
    4400             :                                            unsigned int         height,
    4401             :                                            cairo_trapezoid_t    *traps,
    4402             :                                            int                  num_traps,
    4403             :                                            cairo_region_t       *clip_region)
    4404             : {
    4405           0 :     cairo_image_surface_t       *dst = abstract_dst;
    4406             :     cairo_composite_rectangles_t extents;
    4407             :     cairo_pattern_union_t        source_pattern;
    4408             :     composite_traps_info_t       info;
    4409             :     cairo_status_t               status;
    4410             : 
    4411           0 :     if (height == 0 || width == 0)
    4412           0 :         return CAIRO_STATUS_SUCCESS;
    4413             : 
    4414             :     if (CAIRO_INJECT_FAULT ())
    4415             :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4416             : 
    4417           0 :     extents.source.x = src_x;
    4418           0 :     extents.source.y = src_y;
    4419           0 :     extents.source.width  = width;
    4420           0 :     extents.source.height = height;
    4421             : 
    4422           0 :     extents.mask.x = dst_x;
    4423           0 :     extents.mask.y = dst_y;
    4424           0 :     extents.mask.width  = width;
    4425           0 :     extents.mask.height = height;
    4426             : 
    4427           0 :     extents.bounded.x = dst_x;
    4428           0 :     extents.bounded.y = dst_y;
    4429           0 :     extents.bounded.width  = width;
    4430           0 :     extents.bounded.height = height;
    4431             : 
    4432           0 :     extents.unbounded.x = 0;
    4433           0 :     extents.unbounded.y = 0;
    4434           0 :     extents.unbounded.width  = dst->width;
    4435           0 :     extents.unbounded.height = dst->height;
    4436             : 
    4437           0 :     if (clip_region != NULL) {
    4438             :         cairo_rectangle_int_t rect;
    4439             : 
    4440           0 :         cairo_region_get_extents (clip_region, &rect);
    4441           0 :         if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
    4442           0 :             return CAIRO_STATUS_SUCCESS;
    4443             :     }
    4444             : 
    4445           0 :     extents.is_bounded = _cairo_operator_bounded_by_either (op);
    4446             : 
    4447           0 :     if (clip_region != NULL) {
    4448           0 :         status = _cairo_image_surface_set_clip_region (dst, clip_region);
    4449           0 :         if (unlikely (status))
    4450           0 :             return status;
    4451             :     }
    4452             : 
    4453           0 :     _cairo_pattern_init_static_copy (&source_pattern.base, pattern);
    4454           0 :     cairo_matrix_translate (&source_pattern.base.matrix,
    4455           0 :                             src_x - extents.bounded.x,
    4456           0 :                             src_y - extents.bounded.y);
    4457             : 
    4458           0 :     info.traps = traps;
    4459           0 :     info.num_traps = num_traps;
    4460           0 :     info.antialias = antialias;
    4461           0 :     status = _composite_traps (&info,
    4462             :                                dst->pixman_image,
    4463             :                                dst->pixman_format,
    4464             :                                op,
    4465             :                                &source_pattern.base,
    4466             :                                0, 0,
    4467             :                                &extents.bounded,
    4468             :                                clip_region);
    4469             : 
    4470           0 :     if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
    4471           0 :         status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
    4472             : 
    4473           0 :     if (clip_region != NULL)
    4474           0 :         _cairo_image_surface_unset_clip_region (dst);
    4475             : 
    4476           0 :     return status;
    4477             : }
    4478             : 
    4479             : typedef struct _legacy_image_surface_span_renderer {
    4480             :     cairo_span_renderer_t base;
    4481             : 
    4482             :     cairo_operator_t op;
    4483             :     const cairo_pattern_t *pattern;
    4484             :     cairo_antialias_t antialias;
    4485             :     cairo_region_t *clip_region;
    4486             : 
    4487             :     pixman_image_t *mask;
    4488             :     uint8_t *mask_data;
    4489             :     uint32_t mask_stride;
    4490             : 
    4491             :     cairo_image_surface_t *dst;
    4492             :     cairo_composite_rectangles_t composite_rectangles;
    4493             : } legacy_image_surface_span_renderer_t;
    4494             : 
    4495             : void
    4496           0 : _cairo_image_surface_span_render_row (
    4497             :     int                                  y,
    4498             :     const cairo_half_open_span_t        *spans,
    4499             :     unsigned                             num_spans,
    4500             :     uint8_t                             *data,
    4501             :     uint32_t                             stride)
    4502             : {
    4503             :     uint8_t *row;
    4504             :     unsigned i;
    4505             : 
    4506           0 :     if (num_spans == 0)
    4507           0 :         return;
    4508             : 
    4509           0 :     row = data + y * stride;
    4510           0 :     for (i = 0; i < num_spans - 1; i++) {
    4511           0 :         if (! spans[i].coverage)
    4512           0 :             continue;
    4513             : 
    4514             :         /* We implement setting the most common single pixel wide
    4515             :          * span case to avoid the overhead of a memset call.
    4516             :          * Open coding setting longer spans didn't show a
    4517             :          * noticeable improvement over memset.
    4518             :          */
    4519           0 :         if (spans[i+1].x == spans[i].x + 1) {
    4520           0 :             row[spans[i].x] = spans[i].coverage;
    4521             :         } else {
    4522           0 :             memset (row + spans[i].x,
    4523           0 :                     spans[i].coverage,
    4524           0 :                     spans[i+1].x - spans[i].x);
    4525             :         }
    4526             :     }
    4527             : }
    4528             : 
    4529             : static cairo_status_t
    4530           0 : _cairo_image_surface_span_renderer_render_rows (
    4531             :     void                                *abstract_renderer,
    4532             :     int                                  y,
    4533             :     int                                  height,
    4534             :     const cairo_half_open_span_t        *spans,
    4535             :     unsigned                             num_spans)
    4536             : {
    4537           0 :     legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
    4538           0 :     while (height--)
    4539           0 :         _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
    4540           0 :     return CAIRO_STATUS_SUCCESS;
    4541             : }
    4542             : 
    4543             : static void
    4544           0 : _cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
    4545             : {
    4546           0 :     legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
    4547           0 :     if (renderer == NULL)
    4548           0 :         return;
    4549             : 
    4550           0 :     pixman_image_unref (renderer->mask);
    4551             : 
    4552           0 :     free (renderer);
    4553             : }
    4554             : 
    4555             : static cairo_status_t
    4556           0 : _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
    4557             : {
    4558           0 :     legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
    4559           0 :     cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
    4560           0 :     cairo_image_surface_t *dst = renderer->dst;
    4561             :     pixman_image_t *src;
    4562             :     int src_x, src_y;
    4563             :     cairo_status_t status;
    4564             : 
    4565           0 :     if (renderer->clip_region != NULL) {
    4566           0 :         status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
    4567           0 :         if (unlikely (status))
    4568           0 :             return status;
    4569             :     }
    4570             : 
    4571           0 :     src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, &src_x, &src_y);
    4572           0 :     if (src == NULL)
    4573           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4574             : 
    4575           0 :     status = CAIRO_STATUS_SUCCESS;
    4576           0 :     pixman_image_composite32 (_pixman_operator (renderer->op),
    4577             :                               src,
    4578             :                               renderer->mask,
    4579             :                               dst->pixman_image,
    4580           0 :                               rects->bounded.x + src_x,
    4581           0 :                               rects->bounded.y + src_y,
    4582             :                               0, 0,
    4583             :                               rects->bounded.x, rects->bounded.y,
    4584             :                               rects->bounded.width, rects->bounded.height);
    4585             : 
    4586           0 :     if (! rects->is_bounded)
    4587           0 :         status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
    4588             : 
    4589           0 :     if (renderer->clip_region != NULL)
    4590           0 :          _cairo_image_surface_unset_clip_region (dst);
    4591             : 
    4592           0 :     return status;
    4593             : }
    4594             : 
    4595             : static cairo_bool_t
    4596           0 : _cairo_image_surface_check_span_renderer (cairo_operator_t        op,
    4597             :                                           const cairo_pattern_t  *pattern,
    4598             :                                           void                   *abstract_dst,
    4599             :                                           cairo_antialias_t       antialias)
    4600             : {
    4601           0 :     return TRUE;
    4602             :     (void) op;
    4603             :     (void) pattern;
    4604             :     (void) abstract_dst;
    4605             :     (void) antialias;
    4606             : }
    4607             : 
    4608             : static cairo_span_renderer_t *
    4609           0 : _cairo_image_surface_create_span_renderer (cairo_operator_t      op,
    4610             :                                            const cairo_pattern_t  *pattern,
    4611             :                                            void                 *abstract_dst,
    4612             :                                            cairo_antialias_t     antialias,
    4613             :                                            const cairo_composite_rectangles_t *rects,
    4614             :                                            cairo_region_t *clip_region)
    4615             : {
    4616           0 :     cairo_image_surface_t *dst = abstract_dst;
    4617             :     legacy_image_surface_span_renderer_t *renderer;
    4618             : 
    4619           0 :     renderer = calloc(1, sizeof(*renderer));
    4620           0 :     if (unlikely (renderer == NULL))
    4621           0 :         return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
    4622             : 
    4623           0 :     renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
    4624           0 :     renderer->base.finish = _cairo_image_surface_span_renderer_finish;
    4625           0 :     renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
    4626           0 :     renderer->op = op;
    4627           0 :     renderer->pattern = pattern;
    4628           0 :     renderer->antialias = antialias;
    4629           0 :     renderer->dst = dst;
    4630           0 :     renderer->clip_region = clip_region;
    4631             : 
    4632           0 :     renderer->composite_rectangles = *rects;
    4633             : 
    4634             :     /* TODO: support rendering to A1 surfaces (or: go add span
    4635             :      * compositing to pixman.) */
    4636           0 :     renderer->mask = pixman_image_create_bits (PIXMAN_a8,
    4637             :                                                rects->bounded.width,
    4638             :                                                rects->bounded.height,
    4639             :                                                NULL, 0);
    4640           0 :     if (renderer->mask == NULL) {
    4641           0 :         free (renderer);
    4642           0 :         return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
    4643             :     }
    4644             : 
    4645           0 :     renderer->mask_stride = pixman_image_get_stride (renderer->mask);
    4646           0 :     renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
    4647             : 
    4648           0 :     return &renderer->base;
    4649             : }
    4650             : 
    4651             : /**
    4652             :  * _cairo_surface_is_image:
    4653             :  * @surface: a #cairo_surface_t
    4654             :  *
    4655             :  * Checks if a surface is an #cairo_image_surface_t
    4656             :  *
    4657             :  * Return value: %TRUE if the surface is an image surface
    4658             :  **/
    4659             : cairo_bool_t
    4660           0 : _cairo_surface_is_image (const cairo_surface_t *surface)
    4661             : {
    4662           0 :     return surface->backend == &_cairo_image_surface_backend;
    4663             : }
    4664             : 
    4665             : const cairo_surface_backend_t _cairo_image_surface_backend = {
    4666             :     CAIRO_SURFACE_TYPE_IMAGE,
    4667             :     _cairo_image_surface_create_similar,
    4668             :     _cairo_image_surface_finish,
    4669             :     _cairo_image_surface_acquire_source_image,
    4670             :     _cairo_image_surface_release_source_image,
    4671             :     _cairo_image_surface_acquire_dest_image,
    4672             :     _cairo_image_surface_release_dest_image,
    4673             :     _cairo_image_surface_clone_similar,
    4674             :     _cairo_image_surface_composite,
    4675             :     _cairo_image_surface_fill_rectangles,
    4676             :     _cairo_image_surface_composite_trapezoids,
    4677             :     _cairo_image_surface_create_span_renderer,
    4678             :     _cairo_image_surface_check_span_renderer,
    4679             : 
    4680             :     NULL, /* copy_page */
    4681             :     NULL, /* show_page */
    4682             :     _cairo_image_surface_get_extents,
    4683             :     NULL, /* old_show_glyphs */
    4684             :     _cairo_image_surface_get_font_options,
    4685             :     NULL, /* flush */
    4686             :     NULL, /* mark dirty */
    4687             :     NULL, /* font_fini */
    4688             :     NULL, /* glyph_fini */
    4689             : 
    4690             :     _cairo_image_surface_paint,
    4691             :     _cairo_image_surface_mask,
    4692             :     _cairo_image_surface_stroke,
    4693             :     _cairo_image_surface_fill,
    4694             :     _cairo_image_surface_glyphs,
    4695             :     NULL, /* show_text_glyphs */
    4696             :     NULL, /* snapshot */
    4697             :     NULL, /* is_similar */
    4698             : };
    4699             : 
    4700             : /* A convenience function for when one needs to coerce an image
    4701             :  * surface to an alternate format. */
    4702             : cairo_image_surface_t *
    4703           0 : _cairo_image_surface_coerce (cairo_image_surface_t *surface)
    4704             : {
    4705           0 :     return _cairo_image_surface_coerce_to_format (surface,
    4706             :                                                   _cairo_format_from_content (surface->base.content));
    4707             :         
    4708             : }
    4709             : 
    4710             : /* A convenience function for when one needs to coerce an image
    4711             :  * surface to an alternate format. */
    4712             : cairo_image_surface_t *
    4713           0 : _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
    4714             :                                        cairo_format_t         format)
    4715             : {
    4716             :     cairo_image_surface_t *clone;
    4717             :     cairo_status_t status;
    4718             : 
    4719           0 :     status = surface->base.status;
    4720           0 :     if (unlikely (status))
    4721           0 :         return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
    4722             : 
    4723           0 :     if (surface->format == format)
    4724           0 :         return (cairo_image_surface_t *)cairo_surface_reference(&surface->base);
    4725             : 
    4726           0 :     clone = (cairo_image_surface_t *)
    4727           0 :         cairo_image_surface_create (format, surface->width, surface->height);
    4728           0 :     if (unlikely (clone->base.status))
    4729           0 :         return clone;
    4730             : 
    4731           0 :     pixman_image_composite32 (PIXMAN_OP_SRC,
    4732             :                               surface->pixman_image, NULL, clone->pixman_image,
    4733             :                               0, 0,
    4734             :                               0, 0,
    4735             :                               0, 0,
    4736             :                               surface->width, surface->height);
    4737           0 :     clone->base.is_clear = FALSE;
    4738             : 
    4739           0 :     clone->base.device_transform =
    4740             :         surface->base.device_transform;
    4741           0 :     clone->base.device_transform_inverse =
    4742             :         surface->base.device_transform_inverse;
    4743             : 
    4744           0 :     return clone;
    4745             : }
    4746             : 
    4747             : cairo_image_transparency_t
    4748           0 : _cairo_image_analyze_transparency (cairo_image_surface_t      *image)
    4749             : {
    4750             :     int x, y;
    4751             : 
    4752           0 :     if (image->transparency != CAIRO_IMAGE_UNKNOWN)
    4753           0 :         return image->transparency;
    4754             : 
    4755           0 :     if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0)
    4756           0 :         return image->transparency = CAIRO_IMAGE_IS_OPAQUE;
    4757             : 
    4758           0 :     if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) {
    4759           0 :         if (image->format == CAIRO_FORMAT_A1)
    4760           0 :             return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
    4761             :         else
    4762           0 :             return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
    4763             :     }
    4764             : 
    4765           0 :     if (image->format == CAIRO_FORMAT_RGB16_565) {
    4766           0 :         image->transparency = CAIRO_IMAGE_IS_OPAQUE;
    4767           0 :         return CAIRO_IMAGE_IS_OPAQUE;
    4768             :     }
    4769             : 
    4770           0 :     if (image->format != CAIRO_FORMAT_ARGB32)
    4771           0 :         return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
    4772             : 
    4773           0 :     image->transparency = CAIRO_IMAGE_IS_OPAQUE;
    4774           0 :     for (y = 0; y < image->height; y++) {
    4775           0 :         uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
    4776             : 
    4777           0 :         for (x = 0; x < image->width; x++, pixel++) {
    4778           0 :             int a = (*pixel & 0xff000000) >> 24;
    4779           0 :             if (a > 0 && a < 255) {
    4780           0 :                 return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
    4781           0 :             } else if (a == 0) {
    4782           0 :                 image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
    4783             :             }
    4784             :         }
    4785             :     }
    4786             : 
    4787           0 :     return image->transparency;
    4788             : }

Generated by: LCOV version 1.13