LCOV - app.info - gfx/cairo/cairo/src/cairo-image-surface.c

LCOV - code coverage report
| Current view: | directory - gfx/cairo/cairo/src - cairo-image-surface.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1896 | 222 | 11.7 %
| Date: | 2012-06-02 | Functions: | 106 | 22 | 20.8 %

           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             130 : _cairo_image_surface_is_size_valid (int width, int height)
          93                 : {
          94             260 :     return 0 <= width  &&  width <= MAX_IMAGE_SIZE &&
          95             130 :            0 <= height && height <= MAX_IMAGE_SIZE;
          96                 : }
          97                 :
          98                 : cairo_format_t
          99              65 : _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
         100                 : {
         101              65 :     switch (pixman_format) {
         102                 :     case PIXMAN_a8r8g8b8:
         103              51 :         return CAIRO_FORMAT_ARGB32;
         104                 :     case PIXMAN_x8r8g8b8:
         105              14 :         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              65 : _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
         138                 : {
         139                 :     cairo_content_t content;
         140                 :
         141              65 :     content = 0;
         142              65 :     if (PIXMAN_FORMAT_RGB (pixman_format))
         143              65 :         content |= CAIRO_CONTENT_COLOR;
         144              65 :     if (PIXMAN_FORMAT_A (pixman_format))
         145              51 :         content |= CAIRO_CONTENT_ALPHA;
         146                 :
         147              65 :     return content;
         148                 : }
         149                 :
         150                 : cairo_surface_t *
         151              65 : _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              65 :     int width = pixman_image_get_width (pixman_image);
         156              65 :     int height = pixman_image_get_height (pixman_image);
         157                 :
         158              65 :     surface = malloc (sizeof (cairo_image_surface_t));
         159              65 :     if (unlikely (surface == NULL))
         160               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
         161                 :
         162              65 :     _cairo_surface_init (&surface->base,
         163                 :                          &_cairo_image_surface_backend,
         164                 :                          NULL, /* device */
         165                 :                          _cairo_content_from_pixman_format (pixman_format));
         166                 :
         167              65 :     surface->pixman_image = pixman_image;
         168                 :
         169              65 :     surface->pixman_format = pixman_format;
         170              65 :     surface->format = _cairo_format_from_pixman_format (pixman_format);
         171              65 :     surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
         172              65 :     surface->owns_data = FALSE;
         173              65 :     surface->transparency = CAIRO_IMAGE_UNKNOWN;
         174                 :
         175              65 :     surface->width = width;
         176              65 :     surface->height = height;
         177              65 :     surface->stride = pixman_image_get_stride (pixman_image);
         178              65 :     surface->depth = pixman_image_get_depth (pixman_image);
         179                 :
         180              65 :     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              65 : _cairo_format_to_pixman_format_code (cairo_format_t format)
         290                 : {
         291                 :     pixman_format_code_t ret;
         292              65 :     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              14 :         ret = PIXMAN_x8r8g8b8;
         301              14 :         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              51 :         ret = PIXMAN_a8r8g8b8;
         309              51 :         break;
         310                 :     }
         311              65 :     return ret;
         312                 : }
         313                 :
         314                 : cairo_surface_t *
         315              65 : _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              65 :     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              65 :     pixman_image = pixman_image_create_bits (pixman_format, width, height,
         330                 :                                              (uint32_t *) data, stride ? stride : 4);
         331                 :
         332              65 :     if (unlikely (pixman_image == NULL))
         333               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
         334                 :
         335              65 :     surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
         336                 :                                                             pixman_format);
         337              65 :     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              65 :     surface->is_clear = data == NULL;
         344              65 :     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              65 : cairo_format_stride_for_width (cairo_format_t   format,
         422                 :                                int              width)
         423                 : {
         424                 :     int bpp;
         425                 :
         426              65 :     if (! CAIRO_FORMAT_VALID (format)) {
         427               0 :         _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
         428               0 :         return -1;
         429                 :     }
         430                 :
         431              65 :     bpp = _cairo_format_bits_per_pixel (format);
         432              65 :     if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp))
         433               0 :         return -1;
         434                 :
         435              65 :     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              65 : 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              65 :     if (! CAIRO_FORMAT_VALID (format))
         493               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
         494                 :
         495              65 :     if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0)
         496               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
         497                 :
         498              65 :     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              65 :     minstride = cairo_format_stride_for_width (format, width);
         502              65 :     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              65 :         if (stride < minstride) {
         508               0 :             return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
         509                 :         }
         510                 :     }
         511                 :
         512              65 :     pixman_format = _cairo_format_to_pixman_format_code (format);
         513              65 :     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              65 : _cairo_format_bits_per_pixel (cairo_format_t format)
         682                 : {
         683              65 :     switch (format) {
         684                 :     case CAIRO_FORMAT_ARGB32:
         685              51 :         return 32;
         686                 :     case CAIRO_FORMAT_RGB24:
         687              14 :         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              65 : _cairo_image_surface_finish (void *abstract_surface)
         725                 : {
         726              65 :     cairo_image_surface_t *surface = abstract_surface;
         727                 :
         728              65 :     if (surface->pixman_image) {
         729              65 :         pixman_image_unref (surface->pixman_image);
         730              65 :         surface->pixman_image = NULL;
         731                 :     }
         732                 :
         733              65 :     if (surface->owns_data) {
         734               0 :         free (surface->data);
         735               0 :         surface->data = NULL;
         736                 :     }
         737                 :
         738              65 :     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              47 : _pixman_operator (cairo_operator_t op)
         772                 : {
         773              47 :     switch (op) {
         774                 :     case CAIRO_OPERATOR_CLEAR:
         775               0 :         return PIXMAN_OP_CLEAR;
         776                 :
         777                 :     case CAIRO_OPERATOR_SOURCE:
         778              47 :         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              74 : _pixman_nearest_sample (double d)
         861                 : {
         862              74 :     return ceil (d - .5);
         863                 : }
         864                 :
         865                 : static cairo_bool_t
         866              37 : _nearest_sample (cairo_filter_t filter, double *tx, double *ty)
         867                 : {
         868              37 :     if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
         869              37 :         *tx = _pixman_nearest_sample (*tx);
         870              37 :         *ty = _pixman_nearest_sample (*ty);
         871                 :     } else {
         872               0 :         if (*tx != floor (*tx) || *ty != floor (*ty))
         873               0 :             return FALSE;
         874                 :     }
         875              37 :     return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
         876                 : }
         877                 :
         878                 : #if 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                 : #else
         973                 : static pixman_image_t *
         974               0 : _pixman_transparent_image (void)
         975                 : {
         976               0 :     return _pixman_image_for_solid (&_cairo_pattern_clear);
         977                 : }
         978                 : static pixman_image_t *
         979               0 : _pixman_black_image (void)
         980                 : {
         981               0 :     return _pixman_image_for_solid (&_cairo_pattern_black);
         982                 : }
         983                 : static pixman_image_t *
         984               0 : _pixman_white_image (void)
         985                 : {
         986               0 :     return _pixman_image_for_solid (&_cairo_pattern_white);
         987                 : }
         988                 : #endif
         989                 :
         990                 : static uint32_t
         991               0 : hars_petruska_f54_1_random (void)
         992                 : {
         993                 : #define rol(x,k) ((x << k) | (x >> (32-k)))
         994                 :     static uint32_t x;
         995               0 :     return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
         996                 : #undef rol
         997                 : }
         998                 :
         999                 : static struct {
        1000                 :     cairo_color_t color;
        1001                 :     pixman_image_t *image;
        1002                 : } cache[16];
        1003                 : static int n_cached;
        1004                 :
        1005                 : void
        1006               3 : _cairo_image_reset_static_data (void)
        1007                 : {
        1008               6 :     while (n_cached)
        1009               0 :         pixman_image_unref (cache[--n_cached].image);
        1010                 :
        1011                 : #if HAS_ATOMIC_OPS
        1012                 :     if (__pixman_transparent_image) {
        1013                 :         pixman_image_unref (__pixman_transparent_image);
        1014                 :         __pixman_transparent_image = NULL;
        1015                 :     }
        1016                 :
        1017                 :     if (__pixman_black_image) {
        1018                 :         pixman_image_unref (__pixman_black_image);
        1019                 :         __pixman_black_image = NULL;
        1020                 :     }
        1021                 :
        1022                 :     if (__pixman_white_image) {
        1023                 :         pixman_image_unref (__pixman_white_image);
        1024                 :         __pixman_white_image = NULL;
        1025                 :     }
        1026                 : #endif
        1027               3 : }
        1028                 :
        1029                 : static pixman_image_t *
        1030               0 : _pixman_image_for_solid (const cairo_solid_pattern_t *pattern)
        1031                 : {
        1032                 :     pixman_color_t color;
        1033                 :     pixman_image_t *image;
        1034                 :     int i;
        1035                 :
        1036                 : #if HAS_ATOMIC_OPS
        1037                 :     if (pattern->color.alpha_short <= 0x00ff)
        1038                 :         return _pixman_transparent_image ();
        1039                 :
        1040                 :     if (pattern->color.alpha_short >= 0xff00) {
        1041                 :         if (pattern->color.red_short <= 0x00ff &&
        1042                 :             pattern->color.green_short <= 0x00ff &&
        1043                 :             pattern->color.blue_short <= 0x00ff)
        1044                 :         {
        1045                 :             return _pixman_black_image ();
        1046                 :         }
        1047                 :
        1048                 :         if (pattern->color.red_short >= 0xff00 &&
        1049                 :             pattern->color.green_short >= 0xff00 &&
        1050                 :             pattern->color.blue_short >= 0xff00)
        1051                 :         {
        1052                 :             return _pixman_white_image ();
        1053                 :         }
        1054                 :     }
        1055                 : #endif
        1056                 :
        1057                 :     CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
        1058               0 :     for (i = 0; i < n_cached; i++) {
        1059               0 :         if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
        1060               0 :             image = pixman_image_ref (cache[i].image);
        1061               0 :             goto UNLOCK;
        1062                 :         }
        1063                 :     }
        1064                 :
        1065               0 :     color.red   = pattern->color.red_short;
        1066               0 :     color.green = pattern->color.green_short;
        1067               0 :     color.blue  = pattern->color.blue_short;
        1068               0 :     color.alpha = pattern->color.alpha_short;
        1069                 :
        1070               0 :     image = pixman_image_create_solid_fill (&color);
        1071               0 :     if (image == NULL)
        1072               0 :         goto UNLOCK;
        1073                 :
        1074               0 :     if (n_cached < ARRAY_LENGTH (cache)) {
        1075               0 :         i = n_cached++;
        1076                 :     } else {
        1077               0 :         i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
        1078               0 :         pixman_image_unref (cache[i].image);
        1079                 :     }
        1080               0 :     cache[i].image = pixman_image_ref (image);
        1081               0 :     cache[i].color = pattern->color;
        1082                 :
        1083                 : UNLOCK:
        1084                 :     CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
        1085               0 :     return image;
        1086                 : }
        1087                 :
        1088                 : static pixman_image_t *
        1089               0 : _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
        1090                 :                             const cairo_rectangle_int_t *extents,
        1091                 :                             int *ix, int *iy)
        1092                 : {
        1093                 :     pixman_image_t        *pixman_image;
        1094                 :     pixman_gradient_stop_t pixman_stops_static[2];
        1095               0 :     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
        1096               0 :     cairo_matrix_t matrix = pattern->base.matrix;
        1097                 :     double tx, ty;
        1098                 :     unsigned int i;
        1099                 :
        1100               0 :     if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
        1101               0 :         pixman_stops = _cairo_malloc_ab (pattern->n_stops,
        1102                 :                                          sizeof(pixman_gradient_stop_t));
        1103               0 :         if (unlikely (pixman_stops == NULL))
        1104               0 :             return NULL;
        1105                 :     }
        1106                 :
        1107               0 :     for (i = 0; i < pattern->n_stops; i++) {
        1108               0 :         pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
        1109               0 :         pixman_stops[i].color.red   = pattern->stops[i].color.red_short;
        1110               0 :         pixman_stops[i].color.green = pattern->stops[i].color.green_short;
        1111               0 :         pixman_stops[i].color.blue  = pattern->stops[i].color.blue_short;
        1112               0 :         pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
        1113                 :     }
        1114                 :
        1115               0 :     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
        1116               0 :         cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
        1117                 :         pixman_point_fixed_t p1, p2;
        1118                 :         cairo_fixed_t xdim, ydim;
        1119                 :
        1120               0 :         xdim = fabs (linear->p2.x - linear->p1.x);
        1121               0 :         ydim = fabs (linear->p2.y - linear->p1.y);
        1122                 :
        1123                 :         /*
        1124                 :          * Transform the matrix to avoid overflow when converting between
        1125                 :          * cairo_fixed_t and pixman_fixed_t (without incurring performance
        1126                 :          * loss when the transformation is unnecessary).
        1127                 :          *
        1128                 :          * XXX: Consider converting out-of-range co-ordinates and transforms.
        1129                 :          * Having a function to compute the required transformation to
        1130                 :          * "normalize" a given bounding box would be generally useful -
        1131                 :          * cf linear patterns, gradient patterns, surface patterns...
        1132                 :          */
        1133               0 :         if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
        1134               0 :             _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
        1135               0 :         {
        1136                 :             double sf;
        1137                 :
        1138               0 :             if (xdim > ydim)
        1139               0 :                 sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
        1140                 :             else
        1141               0 :                 sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
        1142                 :
        1143               0 :             p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
        1144               0 :             p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
        1145               0 :             p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
        1146               0 :             p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
        1147                 :
        1148               0 :             cairo_matrix_scale (&matrix, sf, sf);
        1149                 :         }
        1150                 :         else
        1151                 :         {
        1152               0 :             p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
        1153               0 :             p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
        1154               0 :             p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
        1155               0 :             p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
        1156                 :         }
        1157                 :
        1158               0 :         pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
        1159                 :                                                             pixman_stops,
        1160               0 :                                                             pattern->n_stops);
        1161                 :     } else {
        1162               0 :         cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
        1163                 :         pixman_point_fixed_t c1, c2;
        1164                 :         pixman_fixed_t r1, r2;
        1165                 :
        1166               0 :         c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
        1167               0 :         c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
        1168               0 :         r1   = _cairo_fixed_to_16_16 (radial->r1);
        1169                 :
        1170               0 :         c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
        1171               0 :         c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
        1172               0 :         r2   = _cairo_fixed_to_16_16 (radial->r2);
        1173                 :
        1174               0 :         pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
        1175                 :                                                             pixman_stops,
        1176               0 :                                                             pattern->n_stops);
        1177                 :     }
        1178                 :
        1179               0 :     if (pixman_stops != pixman_stops_static)
        1180               0 :         free (pixman_stops);
        1181                 :
        1182               0 :     if (unlikely (pixman_image == NULL))
        1183               0 :         return NULL;
        1184                 :
        1185               0 :     tx = pattern->base.matrix.x0;
        1186               0 :     ty = pattern->base.matrix.y0;
        1187               0 :     if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
        1188               0 :         ! _nearest_sample (pattern->base.filter, &tx, &ty))
        1189                 :     {
        1190                 :         pixman_transform_t pixman_transform;
        1191                 :
        1192               0 :         if (tx != 0. || ty != 0.) {
        1193                 :             cairo_matrix_t m, inv;
        1194                 :             cairo_status_t status;
        1195                 :             double x, y;
        1196                 :
        1197                 :             /* pixman also limits the [xy]_offset to 16 bits so evenly
        1198                 :              * spread the bits between the two.
        1199                 :              */
        1200               0 :             inv = pattern->base.matrix;
        1201               0 :             status = cairo_matrix_invert (&inv);
        1202               0 :             assert (status == CAIRO_STATUS_SUCCESS);
        1203                 :
        1204               0 :             x = _cairo_lround (inv.x0 / 2);
        1205               0 :             y = _cairo_lround (inv.y0 / 2);
        1206               0 :             tx = -x;
        1207               0 :             ty = -y;
        1208               0 :             cairo_matrix_init_translate (&inv, x, y);
        1209               0 :             cairo_matrix_multiply (&m, &inv, &pattern->base.matrix);
        1210               0 :             _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
        1211               0 :                                             extents->x + extents->width/2.,
        1212               0 :                                             extents->y + extents->height/2.);
        1213                 :         } else {
        1214               0 :             tx = ty = 0;
        1215               0 :             _cairo_matrix_to_pixman_matrix (&pattern->base.matrix,
        1216                 :                                             &pixman_transform,
        1217               0 :                                             extents->x + extents->width/2.,
        1218               0 :                                             extents->y + extents->height/2.);
        1219                 :         }
        1220                 :
        1221               0 :         if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
        1222               0 :             pixman_image_unref (pixman_image);
        1223               0 :             return NULL;
        1224                 :         }
        1225                 :     }
        1226               0 :     *ix = tx;
        1227               0 :     *iy = ty;
        1228                 :
        1229                 :     {
        1230                 :         pixman_repeat_t pixman_repeat;
        1231                 :
        1232               0 :         switch (pattern->base.extend) {
        1233                 :         default:
        1234                 :         case CAIRO_EXTEND_NONE:
        1235               0 :             pixman_repeat = PIXMAN_REPEAT_NONE;
        1236               0 :             break;
        1237                 :         case CAIRO_EXTEND_REPEAT:
        1238               0 :             pixman_repeat = PIXMAN_REPEAT_NORMAL;
        1239               0 :             break;
        1240                 :         case CAIRO_EXTEND_REFLECT:
        1241               0 :             pixman_repeat = PIXMAN_REPEAT_REFLECT;
        1242               0 :             break;
        1243                 :         case CAIRO_EXTEND_PAD:
        1244               0 :             pixman_repeat = PIXMAN_REPEAT_PAD;
        1245               0 :             break;
        1246                 :         }
        1247                 :
        1248               0 :         pixman_image_set_repeat (pixman_image, pixman_repeat);
        1249                 :     }
        1250                 :
        1251               0 :     return pixman_image;
        1252                 : }
        1253                 :
        1254                 : struct acquire_source_cleanup {
        1255                 :     cairo_surface_t *surface;
        1256                 :     cairo_image_surface_t *image;
        1257                 :     void *image_extra;
        1258                 : };
        1259                 :
        1260                 : static void
        1261               0 : _acquire_source_cleanup (pixman_image_t *pixman_image,
        1262                 :                          void *closure)
        1263                 : {
        1264               0 :     struct acquire_source_cleanup *data = closure;
        1265                 :
        1266               0 :     _cairo_surface_release_source_image (data->surface,
        1267                 :                                          data->image,
        1268                 :                                          data->image_extra);
        1269               0 :     free (data);
        1270               0 : }
        1271                 :
        1272                 : static cairo_filter_t
        1273              47 : sampled_area (const cairo_surface_pattern_t *pattern,
        1274                 :               const cairo_rectangle_int_t *extents,
        1275                 :               cairo_rectangle_int_t *sample)
        1276                 : {
        1277                 :     cairo_filter_t filter;
        1278                 :     double x1, x2, y1, y2;
        1279                 :     double pad;
        1280                 :
        1281              47 :     x1 = extents->x;
        1282              47 :     y1 = extents->y;
        1283              47 :     x2 = extents->x + (int) extents->width;
        1284              47 :     y2 = extents->y + (int) extents->height;
        1285                 :
        1286              47 :     _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
        1287                 :                                           &x1, &y1, &x2, &y2,
        1288                 :                                           NULL);
        1289                 :
        1290              47 :     filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
        1291              47 :     sample->x = floor (x1 - pad);
        1292              47 :     sample->y = floor (y1 - pad);
        1293              47 :     sample->width  = ceil (x2 + pad) - sample->x;
        1294              47 :     sample->height = ceil (y2 + pad) - sample->y;
        1295                 :
        1296              47 :     return filter;
        1297                 : }
        1298                 :
        1299                 : static uint16_t
        1300               0 : expand_channel (uint16_t v, uint32_t bits)
        1301                 : {
        1302               0 :     int offset = 16 - bits;
        1303               0 :     while (offset > 0) {
        1304               0 :         v |= v >> bits;
        1305               0 :         offset -= bits;
        1306               0 :         bits += bits;
        1307                 :     }
        1308               0 :     return v;
        1309                 : }
        1310                 :
        1311                 : static pixman_image_t *
        1312               0 : _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
        1313                 : {
        1314                 :     uint32_t pixel;
        1315                 :     pixman_color_t color;
        1316                 :
        1317               0 :     switch (image->format) {
        1318                 :     default:
        1319                 :     case CAIRO_FORMAT_INVALID:
        1320               0 :         ASSERT_NOT_REACHED;
        1321               0 :         return NULL;
        1322                 :
        1323                 :     case CAIRO_FORMAT_A1:
        1324               0 :         pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
        1325               0 :         return pixel & (1 << (x&7)) ? _pixman_white_image () : _pixman_transparent_image ();
        1326                 :
        1327                 :     case CAIRO_FORMAT_A8:
        1328               0 :         color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
        1329               0 :         color.alpha |= color.alpha << 8;
        1330               0 :         if (color.alpha == 0)
        1331               0 :             return _pixman_transparent_image ();
        1332                 :
        1333               0 :         color.red = color.green = color.blue = 0;
        1334               0 :         return pixman_image_create_solid_fill (&color);
        1335                 :
        1336                 :     case CAIRO_FORMAT_RGB16_565:
        1337               0 :         pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
        1338               0 :         if (pixel == 0)
        1339               0 :             return _pixman_black_image ();
        1340               0 :         if (pixel == 0xffff)
        1341               0 :             return _pixman_white_image ();
        1342                 :
        1343               0 :         color.alpha = 0xffff;
        1344               0 :         color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
        1345               0 :         color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
        1346               0 :         color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
        1347               0 :         return pixman_image_create_solid_fill (&color);
        1348                 :
        1349                 :     case CAIRO_FORMAT_ARGB32:
        1350                 :     case CAIRO_FORMAT_RGB24:
        1351               0 :         pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
        1352               0 :         color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
        1353               0 :         if (color.alpha == 0)
        1354               0 :             return _pixman_transparent_image ();
        1355               0 :         if (pixel == 0xffffffff)
        1356               0 :             return _pixman_white_image ();
        1357               0 :         if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
        1358               0 :             return _pixman_black_image ();
        1359                 :
        1360               0 :         color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
        1361               0 :         color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
        1362               0 :         color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
        1363               0 :         return pixman_image_create_solid_fill (&color);
        1364                 :     }
        1365                 : }
        1366                 :
        1367                 : static pixman_image_t *
        1368              47 : _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
        1369                 :                            cairo_bool_t is_mask,
        1370                 :                            const cairo_rectangle_int_t *extents,
        1371                 :                            int *ix, int *iy)
        1372                 : {
        1373                 :     pixman_image_t *pixman_image;
        1374                 :     cairo_rectangle_int_t sample;
        1375                 :     cairo_extend_t extend;
        1376                 :     cairo_filter_t filter;
        1377                 :     double tx, ty;
        1378                 :
        1379              47 :     tx = pattern->base.matrix.x0;
        1380              47 :     ty = pattern->base.matrix.y0;
        1381                 :
        1382              47 :     extend = pattern->base.extend;
        1383              47 :     filter = sampled_area (pattern, extents, &sample);
        1384                 :
        1385              47 :     pixman_image = NULL;
        1386              47 :     if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
        1387               0 :         (! is_mask || ! pattern->base.has_component_alpha ||
        1388               0 :          (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
        1389                 :     {
        1390              47 :         cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
        1391                 :         cairo_surface_type_t type;
        1392                 :
        1393              47 :         if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
        1394               0 :             source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
        1395                 :
        1396              47 :         type = source->base.backend->type;
        1397              47 :         if (type == CAIRO_SURFACE_TYPE_IMAGE) {
        1398              47 :             if (extend != CAIRO_EXTEND_NONE &&
        1399               0 :                 sample.x >= 0 &&
        1400               0 :                 sample.y >= 0 &&
        1401               0 :                 sample.x + sample.width  <= source->width &&
        1402               0 :                 sample.y + sample.height <= source->height)
        1403                 :             {
        1404               0 :                 extend = CAIRO_EXTEND_NONE;
        1405                 :             }
        1406                 :
        1407              47 :             if (sample.width == 1 && sample.height == 1) {
        1408               0 :                 if (sample.x < 0 ||
        1409               0 :                     sample.y < 0 ||
        1410               0 :                     sample.x >= source->width ||
        1411               0 :                     sample.y >= source->height)
        1412                 :                 {
        1413               0 :                     if (extend == CAIRO_EXTEND_NONE)
        1414               0 :                         return _pixman_transparent_image ();
        1415                 :                 }
        1416                 :                 else
        1417                 :                 {
        1418               0 :                     return _pixel_to_solid (source, sample.x, sample.y);
        1419                 :                 }
        1420                 :             }
        1421                 :
        1422                 :             /* avoid allocating a 'pattern' image if we can reuse the original */
        1423              94 :             if (extend == CAIRO_EXTEND_NONE &&
        1424              84 :                 _cairo_matrix_is_translation (&pattern->base.matrix) &&
        1425              37 :                 _nearest_sample (filter, &tx, &ty))
        1426                 :             {
        1427              37 :                 *ix = tx;
        1428              37 :                 *iy = ty;
        1429              37 :                 return pixman_image_ref (source->pixman_image);
        1430                 :             }
        1431                 :
        1432              20 :             pixman_image = pixman_image_create_bits (source->pixman_format,
        1433                 :                                                      source->width,
        1434                 :                                                      source->height,
        1435              10 :                                                      (uint32_t *) source->data,
        1436                 :                                                      source->stride);
        1437              10 :             if (unlikely (pixman_image == NULL))
        1438               0 :                 return NULL;
        1439               0 :         } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
        1440                 :             cairo_surface_subsurface_t *sub;
        1441               0 :             cairo_bool_t is_contained = FALSE;
        1442                 :
        1443               0 :             sub = (cairo_surface_subsurface_t *) source;
        1444               0 :             source = (cairo_image_surface_t *) sub->target;
        1445                 :
        1446               0 :             if (sample.x >= 0 &&
        1447               0 :                 sample.y >= 0 &&
        1448               0 :                 sample.x + sample.width  <= sub->extents.width &&
        1449               0 :                 sample.y + sample.height <= sub->extents.height)
        1450                 :             {
        1451               0 :                 is_contained = TRUE;
        1452                 :             }
        1453                 :
        1454               0 :             if (sample.width == 1 && sample.height == 1) {
        1455               0 :                 if (is_contained) {
        1456               0 :                     return _pixel_to_solid (source,
        1457               0 :                                             sub->extents.x + sample.x,
        1458               0 :                                             sub->extents.y + sample.y);
        1459                 :                 } else {
        1460               0 :                     if (extend == CAIRO_EXTEND_NONE)
        1461               0 :                         return _pixman_transparent_image ();
        1462                 :                 }
        1463                 :             }
        1464                 :
        1465               0 :             if (is_contained &&
        1466               0 :                 _cairo_matrix_is_translation (&pattern->base.matrix) &&
        1467               0 :                 _nearest_sample (filter, &tx, &ty))
        1468                 :             {
        1469               0 :                 *ix = tx + sub->extents.x;
        1470               0 :                 *iy = ty + sub->extents.y;
        1471               0 :                 return pixman_image_ref (source->pixman_image);
        1472                 :             }
        1473                 :
        1474                 :             /* Avoid sub-byte offsets, force a copy in that case. */
        1475               0 :             if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
        1476               0 :                 pixman_image = pixman_image_create_bits (source->pixman_format,
        1477                 :                                                          sub->extents.width,
        1478                 :                                                          sub->extents.height,
        1479               0 :                                                          (uint32_t *) (source->data + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 + sub->extents.y * source->stride),
        1480                 :                                                          source->stride);
        1481               0 :                 if (unlikely (pixman_image == NULL))
        1482               0 :                     return NULL;
        1483                 :             }
        1484                 :         }
        1485                 :     }
        1486                 :
        1487              10 :     if (pixman_image == NULL) {
        1488                 :         struct acquire_source_cleanup *cleanup;
        1489                 :         cairo_image_surface_t *image;
        1490                 :         void *extra;
        1491                 :         cairo_status_t status;
        1492                 :
        1493               0 :         status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
        1494               0 :         if (unlikely (status))
        1495               0 :             return NULL;
        1496                 :
        1497               0 :         if (sample.width == 1 && sample.height == 1) {
        1498               0 :             if (sample.x < 0 ||
        1499               0 :                 sample.y < 0 ||
        1500               0 :                 sample.x >= image->width ||
        1501               0 :                 sample.y >= image->height)
        1502                 :             {
        1503               0 :                 if (extend == CAIRO_EXTEND_NONE) {
        1504               0 :                     pixman_image = _pixman_transparent_image ();
        1505               0 :                     _cairo_surface_release_source_image (pattern->surface, image, extra);
        1506               0 :                     return pixman_image;
        1507                 :                 }
        1508                 :             }
        1509                 :             else
        1510                 :             {
        1511               0 :                 pixman_image = _pixel_to_solid (image, sample.x, sample.y);
        1512               0 :                 _cairo_surface_release_source_image (pattern->surface, image, extra);
        1513               0 :                 return pixman_image;
        1514                 :             }
        1515                 :         }
        1516                 :
        1517               0 :         pixman_image = pixman_image_create_bits (image->pixman_format,
        1518               0 :                                                  image->width,
        1519               0 :                                                  image->height,
        1520               0 :                                                  (uint32_t *) image->data,
        1521               0 :                                                  image->stride);
        1522               0 :         if (unlikely (pixman_image == NULL)) {
        1523               0 :             _cairo_surface_release_source_image (pattern->surface, image, extra);
        1524               0 :             return NULL;
        1525                 :         }
        1526                 :
        1527               0 :         cleanup = malloc (sizeof (*cleanup));
        1528               0 :         if (unlikely (cleanup == NULL)) {
        1529               0 :             _cairo_surface_release_source_image (pattern->surface, image, extra);
        1530               0 :             pixman_image_unref (pixman_image);
        1531               0 :             return NULL;
        1532                 :         }
        1533                 :
        1534               0 :         cleanup->surface = pattern->surface;
        1535               0 :         cleanup->image = image;
        1536               0 :         cleanup->image_extra = extra;
        1537               0 :         pixman_image_set_destroy_function (pixman_image,
        1538                 :                                            _acquire_source_cleanup, cleanup);
        1539                 :     }
        1540                 :
        1541              10 :     if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
        1542               0 :         ! _nearest_sample (filter, &tx, &ty))
        1543                 :     {
        1544                 :         pixman_transform_t pixman_transform;
        1545                 :         cairo_matrix_t m;
        1546                 :
        1547              10 :         m = pattern->base.matrix;
        1548              10 :         if (m.x0 != 0. || m.y0 != 0.) {
        1549                 :             cairo_matrix_t inv;
        1550                 :             cairo_status_t status;
        1551                 :             double x, y;
        1552                 :
        1553                 :             /* pixman also limits the [xy]_offset to 16 bits so evenly
        1554                 :              * spread the bits between the two.
        1555                 :              */
        1556               0 :             inv = m;
        1557               0 :             status = cairo_matrix_invert (&inv);
        1558               0 :             assert (status == CAIRO_STATUS_SUCCESS);
        1559                 :
        1560               0 :             x = floor (inv.x0 / 2);
        1561               0 :             y = floor (inv.y0 / 2);
        1562               0 :             tx = -x;
        1563               0 :             ty = -y;
        1564               0 :             cairo_matrix_init_translate (&inv, x, y);
        1565               0 :             cairo_matrix_multiply (&m, &inv, &m);
        1566                 :         } else {
        1567              10 :             tx = ty = 0;
        1568                 :         }
        1569                 :
        1570              40 :         _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
        1571              20 :                                         extents->x + extents->width/2.,
        1572              20 :                                         extents->y + extents->height/2.);
        1573              10 :         if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
        1574               0 :             pixman_image_unref (pixman_image);
        1575               0 :             return NULL;
        1576                 :         }
        1577                 :     }
        1578              10 :     *ix = tx;
        1579              10 :     *iy = ty;
        1580                 :
        1581              10 :     if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
        1582               0 :         tx == pattern->base.matrix.x0 &&
        1583               0 :         ty == pattern->base.matrix.y0)
        1584                 :     {
        1585               0 :         pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
        1586                 :     }
        1587                 :     else
        1588                 :     {
        1589                 :         pixman_filter_t pixman_filter;
        1590                 :
        1591              10 :         switch (filter) {
        1592                 :         case CAIRO_FILTER_FAST:
        1593               0 :             pixman_filter = PIXMAN_FILTER_FAST;
        1594               0 :             break;
        1595                 :         case CAIRO_FILTER_GOOD:
        1596              10 :             pixman_filter = PIXMAN_FILTER_GOOD;
        1597              10 :             break;
        1598                 :         case CAIRO_FILTER_BEST:
        1599               0 :             pixman_filter = PIXMAN_FILTER_BEST;
        1600               0 :             break;
        1601                 :         case CAIRO_FILTER_NEAREST:
        1602               0 :             pixman_filter = PIXMAN_FILTER_NEAREST;
        1603               0 :             break;
        1604                 :         case CAIRO_FILTER_BILINEAR:
        1605               0 :             pixman_filter = PIXMAN_FILTER_BILINEAR;
        1606               0 :             break;
        1607                 :         case CAIRO_FILTER_GAUSSIAN:
        1608                 :             /* XXX: The GAUSSIAN value has no implementation in cairo
        1609                 :              * whatsoever, so it was really a mistake to have it in the
        1610                 :              * API. We could fix this by officially deprecating it, or
        1611                 :              * else inventing semantics and providing an actual
        1612                 :              * implementation for it. */
        1613                 :         default:
        1614               0 :             pixman_filter = PIXMAN_FILTER_BEST;
        1615                 :         }
        1616                 :
        1617              10 :         pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
        1618                 :     }
        1619                 :
        1620                 :     {
        1621                 :         pixman_repeat_t pixman_repeat;
        1622                 :
        1623              10 :         switch (extend) {
        1624                 :         default:
        1625                 :         case CAIRO_EXTEND_NONE:
        1626              10 :             pixman_repeat = PIXMAN_REPEAT_NONE;
        1627              10 :             break;
        1628                 :         case CAIRO_EXTEND_REPEAT:
        1629               0 :             pixman_repeat = PIXMAN_REPEAT_NORMAL;
        1630               0 :             break;
        1631                 :         case CAIRO_EXTEND_REFLECT:
        1632               0 :             pixman_repeat = PIXMAN_REPEAT_REFLECT;
        1633               0 :             break;
        1634                 :         case CAIRO_EXTEND_PAD:
        1635               0 :             pixman_repeat = PIXMAN_REPEAT_PAD;
        1636               0 :             break;
        1637                 :         }
        1638                 :
        1639              10 :         pixman_image_set_repeat (pixman_image, pixman_repeat);
        1640                 :     }
        1641                 :
        1642              10 :     if (pattern->base.has_component_alpha)
        1643               0 :         pixman_image_set_component_alpha (pixman_image, TRUE);
        1644                 :
        1645              10 :     return pixman_image;
        1646                 : }
        1647                 :
        1648                 : static pixman_image_t *
        1649              47 : _pixman_image_for_pattern (const cairo_pattern_t *pattern,
        1650                 :                            cairo_bool_t is_mask,
        1651                 :                            const cairo_rectangle_int_t *extents,
        1652                 :                            int *tx, int *ty)
        1653                 : {
        1654              47 :     *tx = *ty = 0;
        1655                 :
        1656              47 :     if (pattern == NULL)
        1657               0 :         return _pixman_white_image ();
        1658                 :
        1659              47 :     switch (pattern->type) {
        1660                 :     default:
        1661               0 :         ASSERT_NOT_REACHED;
        1662                 :     case CAIRO_PATTERN_TYPE_SOLID:
        1663               0 :         return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
        1664                 :
        1665                 :     case CAIRO_PATTERN_TYPE_RADIAL:
        1666                 :     case CAIRO_PATTERN_TYPE_LINEAR:
        1667               0 :         return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
        1668                 :                                            extents, tx, ty);
        1669                 :
        1670                 :     case CAIRO_PATTERN_TYPE_SURFACE:
        1671              47 :         return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern,
        1672                 :                                           is_mask, extents, tx, ty);
        1673                 :     }
        1674                 : }
        1675                 :
        1676                 : static cairo_status_t
        1677               0 : _cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
        1678                 :                                       const cairo_composite_rectangles_t *rects,
        1679                 :                                       cairo_clip_t *clip)
        1680                 : {
        1681               0 :     pixman_image_t *mask = NULL;
        1682                 :     pixman_box32_t boxes[4];
        1683               0 :     int i, mask_x = 0, mask_y = 0, n_boxes = 0;
        1684                 :
        1685               0 :     if (clip != NULL) {
        1686                 :         cairo_surface_t *clip_surface;
        1687                 :         int clip_x, clip_y;
        1688                 :
        1689               0 :         clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
        1690               0 :         if (unlikely (clip_surface->status))
        1691               0 :             return clip_surface->status;
        1692                 :
        1693               0 :         mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
        1694               0 :         mask_x = -clip_x;
        1695               0 :         mask_y = -clip_y;
        1696                 :     } else {
        1697               0 :         if (rects->bounded.width  == rects->unbounded.width &&
        1698               0 :             rects->bounded.height == rects->unbounded.height)
        1699                 :         {
        1700               0 :             return CAIRO_STATUS_SUCCESS;
        1701                 :         }
        1702                 :     }
        1703                 :
        1704                 :     /* wholly unbounded? */
        1705               0 :     if (rects->bounded.width == 0 || rects->bounded.height == 0) {
        1706               0 :         int x = rects->unbounded.x;
        1707               0 :         int y = rects->unbounded.y;
        1708               0 :         int width = rects->unbounded.width;
        1709               0 :         int height = rects->unbounded.height;
        1710                 :
        1711               0 :         if (mask != NULL) {
        1712               0 :             pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
        1713                 :                                       mask, NULL, dst->pixman_image,
        1714                 :                                       x + mask_x, y + mask_y,
        1715                 :                                       0, 0,
        1716                 :                                       x, y,
        1717                 :                                       width, height);
        1718                 :         } else {
        1719               0 :             pixman_color_t color = { 0, };
        1720               0 :             pixman_box32_t box = { x, y, x + width, y + height };
        1721                 :
        1722               0 :             if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
        1723                 :                                            dst->pixman_image,
        1724                 :                                            &color,
        1725                 :                                            1, &box))
        1726               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        1727                 :         }
        1728                 :
        1729               0 :         return CAIRO_STATUS_SUCCESS;
        1730                 :     }
        1731                 :
        1732                 :     /* top */
        1733               0 :     if (rects->bounded.y != rects->unbounded.y) {
        1734               0 :         boxes[n_boxes].x1 = rects->unbounded.x;
        1735               0 :         boxes[n_boxes].y1 = rects->unbounded.y;
        1736               0 :         boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
        1737               0 :         boxes[n_boxes].y2 = rects->bounded.y;
        1738               0 :         n_boxes++;
        1739                 :     }
        1740                 :
        1741                 :     /* left */
        1742               0 :     if (rects->bounded.x != rects->unbounded.x) {
        1743               0 :         boxes[n_boxes].x1 = rects->unbounded.x;
        1744               0 :         boxes[n_boxes].y1 = rects->bounded.y;
        1745               0 :         boxes[n_boxes].x2 = rects->bounded.x;
        1746               0 :         boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
        1747               0 :         n_boxes++;
        1748                 :     }
        1749                 :
        1750                 :     /* right */
        1751               0 :     if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
        1752               0 :         boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width;
        1753               0 :         boxes[n_boxes].y1 = rects->bounded.y;
        1754               0 :         boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
        1755               0 :         boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
        1756               0 :         n_boxes++;
        1757                 :     }
        1758                 :
        1759                 :     /* bottom */
        1760               0 :     if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
        1761               0 :         boxes[n_boxes].x1 = rects->unbounded.x;
        1762               0 :         boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height;
        1763               0 :         boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
        1764               0 :         boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height;
        1765               0 :         n_boxes++;
        1766                 :     }
        1767                 :
        1768               0 :     if (mask != NULL) {
        1769               0 :         for (i = 0; i < n_boxes; i++) {
        1770               0 :             pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
        1771                 :                                       mask, NULL, dst->pixman_image,
        1772               0 :                                       boxes[i].x1 + mask_x, boxes[i].y1 + mask_y,
        1773                 :                                       0, 0,
        1774                 :                                       boxes[i].x1, boxes[i].y1,
        1775               0 :                                       boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1);
        1776                 :         }
        1777                 :     } else {
        1778               0 :         pixman_color_t color = { 0, };
        1779                 :
        1780               0 :         if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
        1781                 :                                        dst->pixman_image,
        1782                 :                                        &color,
        1783                 :                                        n_boxes,
        1784                 :                                        boxes))
        1785                 :         {
        1786               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        1787                 :         }
        1788                 :     }
        1789                 :
        1790               0 :     return CAIRO_STATUS_SUCCESS;
        1791                 : }
        1792                 :
        1793                 : static cairo_status_t
        1794               0 : _cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst,
        1795                 :                                             const cairo_composite_rectangles_t *extents,
        1796                 :                                             cairo_region_t *clip_region,
        1797                 :                                             cairo_boxes_t *boxes)
        1798                 : {
        1799                 :     cairo_boxes_t clear;
        1800                 :     cairo_box_t box;
        1801                 :     cairo_status_t status;
        1802                 :     struct _cairo_boxes_chunk *chunk;
        1803                 :     int i;
        1804                 :
        1805               0 :     if (boxes->num_boxes < 1 && clip_region == NULL)
        1806               0 :         return _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
        1807                 :
        1808               0 :     _cairo_boxes_init (&clear);
        1809                 :
        1810               0 :     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
        1811               0 :     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
        1812               0 :     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
        1813               0 :     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
        1814                 :
        1815               0 :     if (clip_region == NULL) {
        1816                 :         cairo_boxes_t tmp;
        1817                 :
        1818               0 :         _cairo_boxes_init (&tmp);
        1819                 :
        1820               0 :         status = _cairo_boxes_add (&tmp, &box);
        1821               0 :         assert (status == CAIRO_STATUS_SUCCESS);
        1822                 :
        1823               0 :         tmp.chunks.next = &boxes->chunks;
        1824               0 :         tmp.num_boxes += boxes->num_boxes;
        1825                 :
        1826               0 :         status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
        1827                 :                                                           CAIRO_FILL_RULE_WINDING,
        1828                 :                                                           &clear);
        1829                 :
        1830               0 :         tmp.chunks.next = NULL;
        1831                 :     } else {
        1832                 :         pixman_box32_t *pbox;
        1833                 :
        1834               0 :         pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
        1835               0 :         _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
        1836                 :
        1837               0 :         status = _cairo_boxes_add (&clear, &box);
        1838               0 :         assert (status == CAIRO_STATUS_SUCCESS);
        1839                 :
        1840               0 :         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
        1841               0 :             for (i = 0; i < chunk->count; i++) {
        1842               0 :                 status = _cairo_boxes_add (&clear, &chunk->base[i]);
        1843               0 :                 if (unlikely (status)) {
        1844               0 :                     _cairo_boxes_fini (&clear);
        1845               0 :                     return status;
        1846                 :                 }
        1847                 :             }
        1848                 :         }
        1849                 :
        1850               0 :         status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
        1851                 :                                                           CAIRO_FILL_RULE_WINDING,
        1852                 :                                                           &clear);
        1853                 :     }
        1854                 :
        1855               0 :     if (likely (status == CAIRO_STATUS_SUCCESS)) {
        1856               0 :         for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
        1857               0 :             for (i = 0; i < chunk->count; i++) {
        1858               0 :                 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
        1859               0 :                 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
        1860               0 :                 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
        1861               0 :                 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
        1862                 :
        1863               0 :                 pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
        1864               0 :                              PIXMAN_FORMAT_BPP (dst->pixman_format),
        1865                 :                              x1, y1, x2 - x1, y2 - y1,
        1866                 :                              0);
        1867                 :             }
        1868                 :         }
        1869                 :     }
        1870                 :
        1871               0 :     _cairo_boxes_fini (&clear);
        1872                 :
        1873               0 :     return status;
        1874                 : }
        1875                 :
        1876                 : static cairo_bool_t
        1877               0 : can_reduce_alpha_op (cairo_operator_t op)
        1878                 : {
        1879               0 :     int iop = op;
        1880               0 :     switch (iop) {
        1881                 :     case CAIRO_OPERATOR_OVER:
        1882                 :     case CAIRO_OPERATOR_SOURCE:
        1883                 :     case CAIRO_OPERATOR_ADD:
        1884               0 :         return TRUE;
        1885                 :     default:
        1886               0 :         return FALSE;
        1887                 :     }
        1888                 : }
        1889                 :
        1890                 : static cairo_bool_t
        1891               0 : reduce_alpha_op (cairo_image_surface_t *dst,
        1892                 :                  cairo_operator_t op,
        1893                 :                  const cairo_pattern_t *pattern)
        1894                 : {
        1895               0 :     return dst->base.is_clear &&
        1896               0 :            dst->base.content == CAIRO_CONTENT_ALPHA &&
        1897               0 :            _cairo_pattern_is_opaque_solid (pattern) &&
        1898               0 :            can_reduce_alpha_op (op);
        1899                 : }
        1900                 :
        1901                 : /* low level compositor */
        1902                 : typedef cairo_status_t
        1903                 : (*image_draw_func_t) (void                              *closure,
        1904                 :                       pixman_image_t                    *dst,
        1905                 :                       pixman_format_code_t               dst_format,
        1906                 :                       cairo_operator_t                   op,
        1907                 :                       const cairo_pattern_t             *src,
        1908                 :                       int                                dst_x,
        1909                 :                       int                                dst_y,
        1910                 :                       const cairo_rectangle_int_t       *extents,
        1911                 :                       cairo_region_t                    *clip_region);
        1912                 :
        1913                 : static pixman_image_t *
        1914               0 : _create_composite_mask_pattern (cairo_clip_t                  *clip,
        1915                 :                                 image_draw_func_t              draw_func,
        1916                 :                                 void                          *draw_closure,
        1917                 :                                 cairo_image_surface_t         *dst,
        1918                 :                                 const cairo_rectangle_int_t   *extents)
        1919                 : {
        1920               0 :     cairo_region_t *clip_region = NULL;
        1921                 :     pixman_image_t *mask;
        1922                 :     cairo_status_t status;
        1923               0 :     cairo_bool_t need_clip_surface = FALSE;
        1924                 :
        1925               0 :     if (clip != NULL) {
        1926               0 :         status = _cairo_clip_get_region (clip, &clip_region);
        1927               0 :         assert (! _cairo_status_is_error (status));
        1928                 :
        1929                 :         /* The all-clipped state should never propagate this far. */
        1930               0 :         assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
        1931                 :
        1932               0 :         need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
        1933                 :
        1934               0 :         if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
        1935               0 :             clip_region = NULL;
        1936                 :     }
        1937                 :
        1938               0 :     mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height,
        1939                 :                                      NULL, 0);
        1940               0 :     if (unlikely (mask == NULL))
        1941               0 :         return NULL;
        1942                 :
        1943                 :     /* Is it worth setting the clip region here? */
        1944               0 :     if (clip_region != NULL) {
        1945                 :         pixman_bool_t ret;
        1946                 :
        1947               0 :         pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y);
        1948               0 :         ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
        1949               0 :         pixman_region32_translate (&clip_region->rgn, extents->x, extents->y);
        1950                 :
        1951               0 :         if (! ret) {
        1952               0 :             pixman_image_unref (mask);
        1953               0 :             return NULL;
        1954                 :         }
        1955                 :     }
        1956                 :
        1957               0 :     status = draw_func (draw_closure,
        1958                 :                         mask, PIXMAN_a8,
        1959                 :                         CAIRO_OPERATOR_ADD, NULL,
        1960                 :                         extents->x, extents->y,
        1961                 :                         extents, NULL);
        1962               0 :     if (unlikely (status)) {
        1963               0 :         pixman_image_unref (mask);
        1964               0 :         return NULL;
        1965                 :     }
        1966                 :
        1967               0 :     if (need_clip_surface) {
        1968                 :         cairo_surface_t *tmp;
        1969                 :
        1970               0 :         tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
        1971               0 :         if (unlikely (tmp->status)) {
        1972               0 :             pixman_image_unref (mask);
        1973               0 :             return NULL;
        1974                 :         }
        1975                 :
        1976               0 :         pixman_image_ref (mask);
        1977                 :
        1978               0 :         status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y);
        1979               0 :         cairo_surface_destroy (tmp);
        1980               0 :         if (unlikely (status)) {
        1981               0 :             pixman_image_unref (mask);
        1982               0 :             return NULL;
        1983                 :         }
        1984                 :     }
        1985                 :
        1986               0 :     if (clip_region != NULL)
        1987               0 :         pixman_image_set_clip_region (mask, NULL);
        1988                 :
        1989               0 :     return mask;
        1990                 : }
        1991                 :
        1992                 : /* Handles compositing with a clip surface when the operator allows
        1993                 :  * us to combine the clip with the mask
        1994                 :  */
        1995                 : static cairo_status_t
        1996               0 : _clip_and_composite_with_mask (cairo_clip_t                  *clip,
        1997                 :                                cairo_operator_t               op,
        1998                 :                                const cairo_pattern_t         *pattern,
        1999                 :                                image_draw_func_t              draw_func,
        2000                 :                                void                          *draw_closure,
        2001                 :                                cairo_image_surface_t         *dst,
        2002                 :                                const cairo_rectangle_int_t   *extents)
        2003                 : {
        2004                 :     pixman_image_t *mask;
        2005                 :
        2006               0 :     mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
        2007               0 :     if (unlikely (mask == NULL))
        2008               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2009                 :
        2010               0 :     if (pattern == NULL) {
        2011               0 :         if (dst->pixman_format == PIXMAN_a8) {
        2012               0 :             pixman_image_composite32 (_pixman_operator (op),
        2013                 :                                       mask, NULL, dst->pixman_image,
        2014                 :                                       0, 0, 0, 0,
        2015                 :                                       extents->x,      extents->y,
        2016                 :                                       extents->width,  extents->height);
        2017                 :         } else {
        2018                 :             pixman_image_t *src;
        2019                 :
        2020               0 :             src = _pixman_white_image ();
        2021               0 :             if (unlikely (src == NULL)) {
        2022               0 :                 pixman_image_unref (mask);
        2023               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2024                 :             }
        2025                 :
        2026               0 :             pixman_image_composite32 (_pixman_operator (op),
        2027                 :                                       src, mask, dst->pixman_image,
        2028                 :                                       0, 0, 0, 0,
        2029                 :                                       extents->x,      extents->y,
        2030                 :                                       extents->width,  extents->height);
        2031               0 :             pixman_image_unref (src);
        2032                 :         }
        2033                 :     } else {
        2034                 :         pixman_image_t *src;
        2035                 :         int src_x, src_y;
        2036                 :
        2037               0 :         src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
        2038               0 :         if (unlikely (src == NULL)) {
        2039               0 :             pixman_image_unref (mask);
        2040               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2041                 :         }
        2042                 :
        2043               0 :         pixman_image_composite32 (_pixman_operator (op),
        2044                 :                                   src, mask, dst->pixman_image,
        2045               0 :                                   extents->x + src_x,  extents->y + src_y,
        2046                 :                                   0, 0,
        2047                 :                                   extents->x,          extents->y,
        2048                 :                                   extents->width,      extents->height);
        2049               0 :         pixman_image_unref (src);
        2050                 :     }
        2051                 :
        2052               0 :     pixman_image_unref (mask);
        2053                 :
        2054               0 :     return CAIRO_STATUS_SUCCESS;
        2055                 : }
        2056                 :
        2057                 : /* Handles compositing with a clip surface when we have to do the operation
        2058                 :  * in two pieces and combine them together.
        2059                 :  */
        2060                 : static cairo_status_t
        2061               0 : _clip_and_composite_combine (cairo_clip_t                  *clip,
        2062                 :                              cairo_operator_t               op,
        2063                 :                              const cairo_pattern_t         *src,
        2064                 :                              image_draw_func_t              draw_func,
        2065                 :                              void                          *draw_closure,
        2066                 :                              cairo_image_surface_t               *dst,
        2067                 :                              const cairo_rectangle_int_t   *extents)
        2068                 : {
        2069                 :     pixman_image_t *tmp;
        2070                 :     cairo_surface_t *clip_surface;
        2071                 :     int clip_x, clip_y;
        2072                 :     cairo_status_t status;
        2073                 :
        2074               0 :     tmp  = pixman_image_create_bits (dst->pixman_format,
        2075                 :                                      extents->width, extents->height,
        2076                 :                                      NULL, 0);
        2077               0 :     if (unlikely (tmp == NULL))
        2078               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2079                 :
        2080               0 :     if (src == NULL) {
        2081               0 :         status = (*draw_func) (draw_closure,
        2082                 :                                tmp, dst->pixman_format,
        2083                 :                                CAIRO_OPERATOR_ADD, NULL,
        2084                 :                                extents->x, extents->y,
        2085                 :                                extents, NULL);
        2086                 :     } else {
        2087                 :         /* Initialize the temporary surface from the destination surface */
        2088               0 :         if (! dst->base.is_clear) {
        2089               0 :             pixman_image_composite32 (PIXMAN_OP_SRC,
        2090                 :                                       dst->pixman_image, NULL, tmp,
        2091                 :                                       extents->x, extents->y,
        2092                 :                                       0, 0,
        2093                 :                                       0, 0,
        2094                 :                                       extents->width, extents->height);
        2095                 :         }
        2096                 :
        2097               0 :         status = (*draw_func) (draw_closure,
        2098                 :                                tmp, dst->pixman_format,
        2099                 :                                op, src,
        2100                 :                                extents->x, extents->y,
        2101                 :                                extents, NULL);
        2102                 :     }
        2103               0 :     if (unlikely (status))
        2104               0 :         goto CLEANUP_SURFACE;
        2105                 :
        2106               0 :     assert (clip->path != NULL);
        2107               0 :     clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
        2108               0 :     if (unlikely (clip_surface->status))
        2109               0 :         goto CLEANUP_SURFACE;
        2110                 :
        2111               0 :     if (! dst->base.is_clear) {
        2112                 : #if PIXMAN_HAS_OP_LERP
        2113                 :         pixman_image_composite32 (PIXMAN_OP_LERP,
        2114                 :                                   tmp,
        2115                 :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
        2116                 :                                   dst->pixman_image,
        2117                 :                                   0, 0,
        2118                 :                                   extents->x - clip_x,
        2119                 :                                   extents->y - clip_y,
        2120                 :                                   extents->x, extents->y,
        2121                 :                                   extents->width, extents->height);
        2122                 : #else
        2123                 :         /* Punch the clip out of the destination */
        2124               0 :         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
        2125               0 :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
        2126                 :                                   NULL, dst->pixman_image,
        2127               0 :                                   extents->x - clip_x,
        2128               0 :                                   extents->y - clip_y,
        2129                 :                                   0, 0,
        2130                 :                                   extents->x, extents->y,
        2131                 :                                   extents->width, extents->height);
        2132                 :
        2133                 :         /* Now add the two results together */
        2134               0 :         pixman_image_composite32 (PIXMAN_OP_ADD,
        2135                 :                                   tmp,
        2136               0 :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
        2137                 :                                   dst->pixman_image,
        2138                 :                                   0, 0,
        2139               0 :                                   extents->x - clip_x,
        2140               0 :                                   extents->y - clip_y,
        2141                 :                                   extents->x, extents->y,
        2142                 :                                   extents->width, extents->height);
        2143                 : #endif
        2144                 :     } else {
        2145               0 :         pixman_image_composite32 (PIXMAN_OP_SRC,
        2146                 :                                   tmp,
        2147               0 :                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
        2148                 :                                   dst->pixman_image,
        2149                 :                                   0, 0,
        2150               0 :                                   extents->x - clip_x,
        2151               0 :                                   extents->y - clip_y,
        2152                 :                                   extents->x, extents->y,
        2153                 :                                   extents->width, extents->height);
        2154                 :     }
        2155                 :
        2156                 :  CLEANUP_SURFACE:
        2157               0 :     pixman_image_unref (tmp);
        2158                 :
        2159               0 :     return status;
        2160                 : }
        2161                 :
        2162                 : /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
        2163                 :  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
        2164                 :  */
        2165                 : static cairo_status_t
        2166               0 : _clip_and_composite_source (cairo_clip_t                  *clip,
        2167                 :                             const cairo_pattern_t         *pattern,
        2168                 :                             image_draw_func_t              draw_func,
        2169                 :                             void                          *draw_closure,
        2170                 :                             cairo_image_surface_t         *dst,
        2171                 :                             const cairo_rectangle_int_t   *extents)
        2172                 : {
        2173                 :     pixman_image_t *mask, *src;
        2174                 :     int src_x, src_y;
        2175                 :
        2176               0 :     if (pattern == NULL) {
        2177                 :         cairo_region_t *clip_region;
        2178                 :         cairo_status_t status;
        2179                 :
        2180               0 :         status = draw_func (draw_closure,
        2181                 :                             dst->pixman_image, dst->pixman_format,
        2182                 :                             CAIRO_OPERATOR_SOURCE, NULL,
        2183                 :                             extents->x, extents->y,
        2184                 :                             extents, NULL);
        2185               0 :         if (unlikely (status))
        2186               0 :             return status;
        2187                 :
        2188               0 :         if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED)
        2189               0 :             status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0);
        2190                 :
        2191               0 :         return status;
        2192                 :     }
        2193                 :
        2194                 :     /* Create a surface that is mask IN clip */
        2195               0 :     mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
        2196               0 :     if (unlikely (mask == NULL))
        2197               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2198                 :
        2199               0 :     src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
        2200               0 :     if (unlikely (src == NULL)) {
        2201               0 :         pixman_image_unref (mask);
        2202               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2203                 :     }
        2204                 :
        2205               0 :     if (! dst->base.is_clear) {
        2206                 : #if PIXMAN_HAS_OP_LERP
        2207                 :         pixman_image_composite32 (PIXMAN_OP_LERP,
        2208                 :                                   src, mask, dst->pixman_image,
        2209                 :                                   extents->x + src_x, extents->y + src_y,
        2210                 :                                   0, 0,
        2211                 :                                   extents->x,     extents->y,
        2212                 :                                   extents->width, extents->height);
        2213                 : #else
        2214                 :         /* Compute dest' = dest OUT (mask IN clip) */
        2215               0 :         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
        2216                 :                                   mask, NULL, dst->pixman_image,
        2217                 :                                   0, 0, 0, 0,
        2218                 :                                   extents->x,     extents->y,
        2219                 :                                   extents->width, extents->height);
        2220                 :
        2221                 :         /* Now compute (src IN (mask IN clip)) ADD dest' */
        2222               0 :         pixman_image_composite32 (PIXMAN_OP_ADD,
        2223                 :                                   src, mask, dst->pixman_image,
        2224               0 :                                   extents->x + src_x, extents->y + src_y,
        2225                 :                                   0, 0,
        2226                 :                                   extents->x,     extents->y,
        2227                 :                                   extents->width, extents->height);
        2228                 : #endif
        2229                 :     } else {
        2230               0 :         pixman_image_composite32 (PIXMAN_OP_SRC,
        2231                 :                                   src, mask, dst->pixman_image,
        2232               0 :                                   extents->x + src_x, extents->y + src_y,
        2233                 :                                   0, 0,
        2234                 :                                   extents->x,     extents->y,
        2235                 :                                   extents->width, extents->height);
        2236                 :     }
        2237                 :
        2238               0 :     pixman_image_unref (src);
        2239               0 :     pixman_image_unref (mask);
        2240                 :
        2241               0 :     return CAIRO_STATUS_SUCCESS;
        2242                 : }
        2243                 :
        2244                 : static cairo_status_t
        2245               0 : _clip_and_composite (cairo_image_surface_t      *dst,
        2246                 :                      cairo_operator_t            op,
        2247                 :                      const cairo_pattern_t      *src,
        2248                 :                      image_draw_func_t           draw_func,
        2249                 :                      void                       *draw_closure,
        2250                 :                      cairo_composite_rectangles_t*extents,
        2251                 :                      cairo_clip_t               *clip)
        2252                 : {
        2253                 :     cairo_status_t status;
        2254               0 :     cairo_region_t *clip_region = NULL;
        2255               0 :     cairo_bool_t need_clip_surface = FALSE;
        2256                 :
        2257               0 :     if (clip != NULL) {
        2258               0 :         status = _cairo_clip_get_region (clip, &clip_region);
        2259               0 :         if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
        2260               0 :             return CAIRO_STATUS_SUCCESS;
        2261               0 :         if (unlikely (_cairo_status_is_error (status)))
        2262               0 :             return status;
        2263                 :
        2264               0 :         need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
        2265                 :
        2266               0 :         if (clip_region != NULL) {
        2267                 :             cairo_rectangle_int_t rect;
        2268                 :             cairo_bool_t is_empty;
        2269                 :
        2270               0 :             cairo_region_get_extents (clip_region, &rect);
        2271               0 :             is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect);
        2272               0 :             if (unlikely (is_empty))
        2273               0 :                 return CAIRO_STATUS_SUCCESS;
        2274                 :
        2275               0 :             is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect);
        2276               0 :             if (unlikely (is_empty && extents->is_bounded))
        2277               0 :                 return CAIRO_STATUS_SUCCESS;
        2278                 :
        2279               0 :             if (cairo_region_num_rectangles (clip_region) == 1)
        2280               0 :                 clip_region = NULL;
        2281                 :         }
        2282                 :     }
        2283                 :
        2284               0 :     if (clip_region != NULL) {
        2285               0 :         status = _cairo_image_surface_set_clip_region (dst, clip_region);
        2286               0 :         if (unlikely (status))
        2287               0 :             return status;
        2288                 :     }
        2289                 :
        2290               0 :     if (reduce_alpha_op (dst, op, src)) {
        2291               0 :         op = CAIRO_OPERATOR_ADD;
        2292               0 :         src = NULL;
        2293                 :     }
        2294                 :
        2295               0 :     if (op == CAIRO_OPERATOR_SOURCE) {
        2296               0 :         status = _clip_and_composite_source (clip, src,
        2297                 :                                              draw_func, draw_closure,
        2298               0 :                                              dst, &extents->bounded);
        2299                 :     } else {
        2300               0 :         if (op == CAIRO_OPERATOR_CLEAR) {
        2301               0 :             src = NULL;
        2302               0 :             op = CAIRO_OPERATOR_DEST_OUT;
        2303                 :         }
        2304                 :
        2305               0 :         if (need_clip_surface) {
        2306               0 :             if (extents->is_bounded) {
        2307               0 :                 status = _clip_and_composite_with_mask (clip, op, src,
        2308                 :                                                         draw_func, draw_closure,
        2309               0 :                                                         dst, &extents->bounded);
        2310                 :             } else {
        2311               0 :                 status = _clip_and_composite_combine (clip, op, src,
        2312                 :                                                       draw_func, draw_closure,
        2313               0 :                                                       dst, &extents->bounded);
        2314                 :             }
        2315                 :         } else {
        2316               0 :             status = draw_func (draw_closure,
        2317                 :                                 dst->pixman_image, dst->pixman_format,
        2318                 :                                 op, src,
        2319                 :                                 0, 0,
        2320               0 :                                 &extents->bounded,
        2321                 :                                 clip_region);
        2322                 :         }
        2323                 :     }
        2324                 :
        2325               0 :     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
        2326               0 :         status = _cairo_image_surface_fixup_unbounded (dst, extents,
        2327                 :                                                        need_clip_surface ? clip : NULL);
        2328                 :     }
        2329                 :
        2330               0 :     if (clip_region != NULL)
        2331               0 :         _cairo_image_surface_unset_clip_region (dst);
        2332                 :
        2333               0 :     return status;
        2334                 : }
        2335                 :
        2336                 : #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
        2337                 : #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
        2338                 :
        2339                 : static cairo_bool_t
        2340               0 : _line_exceeds_16_16 (const cairo_line_t *line)
        2341                 : {
        2342               0 :     return
        2343               0 :         line->p1.x <= CAIRO_FIXED_16_16_MIN ||
        2344               0 :         line->p1.x >= CAIRO_FIXED_16_16_MAX ||
        2345                 :
        2346               0 :         line->p2.x <= CAIRO_FIXED_16_16_MIN ||
        2347               0 :         line->p2.x >= CAIRO_FIXED_16_16_MAX ||
        2348                 :
        2349               0 :         line->p1.y <= CAIRO_FIXED_16_16_MIN ||
        2350               0 :         line->p1.y >= CAIRO_FIXED_16_16_MAX ||
        2351                 :
        2352               0 :         line->p2.y <= CAIRO_FIXED_16_16_MIN ||
        2353               0 :         line->p2.y >= CAIRO_FIXED_16_16_MAX;
        2354                 : }
        2355                 :
        2356                 : static void
        2357               0 : _project_line_x_onto_16_16 (const cairo_line_t *line,
        2358                 :                             cairo_fixed_t top,
        2359                 :                             cairo_fixed_t bottom,
        2360                 :                             pixman_line_fixed_t *out)
        2361                 : {
        2362                 :     cairo_point_double_t p1, p2;
        2363                 :     double m;
        2364                 :
        2365               0 :     p1.x = _cairo_fixed_to_double (line->p1.x);
        2366               0 :     p1.y = _cairo_fixed_to_double (line->p1.y);
        2367                 :
        2368               0 :     p2.x = _cairo_fixed_to_double (line->p2.x);
        2369               0 :     p2.y = _cairo_fixed_to_double (line->p2.y);
        2370                 :
        2371               0 :     m = (p2.x - p1.x) / (p2.y - p1.y);
        2372               0 :     out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
        2373               0 :     out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
        2374               0 : }
        2375                 :
        2376                 :
        2377                 : typedef struct {
        2378                 :     cairo_trapezoid_t *traps;
        2379                 :     int num_traps;
        2380                 :     cairo_antialias_t antialias;
        2381                 : } composite_traps_info_t;
        2382                 :
        2383                 : static void
        2384               0 : _pixman_image_add_traps (pixman_image_t *image,
        2385                 :                          int dst_x, int dst_y,
        2386                 :                          composite_traps_info_t *info)
        2387                 : {
        2388               0 :     cairo_trapezoid_t *t = info->traps;
        2389               0 :     int num_traps = info->num_traps;
        2390               0 :     while (num_traps--) {
        2391                 :         pixman_trapezoid_t trap;
        2392                 :
        2393                 :         /* top/bottom will be clamped to surface bounds */
        2394               0 :         trap.top = _cairo_fixed_to_16_16 (t->top);
        2395               0 :         trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
        2396                 :
        2397                 :         /* However, all the other coordinates will have been left untouched so
        2398                 :          * as not to introduce numerical error. Recompute them if they
        2399                 :          * exceed the 16.16 limits.
        2400                 :          */
        2401               0 :         if (unlikely (_line_exceeds_16_16 (&t->left))) {
        2402               0 :             _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
        2403               0 :             trap.left.p1.y = trap.top;
        2404               0 :             trap.left.p2.y = trap.bottom;
        2405                 :         } else {
        2406               0 :             trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
        2407               0 :             trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
        2408               0 :             trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
        2409               0 :             trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
        2410                 :         }
        2411                 :
        2412               0 :         if (unlikely (_line_exceeds_16_16 (&t->right))) {
        2413               0 :             _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
        2414               0 :             trap.right.p1.y = trap.top;
        2415               0 :             trap.right.p2.y = trap.bottom;
        2416                 :         } else {
        2417               0 :             trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
        2418               0 :             trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
        2419               0 :             trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
        2420               0 :             trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
        2421                 :         }
        2422                 :
        2423               0 :         pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
        2424                 :
        2425               0 :         t++;
        2426                 :     }
        2427               0 : }
        2428                 :
        2429                 : static cairo_status_t
        2430               0 : _composite_traps (void                          *closure,
        2431                 :                   pixman_image_t                *dst,
        2432                 :                   pixman_format_code_t           dst_format,
        2433                 :                   cairo_operator_t               op,
        2434                 :                   const cairo_pattern_t         *pattern,
        2435                 :                   int                            dst_x,
        2436                 :                   int                            dst_y,
        2437                 :                   const cairo_rectangle_int_t   *extents,
        2438                 :                   cairo_region_t                *clip_region)
        2439                 : {
        2440               0 :     composite_traps_info_t *info = closure;
        2441                 :     pixman_image_t *src, *mask;
        2442                 :     pixman_format_code_t format;
        2443               0 :     int src_x = 0, src_y = 0;
        2444                 :     cairo_status_t status;
        2445                 :
        2446                 :     /* Special case adding trapezoids onto a mask surface; we want to avoid
        2447                 :      * creating an intermediate temporary mask unnecessarily.
        2448                 :      *
        2449                 :      * We make the assumption here that the portion of the trapezoids
        2450                 :      * contained within the surface is bounded by [dst_x,dst_y,width,height];
        2451                 :      * the Cairo core code passes bounds based on the trapezoid extents.
        2452                 :      */
        2453               0 :     format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
        2454               0 :     if (dst_format == format &&
        2455               0 :         (pattern == NULL ||
        2456               0 :          (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
        2457                 :     {
        2458               0 :         _pixman_image_add_traps (dst, dst_x, dst_y, info);
        2459               0 :         return CAIRO_STATUS_SUCCESS;
        2460                 :     }
        2461                 :
        2462               0 :     src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
        2463               0 :     if (unlikely (src == NULL))
        2464               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2465                 :
        2466               0 :     mask = pixman_image_create_bits (format, extents->width, extents->height,
        2467                 :                                      NULL, 0);
        2468               0 :     if (unlikely (mask == NULL)) {
        2469               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2470               0 :         goto CLEANUP_SOURCE;
        2471                 :     }
        2472                 :
        2473               0 :     _pixman_image_add_traps (mask, extents->x, extents->y, info);
        2474               0 :     pixman_image_composite32 (_pixman_operator (op),
        2475                 :                               src, mask, dst,
        2476               0 :                               extents->x + src_x, extents->y + src_y,
        2477                 :                               0, 0,
        2478               0 :                               extents->x - dst_x, extents->y - dst_y,
        2479                 :                               extents->width, extents->height);
        2480                 :
        2481               0 :     pixman_image_unref (mask);
        2482                 :
        2483               0 :     status = CAIRO_STATUS_SUCCESS;
        2484                 :  CLEANUP_SOURCE:
        2485               0 :     pixman_image_unref (src);
        2486                 :
        2487               0 :     return status;
        2488                 : }
        2489                 :
        2490                 : static inline uint32_t
        2491               0 : color_to_uint32 (const cairo_color_t *color)
        2492                 : {
        2493               0 :     return
        2494               0 :         (color->alpha_short >> 8 << 24) |
        2495               0 :         (color->red_short >> 8 << 16)   |
        2496               0 :         (color->green_short & 0xff00)   |
        2497               0 :         (color->blue_short >> 8);
        2498                 : }
        2499                 :
        2500                 : static inline cairo_bool_t
        2501               0 : color_to_pixel (const cairo_color_t     *color,
        2502                 :                 pixman_format_code_t     format,
        2503                 :                 uint32_t                *pixel)
        2504                 : {
        2505                 :     uint32_t c;
        2506                 :
        2507               0 :     if (!(format == PIXMAN_a8r8g8b8     ||
        2508               0 :           format == PIXMAN_x8r8g8b8     ||
        2509               0 :           format == PIXMAN_a8b8g8r8     ||
        2510               0 :           format == PIXMAN_x8b8g8r8     ||
        2511               0 :           format == PIXMAN_b8g8r8a8     ||
        2512               0 :           format == PIXMAN_b8g8r8x8     ||
        2513               0 :           format == PIXMAN_r5g6b5       ||
        2514                 :           format == PIXMAN_b5g6r5       ||
        2515                 :           format == PIXMAN_a8))
        2516                 :     {
        2517               0 :         return FALSE;
        2518                 :     }
        2519                 :
        2520               0 :     c = color_to_uint32 (color);
        2521                 :
        2522               0 :     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
        2523               0 :         c = ((c & 0xff000000) >>  0) |
        2524               0 :             ((c & 0x00ff0000) >> 16) |
        2525               0 :             ((c & 0x0000ff00) >>  0) |
        2526               0 :             ((c & 0x000000ff) << 16);
        2527                 :     }
        2528                 :
        2529               0 :     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
        2530               0 :         c = ((c & 0xff000000) >> 24) |
        2531               0 :             ((c & 0x00ff0000) >>  8) |
        2532               0 :             ((c & 0x0000ff00) <<  8) |
        2533               0 :             ((c & 0x000000ff) << 24);
        2534                 :     }
        2535                 :
        2536               0 :     if (format == PIXMAN_a8) {
        2537               0 :         c = c >> 24;
        2538               0 :     } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
        2539               0 :         c = ((((c) >> 3) & 0x001f) |
        2540               0 :              (((c) >> 5) & 0x07e0) |
        2541               0 :              (((c) >> 8) & 0xf800));
        2542                 :     }
        2543                 :
        2544               0 :     *pixel = c;
        2545               0 :     return TRUE;
        2546                 : }
        2547                 :
        2548                 : static inline cairo_bool_t
        2549              64 : pattern_to_pixel (const cairo_solid_pattern_t *solid,
        2550                 :                   cairo_operator_t op,
        2551                 :                   pixman_format_code_t format,
        2552                 :                   uint32_t *pixel)
        2553                 : {
        2554              64 :     if (op == CAIRO_OPERATOR_CLEAR) {
        2555              17 :         *pixel = 0;
        2556              17 :         return TRUE;
        2557                 :     }
        2558                 :
        2559              47 :     if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
        2560              47 :         return FALSE;
        2561                 :
        2562               0 :     if (op == CAIRO_OPERATOR_OVER) {
        2563               0 :         if (solid->color.alpha_short >= 0xff00)
        2564               0 :             op = CAIRO_OPERATOR_SOURCE;
        2565                 :     }
        2566                 :
        2567               0 :     if (op != CAIRO_OPERATOR_SOURCE)
        2568               0 :         return FALSE;
        2569                 :
        2570               0 :     return color_to_pixel (&solid->color, format, pixel);
        2571                 : }
        2572                 :
        2573                 : typedef struct _fill_span {
        2574                 :     cairo_span_renderer_t base;
        2575                 :
        2576                 :     uint8_t *mask_data;
        2577                 :     pixman_image_t *src, *dst, *mask;
        2578                 : } fill_span_renderer_t;
        2579                 :
        2580                 : static cairo_status_t
        2581               0 : _fill_span (void *abstract_renderer,
        2582                 :             int y, int height,
        2583                 :             const cairo_half_open_span_t *spans,
        2584                 :             unsigned num_spans)
        2585                 : {
        2586               0 :     fill_span_renderer_t *renderer = abstract_renderer;
        2587                 :     uint8_t *row;
        2588                 :     unsigned i;
        2589                 :
        2590               0 :     if (num_spans == 0)
        2591               0 :         return CAIRO_STATUS_SUCCESS;
        2592                 :
        2593               0 :     row = renderer->mask_data - spans[0].x;
        2594               0 :     for (i = 0; i < num_spans - 1; i++) {
        2595                 :         /* We implement setting the most common single pixel wide
        2596                 :          * span case to avoid the overhead of a memset call.
        2597                 :          * Open coding setting longer spans didn't show a
        2598                 :          * noticeable improvement over memset.
        2599                 :          */
        2600               0 :         if (spans[i+1].x == spans[i].x + 1) {
        2601               0 :             row[spans[i].x] = spans[i].coverage;
        2602                 :         } else {
        2603               0 :             memset (row + spans[i].x,
        2604               0 :                     spans[i].coverage,
        2605               0 :                     spans[i+1].x - spans[i].x);
        2606                 :         }
        2607                 :     }
        2608                 :
        2609                 :     do {
        2610               0 :         pixman_image_composite32 (PIXMAN_OP_OVER,
        2611                 :                                   renderer->src, renderer->mask, renderer->dst,
        2612                 :                                   0, 0, 0, 0,
        2613                 :                                   spans[0].x, y++,
        2614               0 :                                   spans[i].x - spans[0].x, 1);
        2615               0 :     } while (--height);
        2616                 :
        2617               0 :     return CAIRO_STATUS_SUCCESS;
        2618                 : }
        2619                 :
        2620                 : /* avoid using region code to re-validate boxes */
        2621                 : static cairo_status_t
        2622               0 : _fill_unaligned_boxes (cairo_image_surface_t *dst,
        2623                 :                        const cairo_pattern_t *pattern,
        2624                 :                        uint32_t pixel,
        2625                 :                        const cairo_boxes_t *boxes,
        2626                 :                        const cairo_composite_rectangles_t *extents)
        2627                 : {
        2628                 :     uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
        2629                 :     fill_span_renderer_t renderer;
        2630                 :     cairo_rectangular_scan_converter_t converter;
        2631                 :     const struct _cairo_boxes_chunk *chunk;
        2632                 :     cairo_status_t status;
        2633                 :     int i;
        2634                 :
        2635                 :     /* XXX
        2636                 :      * using composite for fill:
        2637                 :      *   spiral-box-nonalign-evenodd-fill.512    2201957    2.202
        2638                 :      *   spiral-box-nonalign-nonzero-fill.512     336726    0.337
        2639                 :      *   spiral-box-pixalign-evenodd-fill.512     352256    0.352
        2640                 :      *   spiral-box-pixalign-nonzero-fill.512     147056    0.147
        2641                 :      * using fill:
        2642                 :      *   spiral-box-nonalign-evenodd-fill.512    3174565    3.175
        2643                 :      *   spiral-box-nonalign-nonzero-fill.512     182710    0.183
        2644                 :      *   spiral-box-pixalign-evenodd-fill.512     353863    0.354
        2645                 :      *   spiral-box-pixalign-nonzero-fill.512     147402    0.147
        2646                 :      *
        2647                 :      * cairo-perf-trace seems to favour using fill.
        2648                 :      */
        2649                 :
        2650               0 :     renderer.base.render_rows = _fill_span;
        2651               0 :     renderer.dst = dst->pixman_image;
        2652                 :
        2653               0 :     if ((unsigned) extents->bounded.width <= sizeof (buf)) {
        2654               0 :         renderer.mask = pixman_image_create_bits (PIXMAN_a8,
        2655                 :                                                   extents->bounded.width, 1,
        2656                 :                                                   (uint32_t *) buf,
        2657                 :                                                   sizeof (buf));
        2658                 :     } else {
        2659               0 :         renderer.mask = pixman_image_create_bits (PIXMAN_a8,
        2660                 :                                                   extents->bounded.width, 1,
        2661                 :                                                   NULL,  0);
        2662                 :     }
        2663               0 :     if (unlikely (renderer.mask == NULL))
        2664               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2665                 :
        2666               0 :     renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
        2667                 :
        2668               0 :     renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
        2669               0 :     if (unlikely (renderer.src == NULL)) {
        2670               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2671               0 :         goto CLEANUP_MASK;
        2672                 :     }
        2673                 :
        2674               0 :     _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
        2675                 :
        2676                 :     /* first blit any aligned part of the boxes */
        2677               0 :     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
        2678               0 :         const cairo_box_t *box = chunk->base;
        2679                 :
        2680               0 :         for (i = 0; i < chunk->count; i++) {
        2681               0 :             int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
        2682               0 :             int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
        2683               0 :             int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
        2684               0 :             int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
        2685                 :
        2686               0 :             if (x2 > x1 && y2 > y1) {
        2687                 :                 cairo_box_t b;
        2688                 :
        2689               0 :                 pixman_fill ((uint32_t *) dst->data,
        2690               0 :                              dst->stride / sizeof (uint32_t),
        2691               0 :                              PIXMAN_FORMAT_BPP (dst->pixman_format),
        2692                 :                              x1, y1, x2 - x1, y2 - y1,
        2693                 :                              pixel);
        2694                 :
        2695                 :                 /* top */
        2696               0 :                 if (! _cairo_fixed_is_integer (box[i].p1.y)) {
        2697               0 :                     b.p1.x = box[i].p1.x;
        2698               0 :                     b.p1.y = box[i].p1.y;
        2699               0 :                     b.p2.x = box[i].p2.x;
        2700               0 :                     b.p2.y = _cairo_fixed_from_int (y1);
        2701                 :
        2702               0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
        2703               0 :                     if (unlikely (status))
        2704               0 :                         goto CLEANUP_CONVERTER;
        2705                 :                 }
        2706                 :
        2707                 :                 /* left */
        2708               0 :                 if (! _cairo_fixed_is_integer (box[i].p1.x)) {
        2709               0 :                     b.p1.x = box[i].p1.x;
        2710               0 :                     b.p1.y = box[i].p1.y;
        2711               0 :                     b.p2.x = _cairo_fixed_from_int (x1);
        2712               0 :                     b.p2.y = box[i].p2.y;
        2713                 :
        2714               0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
        2715               0 :                     if (unlikely (status))
        2716               0 :                         goto CLEANUP_CONVERTER;
        2717                 :                 }
        2718                 :
        2719                 :                 /* right */
        2720               0 :                 if (! _cairo_fixed_is_integer (box[i].p2.x)) {
        2721               0 :                     b.p1.x = _cairo_fixed_from_int (x2);
        2722               0 :                     b.p1.y = box[i].p1.y;
        2723               0 :                     b.p2.x = box[i].p2.x;
        2724               0 :                     b.p2.y = box[i].p2.y;
        2725                 :
        2726               0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
        2727               0 :                     if (unlikely (status))
        2728               0 :                         goto CLEANUP_CONVERTER;
        2729                 :                 }
        2730                 :
        2731                 :                 /* bottom */
        2732               0 :                 if (! _cairo_fixed_is_integer (box[i].p2.y)) {
        2733               0 :                     b.p1.x = box[i].p1.x;
        2734               0 :                     b.p1.y = _cairo_fixed_from_int (y2);
        2735               0 :                     b.p2.x = box[i].p2.x;
        2736               0 :                     b.p2.y = box[i].p2.y;
        2737                 :
        2738               0 :                     status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
        2739               0 :                     if (unlikely (status))
        2740               0 :                         goto CLEANUP_CONVERTER;
        2741                 :                 }
        2742                 :             } else {
        2743               0 :                 status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
        2744               0 :                 if (unlikely (status))
        2745               0 :                     goto CLEANUP_CONVERTER;
        2746                 :             }
        2747                 :         }
        2748                 :     }
        2749                 :
        2750               0 :     status = converter.base.generate (&converter.base, &renderer.base);
        2751                 :
        2752                 :   CLEANUP_CONVERTER:
        2753               0 :     converter.base.destroy (&converter.base);
        2754               0 :     pixman_image_unref (renderer.src);
        2755                 :   CLEANUP_MASK:
        2756               0 :     pixman_image_unref (renderer.mask);
        2757                 :
        2758               0 :     return status;
        2759                 : }
        2760                 :
        2761                 : typedef struct _cairo_image_surface_span_renderer {
        2762                 :     cairo_span_renderer_t base;
        2763                 :
        2764                 :     uint8_t *mask_data;
        2765                 :     uint32_t mask_stride;
        2766                 : } cairo_image_surface_span_renderer_t;
        2767                 :
        2768                 : cairo_status_t
        2769               0 : _cairo_image_surface_span (void *abstract_renderer,
        2770                 :                            int y, int height,
        2771                 :                            const cairo_half_open_span_t *spans,
        2772                 :                            unsigned num_spans)
        2773                 : {
        2774               0 :     cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
        2775                 :     uint8_t *row;
        2776                 :     unsigned i;
        2777                 :
        2778               0 :     if (num_spans == 0)
        2779               0 :         return CAIRO_STATUS_SUCCESS;
        2780                 :
        2781                 :     /* XXX will it be quicker to repeat the sparse memset,
        2782                 :      * or perform a simpler memcpy?
        2783                 :      * The fairly dense spiral benchmarks suggests that the sparse
        2784                 :      * memset is a win there as well.
        2785                 :      */
        2786               0 :     row = renderer->mask_data + y * renderer->mask_stride;
        2787                 :     do {
        2788               0 :         for (i = 0; i < num_spans - 1; i++) {
        2789               0 :             if (! spans[i].coverage)
        2790               0 :                 continue;
        2791                 :
        2792                 :             /* We implement setting rendering the most common single
        2793                 :              * pixel wide span case to avoid the overhead of a memset
        2794                 :              * call.  Open coding setting longer spans didn't show a
        2795                 :              * noticeable improvement over memset. */
        2796               0 :             if (spans[i+1].x == spans[i].x + 1) {
        2797               0 :                 row[spans[i].x] = spans[i].coverage;
        2798                 :             } else {
        2799               0 :                 memset (row + spans[i].x,
        2800               0 :                         spans[i].coverage,
        2801               0 :                         spans[i+1].x - spans[i].x);
        2802                 :             }
        2803                 :         }
        2804               0 :         row += renderer->mask_stride;
        2805               0 :     } while (--height);
        2806                 :
        2807               0 :     return CAIRO_STATUS_SUCCESS;
        2808                 : }
        2809                 :
        2810                 : static cairo_status_t
        2811               0 : _composite_unaligned_boxes (cairo_image_surface_t *dst,
        2812                 :                             cairo_operator_t op,
        2813                 :                             const cairo_pattern_t *pattern,
        2814                 :                             const cairo_boxes_t *boxes,
        2815                 :                             const cairo_composite_rectangles_t *extents)
        2816                 : {
        2817                 :     uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
        2818                 :     cairo_image_surface_span_renderer_t renderer;
        2819                 :     cairo_rectangular_scan_converter_t converter;
        2820                 :     pixman_image_t *mask, *src;
        2821                 :     cairo_status_t status;
        2822                 :     const struct _cairo_boxes_chunk *chunk;
        2823                 :     int i, src_x, src_y;
        2824                 :
        2825               0 :     i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
        2826               0 :     if ((unsigned) i <= sizeof (buf)) {
        2827               0 :         mask = pixman_image_create_bits (PIXMAN_a8,
        2828                 :                                          extents->bounded.width,
        2829                 :                                          extents->bounded.height,
        2830                 :                                          (uint32_t *) buf,
        2831               0 :                                          CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
        2832               0 :         memset (buf, 0, i);
        2833                 :     } else {
        2834               0 :         mask = pixman_image_create_bits (PIXMAN_a8,
        2835                 :                                          extents->bounded.width,
        2836                 :                                          extents->bounded.height,
        2837                 :                                          NULL,  0);
        2838                 :     }
        2839               0 :     if (unlikely (mask == NULL))
        2840               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2841                 :
        2842               0 :     renderer.base.render_rows = _cairo_image_surface_span;
        2843               0 :     renderer.mask_stride = pixman_image_get_stride (mask);
        2844               0 :     renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
        2845               0 :     renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
        2846                 :
        2847               0 :     _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
        2848                 :
        2849               0 :     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
        2850               0 :         const cairo_box_t *box = chunk->base;
        2851                 :
        2852               0 :         for (i = 0; i < chunk->count; i++) {
        2853               0 :             status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
        2854               0 :             if (unlikely (status))
        2855               0 :                 goto CLEANUP;
        2856                 :         }
        2857                 :     }
        2858                 :
        2859               0 :     status = converter.base.generate (&converter.base, &renderer.base);
        2860               0 :     if (unlikely (status))
        2861               0 :         goto CLEANUP;
        2862                 :
        2863               0 :     src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
        2864               0 :     if (unlikely (src == NULL)) {
        2865               0 :         status =  _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2866               0 :         goto CLEANUP;
        2867                 :     }
        2868                 :
        2869               0 :     pixman_image_composite32 (_pixman_operator (op),
        2870                 :                               src, mask, dst->pixman_image,
        2871               0 :                               extents->bounded.x + src_x, extents->bounded.y + src_y,
        2872                 :                               0, 0,
        2873                 :                               extents->bounded.x, extents->bounded.y,
        2874                 :                               extents->bounded.width, extents->bounded.height);
        2875               0 :     pixman_image_unref (src);
        2876                 :
        2877                 :   CLEANUP:
        2878               0 :     converter.base.destroy (&converter.base);
        2879               0 :     pixman_image_unref (mask);
        2880                 :
        2881               0 :     return status;
        2882                 : }
        2883                 :
        2884                 : static cairo_status_t
        2885              64 : _composite_boxes (cairo_image_surface_t *dst,
        2886                 :                   cairo_operator_t op,
        2887                 :                   const cairo_pattern_t *pattern,
        2888                 :                   cairo_boxes_t *boxes,
        2889                 :                   cairo_antialias_t antialias,
        2890                 :                   cairo_clip_t *clip,
        2891                 :                   const cairo_composite_rectangles_t *extents)
        2892                 : {
        2893              64 :     cairo_region_t *clip_region = NULL;
        2894              64 :     cairo_bool_t need_clip_mask = FALSE;
        2895                 :     cairo_status_t status;
        2896                 :     struct _cairo_boxes_chunk *chunk;
        2897                 :     uint32_t pixel;
        2898                 :     int i;
        2899                 :
        2900              64 :     if (clip != NULL) {
        2901               0 :         status = _cairo_clip_get_region (clip, &clip_region);
        2902               0 :         need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
        2903               0 :         if (need_clip_mask &&
        2904               0 :             (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
        2905                 :         {
        2906               0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
        2907                 :         }
        2908                 :
        2909               0 :         if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
        2910               0 :             clip_region = NULL;
        2911                 :     }
        2912                 :
        2913              64 :     if (antialias != CAIRO_ANTIALIAS_NONE) {
        2914              64 :         if (! boxes->is_pixel_aligned) {
        2915               0 :             if (need_clip_mask)
        2916               0 :                 return CAIRO_INT_STATUS_UNSUPPORTED;
        2917                 :
        2918               0 :             if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
        2919                 :                                   dst->pixman_format, &pixel))
        2920                 :             {
        2921               0 :                 return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
        2922                 :             }
        2923                 :             else
        2924                 :             {
        2925               0 :                 return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
        2926                 :             }
        2927                 :         }
        2928                 :     }
        2929                 :
        2930              64 :     status = CAIRO_STATUS_SUCCESS;
        2931             145 :     if (! need_clip_mask &&
        2932              64 :         pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
        2933                 :                           &pixel))
        2934                 :     {
        2935              34 :         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
        2936              17 :             cairo_box_t *box = chunk->base;
        2937                 :
        2938              34 :             for (i = 0; i < chunk->count; i++) {
        2939              17 :                 int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
        2940              17 :                 int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
        2941              17 :                 int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
        2942              17 :                 int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
        2943                 :
        2944              17 :                 if (x2 == x1 || y2 == y1)
        2945               0 :                     continue;
        2946                 :
        2947              34 :                 pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
        2948              17 :                              PIXMAN_FORMAT_BPP (dst->pixman_format),
        2949                 :                              x1, y1, x2 - x1, y2 - y1,
        2950                 :                              pixel);
        2951                 :             }
        2952                 :         }
        2953                 :     }
        2954                 :     else
        2955                 :     {
        2956              47 :         pixman_image_t *src = NULL, *mask = NULL;
        2957              47 :         int src_x, src_y, mask_x = 0, mask_y = 0;
        2958              47 :         pixman_op_t pixman_op = _pixman_operator (op);
        2959                 :
        2960              47 :         if (need_clip_mask) {
        2961                 :             cairo_surface_t *clip_surface;
        2962                 :             int clip_x, clip_y;
        2963                 :
        2964               0 :             clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
        2965               0 :             if (unlikely (clip_surface->status))
        2966               0 :                 return clip_surface->status;
        2967                 :
        2968               0 :             mask_x = -clip_x;
        2969               0 :             mask_y = -clip_y;
        2970                 :
        2971               0 :             if (op == CAIRO_OPERATOR_CLEAR) {
        2972               0 :                 pattern = NULL;
        2973               0 :                 pixman_op = PIXMAN_OP_OUT_REVERSE;
        2974                 :             }
        2975                 :
        2976               0 :             mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
        2977                 :         }
        2978                 :
        2979              47 :         if (pattern != NULL) {
        2980              47 :             src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y);
        2981              47 :             if (unlikely (src == NULL))
        2982               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        2983                 :         } else {
        2984               0 :             src = mask;
        2985               0 :             src_x = mask_x;
        2986               0 :             src_y = mask_y;
        2987               0 :             mask = NULL;
        2988                 :         }
        2989                 :
        2990              94 :         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
        2991              47 :             const cairo_box_t *box = chunk->base;
        2992                 :
        2993              94 :             for (i = 0; i < chunk->count; i++) {
        2994              47 :                 int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
        2995              47 :                 int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
        2996              47 :                 int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
        2997              47 :                 int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
        2998                 :
        2999              47 :                 if (x2 == x1 || y2 == y1)
        3000               0 :                     continue;
        3001                 :
        3002              47 :                 pixman_image_composite32 (pixman_op,
        3003                 :                                           src, mask, dst->pixman_image,
        3004                 :                                           x1 + src_x,  y1 + src_y,
        3005                 :                                           x1 + mask_x, y1 + mask_y,
        3006                 :                                           x1, y1,
        3007                 :                                           x2 - x1, y2 - y1);
        3008                 :             }
        3009                 :         }
        3010                 :
        3011              47 :         if (pattern != NULL)
        3012              47 :             pixman_image_unref (src);
        3013                 :
        3014              47 :         if (! extents->is_bounded) {
        3015               0 :             status =
        3016               0 :                 _cairo_image_surface_fixup_unbounded_boxes (dst, extents,
        3017                 :                                                             clip_region, boxes);
        3018                 :         }
        3019                 :     }
        3020                 :
        3021              64 :     return status;
        3022                 : }
        3023                 :
        3024                 : static cairo_status_t
        3025              64 : _clip_and_composite_boxes (cairo_image_surface_t *dst,
        3026                 :                            cairo_operator_t op,
        3027                 :                            const cairo_pattern_t *src,
        3028                 :                            cairo_boxes_t *boxes,
        3029                 :                            cairo_antialias_t antialias,
        3030                 :                            cairo_composite_rectangles_t *extents,
        3031                 :                            cairo_clip_t *clip)
        3032                 : {
        3033                 :     cairo_traps_t traps;
        3034                 :     cairo_status_t status;
        3035                 :     composite_traps_info_t info;
        3036                 :
        3037              64 :     if (boxes->num_boxes == 0 && extents->is_bounded)
        3038               0 :         return CAIRO_STATUS_SUCCESS;
        3039                 :
        3040                 :     /* Use a fast path if the boxes are pixel aligned */
        3041              64 :     status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
        3042              64 :     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
        3043              64 :         return status;
        3044                 :
        3045                 :     /* Otherwise render via a mask and composite in the usual fashion.  */
        3046               0 :     status = _cairo_traps_init_boxes (&traps, boxes);
        3047               0 :     if (unlikely (status))
        3048               0 :         return status;
        3049                 :
        3050               0 :     info.num_traps = traps.num_traps;
        3051               0 :     info.traps = traps.traps;
        3052               0 :     info.antialias = antialias;
        3053               0 :     status = _clip_and_composite (dst, op, src,
        3054                 :                                   _composite_traps, &info,
        3055                 :                                   extents, clip);
        3056                 :
        3057               0 :     _cairo_traps_fini (&traps);
        3058               0 :     return status;
        3059                 : }
        3060                 :
        3061                 : static cairo_bool_t
        3062               0 : _mono_edge_is_vertical (const cairo_line_t *line)
        3063                 : {
        3064               0 :     return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
        3065                 : }
        3066                 :
        3067                 : static cairo_bool_t
        3068               0 : _traps_are_pixel_aligned (cairo_traps_t *traps,
        3069                 :                           cairo_antialias_t antialias)
        3070                 : {
        3071                 :     int i;
        3072                 :
        3073               0 :     if (antialias == CAIRO_ANTIALIAS_NONE) {
        3074               0 :         for (i = 0; i < traps->num_traps; i++) {
        3075               0 :             if (! _mono_edge_is_vertical (&traps->traps[i].left)   ||
        3076               0 :                 ! _mono_edge_is_vertical (&traps->traps[i].right))
        3077                 :             {
        3078               0 :                 traps->maybe_region = FALSE;
        3079               0 :                 return FALSE;
        3080                 :             }
        3081                 :         }
        3082                 :     } else {
        3083               0 :         for (i = 0; i < traps->num_traps; i++) {
        3084               0 :             if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
        3085               0 :                 traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
        3086               0 :                 ! _cairo_fixed_is_integer (traps->traps[i].top)          ||
        3087               0 :                 ! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
        3088               0 :                 ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
        3089               0 :                 ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
        3090                 :             {
        3091               0 :                 traps->maybe_region = FALSE;
        3092               0 :                 return FALSE;
        3093                 :             }
        3094                 :         }
        3095                 :     }
        3096                 :
        3097               0 :     return TRUE;
        3098                 : }
        3099                 :
        3100                 : static void
        3101               0 : _boxes_for_traps (cairo_boxes_t *boxes,
        3102                 :                   cairo_traps_t *traps,
        3103                 :                   cairo_antialias_t antialias)
        3104                 : {
        3105                 :     int i;
        3106                 :
        3107               0 :     _cairo_boxes_init (boxes);
        3108                 :
        3109               0 :     boxes->num_boxes    = traps->num_traps;
        3110               0 :     boxes->chunks.base  = (cairo_box_t *) traps->traps;
        3111               0 :     boxes->chunks.count = traps->num_traps;
        3112               0 :     boxes->chunks.size  = traps->num_traps;
        3113                 :
        3114               0 :     if (antialias != CAIRO_ANTIALIAS_NONE) {
        3115               0 :         for (i = 0; i < traps->num_traps; i++) {
        3116                 :             /* Note the traps and boxes alias so we need to take the local copies first. */
        3117               0 :             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
        3118               0 :             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
        3119               0 :             cairo_fixed_t y1 = traps->traps[i].top;
        3120               0 :             cairo_fixed_t y2 = traps->traps[i].bottom;
        3121                 :
        3122               0 :             boxes->chunks.base[i].p1.x = x1;
        3123               0 :             boxes->chunks.base[i].p1.y = y1;
        3124               0 :             boxes->chunks.base[i].p2.x = x2;
        3125               0 :             boxes->chunks.base[i].p2.y = y2;
        3126                 :
        3127               0 :             if (boxes->is_pixel_aligned) {
        3128               0 :                 boxes->is_pixel_aligned =
        3129               0 :                     _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
        3130               0 :                     _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
        3131                 :             }
        3132                 :         }
        3133                 :     } else {
        3134               0 :         boxes->is_pixel_aligned = TRUE;
        3135                 :
        3136               0 :         for (i = 0; i < traps->num_traps; i++) {
        3137                 :             /* Note the traps and boxes alias so we need to take the local copies first. */
        3138               0 :             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
        3139               0 :             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
        3140               0 :             cairo_fixed_t y1 = traps->traps[i].top;
        3141               0 :             cairo_fixed_t y2 = traps->traps[i].bottom;
        3142                 :
        3143                 :             /* round down here to match Pixman's behavior when using traps. */
        3144               0 :             boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
        3145               0 :             boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
        3146               0 :             boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
        3147               0 :             boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
        3148                 :         }
        3149                 :     }
        3150               0 : }
        3151                 :
        3152                 : static cairo_status_t
        3153               0 : _clip_and_composite_trapezoids (cairo_image_surface_t *dst,
        3154                 :                                 cairo_operator_t op,
        3155                 :                                 const cairo_pattern_t *src,
        3156                 :                                 cairo_traps_t *traps,
        3157                 :                                 cairo_antialias_t antialias,
        3158                 :                                 cairo_composite_rectangles_t *extents,
        3159                 :                                 cairo_clip_t *clip)
        3160                 : {
        3161                 :     composite_traps_info_t info;
        3162               0 :     cairo_bool_t need_clip_surface = FALSE;
        3163                 :     cairo_status_t status;
        3164                 :
        3165               0 :     if (traps->num_traps == 0 && extents->is_bounded)
        3166               0 :         return CAIRO_STATUS_SUCCESS;
        3167                 :
        3168               0 :     if (clip != NULL) {
        3169                 :         cairo_region_t *clip_region;
        3170                 :
        3171               0 :         status = _cairo_clip_get_region (clip, &clip_region);
        3172               0 :         need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
        3173                 :     }
        3174                 :
        3175               0 :     if (traps->has_intersections) {
        3176               0 :         if (traps->is_rectangular)
        3177               0 :             status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
        3178               0 :         else if (traps->is_rectilinear)
        3179               0 :             status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
        3180                 :         else
        3181               0 :             status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
        3182               0 :         if (unlikely (status))
        3183               0 :             return status;
        3184                 :     }
        3185                 :
        3186                 :     /* Use a fast path if the trapezoids consist of a simple region,
        3187                 :      * but we can only do this if we do not have a clip surface, or can
        3188                 :      * substitute the mask with the clip.
        3189                 :      */
        3190               0 :     if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
        3191               0 :         (! need_clip_surface ||
        3192               0 :          (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
        3193                 :     {
        3194                 :         cairo_boxes_t boxes;
        3195                 :
        3196               0 :         _boxes_for_traps (&boxes, traps, antialias);
        3197               0 :         return _clip_and_composite_boxes (dst, op, src,
        3198                 :                                           &boxes, antialias,
        3199                 :                                           extents, clip);
        3200                 :     }
        3201                 :
        3202                 :     /* No fast path, exclude self-intersections and clip trapezoids. */
        3203                 :     /* Otherwise render the trapezoids to a mask and composite in the usual
        3204                 :      * fashion.
        3205                 :      */
        3206               0 :     info.traps = traps->traps;
        3207               0 :     info.num_traps = traps->num_traps;
        3208               0 :     info.antialias = antialias;
        3209               0 :     return _clip_and_composite (dst, op, src,
        3210                 :                                 _composite_traps, &info,
        3211                 :                                 extents, clip);
        3212                 : }
        3213                 :
        3214                 : static cairo_clip_path_t *
        3215               0 : _clip_get_single_path (cairo_clip_t *clip)
        3216                 : {
        3217               0 :     cairo_clip_path_t *iter = clip->path;
        3218               0 :     cairo_clip_path_t *path = NULL;
        3219                 :
        3220                 :     do {
        3221               0 :         if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
        3222               0 :             if (path != NULL)
        3223               0 :                 return FALSE;
        3224                 :
        3225               0 :             path = iter;
        3226                 :         }
        3227               0 :         iter = iter->prev;
        3228               0 :     } while (iter != NULL);
        3229                 :
        3230               0 :     return path;
        3231                 : }
        3232                 :
        3233                 : /* high level image interface */
        3234                 :
        3235                 : static cairo_int_status_t
        3236              64 : _cairo_image_surface_paint (void                        *abstract_surface,
        3237                 :                             cairo_operator_t             op,
        3238                 :                             const cairo_pattern_t       *source,
        3239                 :                             cairo_clip_t                *clip)
        3240                 : {
        3241              64 :     cairo_image_surface_t *surface = abstract_surface;
        3242                 :     cairo_composite_rectangles_t extents;
        3243                 :     cairo_clip_path_t *clip_path;
        3244                 :     cairo_clip_t local_clip;
        3245              64 :     cairo_bool_t have_clip = FALSE;
        3246              64 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
        3247              64 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
        3248                 :     cairo_status_t status;
        3249                 :
        3250                 :     cairo_rectangle_int_t rect;
        3251              64 :     rect.x = rect.y = 0;
        3252              64 :     rect.width = surface->width;
        3253              64 :     rect.height = surface->height;
        3254                 :
        3255              64 :     status = _cairo_composite_rectangles_init_for_paint (&extents,
        3256                 :                                                          &rect,
        3257                 :                                                          op, source,
        3258                 :                                                          clip);
        3259              64 :     if (unlikely (status))
        3260               0 :         return status;
        3261                 :
        3262              64 :     if (_cairo_clip_contains_extents (clip, &extents))
        3263               0 :         clip = NULL;
        3264                 :
        3265              64 :     if (clip != NULL) {
        3266               0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
        3267               0 :         have_clip = TRUE;
        3268                 :     }
        3269                 :
        3270              64 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
        3271              64 :     if (unlikely (status)) {
        3272               0 :         if (have_clip)
        3273               0 :             _cairo_clip_fini (&local_clip);
        3274                 :
        3275               0 :         return status;
        3276                 :     }
        3277                 :
        3278                 :     /* If the clip cannot be reduced to a set of boxes, we will need to
        3279                 :      * use a clipmask. Paint is special as it is the only operation that
        3280                 :      * does not implicitly use a mask, so we may be able to reduce this
        3281                 :      * operation to a fill...
        3282                 :      */
        3283              64 :     if (clip != NULL &&
        3284               0 :         extents.is_bounded &&
        3285               0 :         (clip_path = _clip_get_single_path (clip)) != NULL)
        3286                 :     {
        3287               0 :         status = _cairo_image_surface_fill (surface, op, source,
        3288                 :                                             &clip_path->path,
        3289                 :                                             clip_path->fill_rule,
        3290                 :                                             clip_path->tolerance,
        3291                 :                                             clip_path->antialias,
        3292                 :                                             NULL);
        3293                 :     }
        3294                 :     else
        3295                 :     {
        3296                 :         cairo_boxes_t boxes;
        3297                 :
        3298              64 :         _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
        3299              64 :         status = _clip_and_composite_boxes (surface, op, source,
        3300                 :                                             &boxes, CAIRO_ANTIALIAS_DEFAULT,
        3301                 :                                             &extents, clip);
        3302                 :     }
        3303                 :
        3304              64 :     if (clip_boxes != boxes_stack)
        3305               0 :         free (clip_boxes);
        3306                 :
        3307              64 :     if (have_clip)
        3308               0 :         _cairo_clip_fini (&local_clip);
        3309                 :
        3310              64 :     return status;
        3311                 : }
        3312                 :
        3313                 : static cairo_status_t
        3314               0 : _composite_mask (void                           *closure,
        3315                 :                  pixman_image_t                 *dst,
        3316                 :                  pixman_format_code_t            dst_format,
        3317                 :                  cairo_operator_t                op,
        3318                 :                  const cairo_pattern_t          *src_pattern,
        3319                 :                  int                             dst_x,
        3320                 :                  int                             dst_y,
        3321                 :                  const cairo_rectangle_int_t    *extents,
        3322                 :                  cairo_region_t                 *clip_region)
        3323                 : {
        3324               0 :     const cairo_pattern_t *mask_pattern = closure;
        3325               0 :     pixman_image_t *src, *mask = NULL;
        3326               0 :     int src_x = 0, src_y = 0;
        3327               0 :     int mask_x = 0, mask_y = 0;
        3328                 :
        3329               0 :     if (src_pattern != NULL) {
        3330               0 :         src = _pixman_image_for_pattern (src_pattern, FALSE, extents, &src_x, &src_y);
        3331               0 :         if (unlikely (src == NULL))
        3332               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3333                 :
        3334               0 :         mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, &mask_x, &mask_y);
        3335               0 :         if (unlikely (mask == NULL)) {
        3336               0 :             pixman_image_unref (src);
        3337               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3338                 :         }
        3339                 :
        3340               0 :         if (mask_pattern->has_component_alpha)
        3341               0 :             pixman_image_set_component_alpha (mask, TRUE);
        3342                 :     } else {
        3343               0 :         src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, &src_x, &src_y);
        3344               0 :         if (unlikely (src == NULL))
        3345               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3346                 :     }
        3347                 :
        3348               0 :     pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
        3349               0 :                               extents->x + src_x,  extents->y + src_y,
        3350               0 :                               extents->x + mask_x, extents->y + mask_y,
        3351               0 :                               extents->x - dst_x,  extents->y - dst_y,
        3352                 :                               extents->width,      extents->height);
        3353                 :
        3354               0 :     if (mask != NULL)
        3355               0 :         pixman_image_unref (mask);
        3356               0 :     pixman_image_unref (src);
        3357                 :
        3358               0 :     return CAIRO_STATUS_SUCCESS;
        3359                 : }
        3360                 :
        3361                 : static cairo_int_status_t
        3362               0 : _cairo_image_surface_mask (void                         *abstract_surface,
        3363                 :                            cairo_operator_t              op,
        3364                 :                            const cairo_pattern_t        *source,
        3365                 :                            const cairo_pattern_t        *mask,
        3366                 :                            cairo_clip_t                 *clip)
        3367                 : {
        3368               0 :     cairo_image_surface_t *surface = abstract_surface;
        3369                 :     cairo_composite_rectangles_t extents;
        3370                 :     cairo_clip_t local_clip;
        3371               0 :     cairo_bool_t have_clip = FALSE;
        3372                 :     cairo_status_t status;
        3373                 :
        3374                 :     cairo_rectangle_int_t rect;
        3375               0 :     rect.x = rect.y = 0;
        3376               0 :     rect.width = surface->width;
        3377               0 :     rect.height = surface->height;
        3378                 :
        3379               0 :     status = _cairo_composite_rectangles_init_for_mask (&extents,
        3380                 :                                                         &rect,
        3381                 :                                                         op, source, mask, clip);
        3382               0 :     if (unlikely (status))
        3383               0 :         return status;
        3384                 :
        3385               0 :     if (_cairo_clip_contains_extents (clip, &extents))
        3386               0 :         clip = NULL;
        3387                 :
        3388               0 :     if (clip != NULL && extents.is_bounded) {
        3389               0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
        3390               0 :         status = _cairo_clip_rectangle (clip, &extents.bounded);
        3391               0 :         if (unlikely (status)) {
        3392               0 :             _cairo_clip_fini (&local_clip);
        3393               0 :             return status;
        3394                 :         }
        3395                 :
        3396               0 :         have_clip = TRUE;
        3397                 :     }
        3398                 :
        3399               0 :     status = _clip_and_composite (surface, op, source,
        3400                 :                                   _composite_mask, (void *) mask,
        3401                 :                                   &extents, clip);
        3402                 :
        3403               0 :     if (have_clip)
        3404               0 :         _cairo_clip_fini (&local_clip);
        3405                 :
        3406               0 :     return status;
        3407                 : }
        3408                 :
        3409                 : typedef struct {
        3410                 :     cairo_polygon_t             *polygon;
        3411                 :     cairo_fill_rule_t            fill_rule;
        3412                 :     cairo_antialias_t            antialias;
        3413                 : } composite_spans_info_t;
        3414                 :
        3415                 : //#define USE_BOTOR_SCAN_CONVERTER
        3416                 : static cairo_status_t
        3417               0 : _composite_spans (void                          *closure,
        3418                 :                   pixman_image_t                *dst,
        3419                 :                   pixman_format_code_t           dst_format,
        3420                 :                   cairo_operator_t               op,
        3421                 :                   const cairo_pattern_t         *pattern,
        3422                 :                   int                            dst_x,
        3423                 :                   int                            dst_y,
        3424                 :                   const cairo_rectangle_int_t   *extents,
        3425                 :                   cairo_region_t                *clip_region)
        3426                 : {
        3427                 :     uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
        3428               0 :     composite_spans_info_t *info = closure;
        3429                 :     cairo_image_surface_span_renderer_t renderer;
        3430                 : #if USE_BOTOR_SCAN_CONVERTER
        3431                 :     cairo_box_t box;
        3432                 :     cairo_botor_scan_converter_t converter;
        3433                 : #else
        3434                 :     cairo_scan_converter_t *converter;
        3435                 : #endif
        3436                 :     pixman_image_t *mask;
        3437                 :     cairo_status_t status;
        3438                 :
        3439                 : #if USE_BOTOR_SCAN_CONVERTER
        3440                 :     box.p1.x = _cairo_fixed_from_int (extents->x);
        3441                 :     box.p1.y = _cairo_fixed_from_int (extents->y);
        3442                 :     box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
        3443                 :     box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
        3444                 :     _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
        3445                 :     status = converter.base.add_polygon (&converter.base, info->polygon);
        3446                 : #else
        3447               0 :     converter = _cairo_tor_scan_converter_create (extents->x, extents->y,
        3448               0 :                                                   extents->x + extents->width,
        3449               0 :                                                   extents->y + extents->height,
        3450                 :                                                   info->fill_rule);
        3451               0 :     status = converter->add_polygon (converter, info->polygon);
        3452                 : #endif
        3453               0 :     if (unlikely (status))
        3454               0 :         goto CLEANUP_CONVERTER;
        3455                 :
        3456                 :     /* TODO: support rendering to A1 surfaces (or: go add span
        3457                 :      * compositing to pixman.) */
        3458                 :
        3459               0 :     if (pattern == NULL &&
        3460               0 :         dst_format == PIXMAN_a8 &&
        3461                 :         op == CAIRO_OPERATOR_SOURCE)
        3462                 :     {
        3463               0 :         mask = dst;
        3464               0 :         dst = NULL;
        3465                 :     }
        3466                 :     else
        3467                 :     {
        3468               0 :         int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8);
        3469               0 :         uint8_t *data = mask_buf;
        3470                 :
        3471               0 :         if (extents->height * stride <= (int) sizeof (mask_buf))
        3472               0 :             memset (data, 0, extents->height * stride);
        3473                 :         else
        3474               0 :             data = NULL, stride = 0;
        3475                 :
        3476               0 :         mask = pixman_image_create_bits (PIXMAN_a8,
        3477                 :                                          extents->width,
        3478                 :                                          extents->height,
        3479                 :                                          (uint32_t *) data,
        3480                 :                                          stride);
        3481               0 :         if (unlikely (mask == NULL)) {
        3482               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3483               0 :             goto CLEANUP_CONVERTER;
        3484                 :         }
        3485                 :     }
        3486                 :
        3487               0 :     renderer.base.render_rows = _cairo_image_surface_span;
        3488               0 :     renderer.mask_stride = pixman_image_get_stride (mask);
        3489               0 :     renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
        3490               0 :     if (dst != NULL)
        3491               0 :         renderer.mask_data -= extents->y * renderer.mask_stride + extents->x;
        3492                 :     else
        3493               0 :         renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
        3494                 :
        3495                 : #if USE_BOTOR_SCAN_CONVERTER
        3496                 :     status = converter.base.generate (&converter.base, &renderer.base);
        3497                 : #else
        3498               0 :     status = converter->generate (converter, &renderer.base);
        3499                 : #endif
        3500               0 :     if (unlikely (status))
        3501               0 :         goto CLEANUP_RENDERER;
        3502                 :
        3503               0 :     if (dst != NULL) {
        3504                 :         pixman_image_t *src;
        3505                 :         int src_x, src_y;
        3506                 :
        3507               0 :         src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
        3508               0 :         if (unlikely (src == NULL)) {
        3509               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3510               0 :             goto CLEANUP_RENDERER;
        3511                 :         }
        3512                 :
        3513               0 :         pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
        3514               0 :                                   extents->x + src_x, extents->y + src_y,
        3515                 :                                   0, 0, /* mask.x, mask.y */
        3516               0 :                                   extents->x - dst_x, extents->y - dst_y,
        3517                 :                                   extents->width, extents->height);
        3518               0 :         pixman_image_unref (src);
        3519                 :     }
        3520                 :
        3521                 :  CLEANUP_RENDERER:
        3522               0 :     if (dst != NULL)
        3523               0 :         pixman_image_unref (mask);
        3524                 :  CLEANUP_CONVERTER:
        3525                 : #if USE_BOTOR_SCAN_CONVERTER
        3526                 :     converter.base.destroy (&converter.base);
        3527                 : #else
        3528               0 :     converter->destroy (converter);
        3529                 : #endif
        3530               0 :     return status;
        3531                 : }
        3532                 :
        3533                 : static cairo_status_t
        3534               0 : _clip_and_composite_polygon (cairo_image_surface_t *dst,
        3535                 :                              cairo_operator_t op,
        3536                 :                              const cairo_pattern_t *src,
        3537                 :                              cairo_polygon_t *polygon,
        3538                 :                              cairo_fill_rule_t fill_rule,
        3539                 :                              cairo_antialias_t antialias,
        3540                 :                              cairo_composite_rectangles_t *extents,
        3541                 :                              cairo_clip_t *clip)
        3542                 : {
        3543                 :     cairo_status_t status;
        3544                 :
        3545               0 :     if (polygon->num_edges == 0) {
        3546                 :         cairo_traps_t traps;
        3547                 :
        3548               0 :         if (extents->is_bounded)
        3549               0 :             return CAIRO_STATUS_SUCCESS;
        3550                 :
        3551               0 :         _cairo_traps_init (&traps);
        3552               0 :         status = _clip_and_composite_trapezoids (dst, op, src,
        3553                 :                                                  &traps, antialias,
        3554                 :                                                  extents, clip);
        3555               0 :         _cairo_traps_fini (&traps);
        3556                 :
        3557               0 :         return status;
        3558                 :     }
        3559                 :
        3560               0 :     _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
        3561               0 :     if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
        3562               0 :         return CAIRO_STATUS_SUCCESS;
        3563                 :
        3564               0 :     if (antialias != CAIRO_ANTIALIAS_NONE) {
        3565                 :         composite_spans_info_t info;
        3566                 :
        3567               0 :         info.polygon = polygon;
        3568               0 :         info.fill_rule = fill_rule;
        3569               0 :         info.antialias = antialias;
        3570                 :
        3571               0 :         status = _clip_and_composite (dst, op, src,
        3572                 :                                       _composite_spans, &info,
        3573                 :                                       extents, clip);
        3574                 :     } else {
        3575                 :         cairo_traps_t traps;
        3576                 :
        3577               0 :         _cairo_traps_init (&traps);
        3578                 :
        3579                 :         /* Fall back to trapezoid fills. */
        3580               0 :         status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
        3581                 :                                                             polygon,
        3582                 :                                                             fill_rule);
        3583               0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
        3584               0 :             status = _clip_and_composite_trapezoids (dst, op, src,
        3585                 :                                                      &traps, antialias,
        3586                 :                                                      extents, clip);
        3587                 :         }
        3588                 :
        3589               0 :         _cairo_traps_fini (&traps);
        3590                 :     }
        3591                 :
        3592               0 :     return status;
        3593                 : }
        3594                 :
        3595                 : static cairo_int_status_t
        3596               0 : _cairo_image_surface_stroke (void                       *abstract_surface,
        3597                 :                              cairo_operator_t            op,
        3598                 :                              const cairo_pattern_t      *source,
        3599                 :                              cairo_path_fixed_t         *path,
        3600                 :                              const cairo_stroke_style_t *style,
        3601                 :                              const cairo_matrix_t       *ctm,
        3602                 :                              const cairo_matrix_t       *ctm_inverse,
        3603                 :                              double                      tolerance,
        3604                 :                              cairo_antialias_t           antialias,
        3605                 :                              cairo_clip_t               *clip)
        3606                 : {
        3607               0 :     cairo_image_surface_t *surface = abstract_surface;
        3608                 :     cairo_composite_rectangles_t extents;
        3609               0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
        3610               0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
        3611                 :     cairo_clip_t local_clip;
        3612               0 :     cairo_bool_t have_clip = FALSE;
        3613                 :     cairo_status_t status;
        3614                 :
        3615                 :     cairo_rectangle_int_t rect;
        3616               0 :     rect.x = rect.y = 0;
        3617               0 :     rect.width = surface->width;
        3618               0 :     rect.height = surface->height;
        3619                 :
        3620               0 :     status = _cairo_composite_rectangles_init_for_stroke (&extents,
        3621                 :                                                           &rect,
        3622                 :                                                           op, source,
        3623                 :                                                           path, style, ctm,
        3624                 :                                                           clip);
        3625               0 :     if (unlikely (status))
        3626               0 :         return status;
        3627                 :
        3628               0 :     if (_cairo_clip_contains_extents (clip, &extents))
        3629               0 :         clip = NULL;
        3630                 :
        3631               0 :     if (clip != NULL) {
        3632               0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
        3633               0 :         have_clip = TRUE;
        3634                 :     }
        3635                 :
        3636               0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
        3637               0 :     if (unlikely (status)) {
        3638               0 :         if (have_clip)
        3639               0 :             _cairo_clip_fini (&local_clip);
        3640                 :
        3641               0 :         return status;
        3642                 :     }
        3643                 :
        3644               0 :     status = CAIRO_INT_STATUS_UNSUPPORTED;
        3645               0 :     if (path->is_rectilinear) {
        3646                 :         cairo_boxes_t boxes;
        3647                 :
        3648               0 :         _cairo_boxes_init (&boxes);
        3649               0 :         _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
        3650                 :
        3651               0 :         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
        3652                 :                                                                 style,
        3653                 :                                                                 ctm,
        3654                 :                                                                 &boxes);
        3655               0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
        3656               0 :             status = _clip_and_composite_boxes (surface, op, source,
        3657                 :                                                 &boxes, antialias,
        3658                 :                                                 &extents, clip);
        3659                 :         }
        3660                 :
        3661               0 :         _cairo_boxes_fini (&boxes);
        3662                 :     }
        3663                 :
        3664               0 :     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
        3665                 :         cairo_polygon_t polygon;
        3666                 :
        3667               0 :         _cairo_polygon_init (&polygon);
        3668               0 :         _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
        3669                 :
        3670               0 :         status = _cairo_path_fixed_stroke_to_polygon (path,
        3671                 :                                                       style,
        3672                 :                                                       ctm, ctm_inverse,
        3673                 :                                                       tolerance,
        3674                 :                                                       &polygon);
        3675               0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
        3676               0 :             status = _clip_and_composite_polygon (surface, op, source, &polygon,
        3677                 :                                                   CAIRO_FILL_RULE_WINDING, antialias,
        3678                 :                                                   &extents, clip);
        3679                 :         }
        3680                 :
        3681               0 :         _cairo_polygon_fini (&polygon);
        3682                 :     }
        3683                 :
        3684               0 :     if (clip_boxes != boxes_stack)
        3685               0 :         free (clip_boxes);
        3686                 :
        3687               0 :     if (have_clip)
        3688               0 :         _cairo_clip_fini (&local_clip);
        3689                 :
        3690               0 :     return status;
        3691                 : }
        3692                 :
        3693                 : static cairo_int_status_t
        3694               0 : _cairo_image_surface_fill (void                         *abstract_surface,
        3695                 :                            cairo_operator_t              op,
        3696                 :                            const cairo_pattern_t        *source,
        3697                 :                            cairo_path_fixed_t           *path,
        3698                 :                            cairo_fill_rule_t             fill_rule,
        3699                 :                            double                        tolerance,
        3700                 :                            cairo_antialias_t             antialias,
        3701                 :                            cairo_clip_t                 *clip)
        3702                 : {
        3703               0 :     cairo_image_surface_t *surface = abstract_surface;
        3704                 :     cairo_composite_rectangles_t extents;
        3705               0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
        3706                 :     cairo_clip_t local_clip;
        3707               0 :     cairo_bool_t have_clip = FALSE;
        3708               0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
        3709                 :     cairo_status_t status;
        3710                 :
        3711                 :     cairo_rectangle_int_t rect;
        3712               0 :     rect.x = rect.y = 0;
        3713               0 :     rect.width = surface->width;
        3714               0 :     rect.height = surface->height;
        3715                 :
        3716               0 :     status = _cairo_composite_rectangles_init_for_fill (&extents,
        3717                 :                                                         &rect,
        3718                 :                                                         op, source, path,
        3719                 :                                                         clip);
        3720               0 :     if (unlikely (status))
        3721               0 :         return status;
        3722                 :
        3723               0 :     if (_cairo_clip_contains_extents (clip, &extents))
        3724               0 :         clip = NULL;
        3725                 :
        3726               0 :     if (extents.is_bounded && clip != NULL) {
        3727                 :         cairo_clip_path_t *clip_path;
        3728                 :
        3729               0 :         if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
        3730               0 :             _cairo_path_fixed_equal (&clip_path->path, path))
        3731                 :         {
        3732               0 :             clip = NULL;
        3733                 :         }
        3734                 :     }
        3735                 :
        3736               0 :     if (clip != NULL) {
        3737               0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
        3738               0 :         have_clip = TRUE;
        3739                 :     }
        3740                 :
        3741               0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
        3742               0 :     if (unlikely (status)) {
        3743               0 :         if (have_clip)
        3744               0 :             _cairo_clip_fini (&local_clip);
        3745                 :
        3746               0 :         return status;
        3747                 :     }
        3748                 :
        3749               0 :     if (_cairo_path_fixed_is_rectilinear_fill (path)) {
        3750                 :         cairo_boxes_t boxes;
        3751                 :
        3752               0 :         _cairo_boxes_init (&boxes);
        3753               0 :         _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
        3754                 :
        3755               0 :         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
        3756                 :                                                               fill_rule,
        3757                 :                                                               &boxes);
        3758               0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
        3759               0 :             status = _clip_and_composite_boxes (surface, op, source,
        3760                 :                                                 &boxes, antialias,
        3761                 :                                                 &extents, clip);
        3762                 :         }
        3763                 :
        3764               0 :         _cairo_boxes_fini (&boxes);
        3765                 :     } else {
        3766                 :         cairo_polygon_t polygon;
        3767                 :
        3768               0 :         assert (! path->is_empty_fill);
        3769                 :
        3770               0 :         _cairo_polygon_init (&polygon);
        3771               0 :         _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
        3772                 :
        3773               0 :         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
        3774               0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
        3775               0 :             status = _clip_and_composite_polygon (surface, op, source, &polygon,
        3776                 :                                                   fill_rule, antialias,
        3777                 :                                                   &extents, clip);
        3778                 :         }
        3779                 :
        3780               0 :         _cairo_polygon_fini (&polygon);
        3781                 :     }
        3782                 :
        3783               0 :     if (clip_boxes != boxes_stack)
        3784               0 :         free (clip_boxes);
        3785                 :
        3786               0 :     if (have_clip)
        3787               0 :         _cairo_clip_fini (&local_clip);
        3788                 :
        3789               0 :     return status;
        3790                 : }
        3791                 :
        3792                 : typedef struct {
        3793                 :     cairo_scaled_font_t *font;
        3794                 :     cairo_glyph_t *glyphs;
        3795                 :     int num_glyphs;
        3796                 : } composite_glyphs_info_t;
        3797                 :
        3798                 : static cairo_status_t
        3799               0 : _composite_glyphs_via_mask (void                        *closure,
        3800                 :                             pixman_image_t              *dst,
        3801                 :                             pixman_format_code_t         dst_format,
        3802                 :                             cairo_operator_t             op,
        3803                 :                             const cairo_pattern_t       *pattern,
        3804                 :                             int                          dst_x,
        3805                 :                             int                          dst_y,
        3806                 :                             const cairo_rectangle_int_t *extents,
        3807                 :                             cairo_region_t              *clip_region)
        3808                 : {
        3809               0 :     composite_glyphs_info_t *info = closure;
        3810               0 :     cairo_scaled_font_t *font = info->font;
        3811               0 :     cairo_glyph_t *glyphs = info->glyphs;
        3812               0 :     int num_glyphs = info->num_glyphs;
        3813               0 :     pixman_image_t *mask = NULL;
        3814                 :     pixman_image_t *src;
        3815                 :     pixman_image_t *white;
        3816               0 :     pixman_format_code_t mask_format = 0; /* silence gcc */
        3817                 :     cairo_status_t status;
        3818                 :     int src_x, src_y;
        3819                 :     int i;
        3820                 :
        3821               0 :     src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
        3822               0 :     if (unlikely (src == NULL))
        3823               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3824                 :
        3825               0 :     white = _pixman_white_image ();
        3826               0 :     if (unlikely (white == NULL)) {
        3827               0 :         pixman_image_unref (src);
        3828               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3829                 :     }
        3830                 :
        3831               0 :     _cairo_scaled_font_freeze_cache (font);
        3832                 :
        3833               0 :     for (i = 0; i < num_glyphs; i++) {
        3834                 :         int x, y;
        3835                 :         cairo_image_surface_t *glyph_surface;
        3836                 :         cairo_scaled_glyph_t *scaled_glyph;
        3837                 :
        3838               0 :         status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
        3839                 :                                              CAIRO_SCALED_GLYPH_INFO_SURFACE,
        3840                 :                                              &scaled_glyph);
        3841                 :
        3842               0 :         if (unlikely (status))
        3843               0 :             goto CLEANUP;
        3844                 :
        3845               0 :         glyph_surface = scaled_glyph->surface;
        3846                 :
        3847               0 :         if (glyph_surface->width == 0 || glyph_surface->height == 0)
        3848               0 :             continue;
        3849                 :
        3850                 :         /* To start, create the mask using the format from the first
        3851                 :          * glyph. Later we'll deal with different formats. */
        3852               0 :         if (mask == NULL) {
        3853               0 :             mask_format = glyph_surface->pixman_format;
        3854               0 :             mask = pixman_image_create_bits (mask_format,
        3855                 :                                              extents->width, extents->height,
        3856                 :                                              NULL, 0);
        3857               0 :             if (unlikely (mask == NULL)) {
        3858               0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3859               0 :                 goto CLEANUP;
        3860                 :             }
        3861                 :
        3862               0 :             if (PIXMAN_FORMAT_RGB (mask_format))
        3863               0 :                 pixman_image_set_component_alpha (mask, TRUE);
        3864                 :         }
        3865                 :
        3866                 :         /* If we have glyphs of different formats, we "upgrade" the mask
        3867                 :          * to the wider of the formats. */
        3868               0 :         if (glyph_surface->pixman_format != mask_format &&
        3869               0 :             PIXMAN_FORMAT_BPP (mask_format) <
        3870               0 :             PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
        3871                 :         {
        3872                 :             pixman_image_t *new_mask;
        3873                 :
        3874               0 :             mask_format = glyph_surface->pixman_format;
        3875               0 :             new_mask = pixman_image_create_bits (mask_format,
        3876                 :                                                  extents->width, extents->height,
        3877                 :                                                  NULL, 0);
        3878               0 :             if (unlikely (new_mask == NULL)) {
        3879               0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3880               0 :                 goto CLEANUP;
        3881                 :             }
        3882                 :
        3883               0 :             pixman_image_composite32 (PIXMAN_OP_SRC,
        3884                 :                                       white, mask, new_mask,
        3885                 :                                       0, 0, 0, 0, 0, 0,
        3886                 :                                       extents->width, extents->height);
        3887                 :
        3888               0 :             pixman_image_unref (mask);
        3889               0 :             mask = new_mask;
        3890               0 :             if (PIXMAN_FORMAT_RGB (mask_format))
        3891               0 :                 pixman_image_set_component_alpha (mask, TRUE);
        3892                 :         }
        3893                 :
        3894                 :         /* round glyph locations to the nearest pixel */
        3895                 :         /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
        3896               0 :         x = _cairo_lround (glyphs[i].x -
        3897               0 :                            glyph_surface->base.device_transform.x0);
        3898               0 :         y = _cairo_lround (glyphs[i].y -
        3899               0 :                            glyph_surface->base.device_transform.y0);
        3900               0 :         if (glyph_surface->pixman_format == mask_format) {
        3901               0 :             pixman_image_composite32 (PIXMAN_OP_ADD,
        3902                 :                                       glyph_surface->pixman_image, NULL, mask,
        3903                 :                                       0, 0, 0, 0,
        3904               0 :                                       x - extents->x, y - extents->y,
        3905                 :                                       glyph_surface->width,
        3906                 :                                       glyph_surface->height);
        3907                 :         } else {
        3908               0 :             pixman_image_composite32 (PIXMAN_OP_ADD,
        3909                 :                                       white, glyph_surface->pixman_image, mask,
        3910                 :                                       0, 0, 0, 0,
        3911               0 :                                       x - extents->x, y - extents->y,
        3912                 :                                       glyph_surface->width,
        3913                 :                                       glyph_surface->height);
        3914                 :         }
        3915                 :     }
        3916                 :
        3917               0 :     pixman_image_composite32 (_pixman_operator (op),
        3918                 :                               src, mask, dst,
        3919               0 :                               extents->x + src_x, extents->y + src_y,
        3920                 :                               0, 0,
        3921               0 :                               extents->x - dst_x, extents->y - dst_y,
        3922                 :                               extents->width,     extents->height);
        3923                 :
        3924                 : CLEANUP:
        3925               0 :     _cairo_scaled_font_thaw_cache (font);
        3926               0 :     if (mask != NULL)
        3927               0 :         pixman_image_unref (mask);
        3928               0 :     pixman_image_unref (src);
        3929               0 :     pixman_image_unref (white);
        3930                 :
        3931               0 :     return status;
        3932                 : }
        3933                 :
        3934                 : static cairo_status_t
        3935               0 : _composite_glyphs (void                         *closure,
        3936                 :                    pixman_image_t               *dst,
        3937                 :                    pixman_format_code_t          dst_format,
        3938                 :                    cairo_operator_t              op,
        3939                 :                    const cairo_pattern_t        *pattern,
        3940                 :                    int                           dst_x,
        3941                 :                    int                           dst_y,
        3942                 :                    const cairo_rectangle_int_t  *extents,
        3943                 :                    cairo_region_t               *clip_region)
        3944                 : {
        3945               0 :     composite_glyphs_info_t *info = closure;
        3946                 :     cairo_scaled_glyph_t *glyph_cache[64];
        3947               0 :     pixman_op_t pixman_op = _pixman_operator (op);
        3948               0 :     pixman_image_t *src = NULL;
        3949               0 :     int src_x = 0, src_y = 0;
        3950                 :     cairo_status_t status;
        3951                 :     int i;
        3952                 :
        3953               0 :     if (pattern != NULL) {
        3954               0 :         src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y);
        3955               0 :         src_x -= dst_x;
        3956               0 :         src_y -= dst_y;
        3957                 :     } else {
        3958               0 :         src = _pixman_white_image ();
        3959                 :     }
        3960               0 :     if (unlikely (src == NULL))
        3961               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        3962                 :
        3963               0 :     memset (glyph_cache, 0, sizeof (glyph_cache));
        3964               0 :     status = CAIRO_STATUS_SUCCESS;
        3965                 :
        3966               0 :     _cairo_scaled_font_freeze_cache (info->font);
        3967               0 :     for (i = 0; i < info->num_glyphs; i++) {
        3968                 :         int x, y;
        3969                 :         cairo_image_surface_t *glyph_surface;
        3970                 :         cairo_scaled_glyph_t *scaled_glyph;
        3971               0 :         unsigned long glyph_index = info->glyphs[i].index;
        3972               0 :         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
        3973                 :
        3974               0 :         scaled_glyph = glyph_cache[cache_index];
        3975               0 :         if (scaled_glyph == NULL ||
        3976               0 :             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
        3977                 :         {
        3978               0 :             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
        3979                 :                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
        3980                 :                                                  &scaled_glyph);
        3981                 :
        3982               0 :             if (unlikely (status))
        3983               0 :                 break;
        3984                 :
        3985               0 :             glyph_cache[cache_index] = scaled_glyph;
        3986                 :         }
        3987                 :
        3988               0 :         glyph_surface = scaled_glyph->surface;
        3989               0 :         if (glyph_surface->width && glyph_surface->height) {
        3990                 :             int x1, y1, x2, y2;
        3991                 :
        3992                 :             /* round glyph locations to the nearest pixel */
        3993                 :             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
        3994               0 :             x = _cairo_lround (info->glyphs[i].x -
        3995               0 :                                glyph_surface->base.device_transform.x0);
        3996               0 :             y = _cairo_lround (info->glyphs[i].y -
        3997               0 :                                glyph_surface->base.device_transform.y0);
        3998                 :
        3999               0 :             x1 = x;
        4000               0 :             if (x1 < extents->x)
        4001               0 :                 x1 = extents->x;
        4002               0 :             x2 = x + glyph_surface->width;
        4003               0 :             if (x2 > extents->x + extents->width)
        4004               0 :                 x2 = extents->x + extents->width;
        4005                 :
        4006               0 :             y1 = y;
        4007               0 :             if (y1 < extents->y)
        4008               0 :                 y1 = extents->y;
        4009               0 :             y2 = y + glyph_surface->height;
        4010               0 :             if (y2 > extents->y + extents->height)
        4011               0 :                 y2 = extents->y + extents->height;
        4012                 :
        4013               0 :             pixman_image_composite32 (pixman_op,
        4014                 :                                       src, glyph_surface->pixman_image, dst,
        4015                 :                                       x1 + src_x,  y1 + src_y,
        4016                 :                                       x1 - x, y1 - y,
        4017                 :                                       x1 - dst_x, y1 - dst_y,
        4018                 :                                       x2 - x1, y2 - y1);
        4019                 :         }
        4020                 :     }
        4021               0 :     _cairo_scaled_font_thaw_cache (info->font);
        4022                 :
        4023               0 :     pixman_image_unref (src);
        4024                 :
        4025               0 :     return status;
        4026                 : }
        4027                 :
        4028                 : static cairo_int_status_t
        4029               0 : _cairo_image_surface_glyphs (void                       *abstract_surface,
        4030                 :                              cairo_operator_t            op,
        4031                 :                              const cairo_pattern_t      *source,
        4032                 :                              cairo_glyph_t              *glyphs,
        4033                 :                              int                         num_glyphs,
        4034                 :                              cairo_scaled_font_t        *scaled_font,
        4035                 :                              cairo_clip_t               *clip,
        4036                 :                              int *num_remaining)
        4037                 : {
        4038               0 :     cairo_image_surface_t *surface = abstract_surface;
        4039                 :     cairo_composite_rectangles_t extents;
        4040                 :     composite_glyphs_info_t glyph_info;
        4041                 :     cairo_clip_t local_clip;
        4042               0 :     cairo_bool_t have_clip = FALSE;
        4043                 :     cairo_bool_t overlap;
        4044                 :     cairo_status_t status;
        4045                 :
        4046                 :     cairo_rectangle_int_t rect;
        4047               0 :     rect.x = rect.y = 0;
        4048               0 :     rect.width = surface->width;
        4049               0 :     rect.height = surface->height;
        4050                 :
        4051               0 :     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
        4052                 :                                                           &rect,
        4053                 :                                                           op, source,
        4054                 :                                                           scaled_font,
        4055                 :                                                           glyphs, num_glyphs,
        4056                 :                                                           clip,
        4057                 :                                                           &overlap);
        4058               0 :     if (unlikely (status))
        4059               0 :         return status;
        4060                 :
        4061               0 :     if (_cairo_clip_contains_rectangle (clip, &extents.mask))
        4062               0 :         clip = NULL;
        4063                 :
        4064               0 :     if (clip != NULL && extents.is_bounded) {
        4065               0 :         clip = _cairo_clip_init_copy (&local_clip, clip);
        4066               0 :         status = _cairo_clip_rectangle (clip, &extents.bounded);
        4067               0 :         if (unlikely (status))
        4068               0 :             return status;
        4069                 :
        4070               0 :         have_clip = TRUE;
        4071                 :     }
        4072                 :
        4073               0 :     glyph_info.font = scaled_font;
        4074               0 :     glyph_info.glyphs = glyphs;
        4075               0 :     glyph_info.num_glyphs = num_glyphs;
        4076                 :
        4077               0 :     status = _clip_and_composite (surface, op, source,
        4078               0 :                                   overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs,
        4079                 :                                   &glyph_info,
        4080                 :                                   &extents, clip);
        4081                 :
        4082               0 :     if (have_clip)
        4083               0 :         _cairo_clip_fini (&local_clip);
        4084                 :
        4085               0 :     *num_remaining = 0;
        4086               0 :     return status;
        4087                 : }
        4088                 :
        4089                 : static cairo_bool_t
        4090             115 : _cairo_image_surface_get_extents (void                    *abstract_surface,
        4091                 :                                   cairo_rectangle_int_t   *rectangle)
        4092                 : {
        4093             115 :     cairo_image_surface_t *surface = abstract_surface;
        4094                 :
        4095             115 :     rectangle->x = 0;
        4096             115 :     rectangle->y = 0;
        4097             115 :     rectangle->width  = surface->width;
        4098             115 :     rectangle->height = surface->height;
        4099                 :
        4100             115 :     return TRUE;
        4101                 : }
        4102                 :
        4103                 : static void
        4104               0 : _cairo_image_surface_get_font_options (void                  *abstract_surface,
        4105                 :                                        cairo_font_options_t  *options)
        4106                 : {
        4107               0 :     _cairo_font_options_init_default (options);
        4108                 :
        4109               0 :     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
        4110               0 :     _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
        4111               0 : }
        4112                 :
        4113                 : /* legacy interface kept for compatibility until surface-fallback is removed */
        4114                 : static cairo_status_t
        4115               0 : _cairo_image_surface_acquire_dest_image (void                    *abstract_surface,
        4116                 :                                          cairo_rectangle_int_t   *interest_rect,
        4117                 :                                          cairo_image_surface_t  **image_out,
        4118                 :                                          cairo_rectangle_int_t   *image_rect_out,
        4119                 :                                          void                   **image_extra)
        4120                 : {
        4121               0 :     cairo_image_surface_t *surface = abstract_surface;
        4122                 :
        4123               0 :     image_rect_out->x = 0;
        4124               0 :     image_rect_out->y = 0;
        4125               0 :     image_rect_out->width = surface->width;
        4126               0 :     image_rect_out->height = surface->height;
        4127                 :
        4128               0 :     *image_out = surface;
        4129               0 :     *image_extra = NULL;
        4130                 :
        4131               0 :     return CAIRO_STATUS_SUCCESS;
        4132                 : }
        4133                 :
        4134                 : static void
        4135               0 : _cairo_image_surface_release_dest_image (void                    *abstract_surface,
        4136                 :                                         cairo_rectangle_int_t   *interest_rect,
        4137                 :                                         cairo_image_surface_t   *image,
        4138                 :                                         cairo_rectangle_int_t   *image_rect,
        4139                 :                                         void                    *image_extra)
        4140                 : {
        4141               0 : }
        4142                 :
        4143                 : static cairo_status_t
        4144               0 : _cairo_image_surface_clone_similar (void               *abstract_surface,
        4145                 :                                     cairo_surface_t     *src,
        4146                 :                                     int                  src_x,
        4147                 :                                     int                  src_y,
        4148                 :                                     int                  width,
        4149                 :                                     int                  height,
        4150                 :                                     int                 *clone_offset_x,
        4151                 :                                     int                 *clone_offset_y,
        4152                 :                                     cairo_surface_t    **clone_out)
        4153                 : {
        4154               0 :     cairo_image_surface_t *surface = abstract_surface;
        4155                 :
        4156               0 :     if (src->backend == surface->base.backend) {
        4157               0 :         *clone_offset_x = *clone_offset_y = 0;
        4158               0 :         *clone_out = cairo_surface_reference (src);
        4159                 :
        4160               0 :         return CAIRO_STATUS_SUCCESS;
        4161                 :     }
        4162                 :
        4163               0 :     return CAIRO_INT_STATUS_UNSUPPORTED;
        4164                 : }
        4165                 :
        4166                 : static cairo_int_status_t
        4167               0 : _cairo_image_surface_composite (cairo_operator_t         op,
        4168                 :                                 const cairo_pattern_t   *src_pattern,
        4169                 :                                 const cairo_pattern_t   *mask_pattern,
        4170                 :                                 void                    *abstract_dst,
        4171                 :                                 int                      src_x,
        4172                 :                                 int                      src_y,
        4173                 :                                 int                      mask_x,
        4174                 :                                 int                      mask_y,
        4175                 :                                 int                      dst_x,
        4176                 :                                 int                      dst_y,
        4177                 :                                 unsigned int             width,
        4178                 :                                 unsigned int             height,
        4179                 :                                 cairo_region_t          *clip_region)
        4180                 : {
        4181               0 :     cairo_image_surface_t *dst = abstract_dst;
        4182                 :     cairo_composite_rectangles_t extents;
        4183                 :     pixman_image_t *src;
        4184                 :     int src_offset_x, src_offset_y;
        4185                 :     cairo_status_t status;
        4186                 :
        4187               0 :     if (clip_region != NULL) {
        4188               0 :         status = _cairo_image_surface_set_clip_region (dst, clip_region);
        4189               0 :         if (unlikely (status))
        4190               0 :             return status;
        4191                 :     }
        4192                 :
        4193               0 :     extents.source.x = src_x;
        4194               0 :     extents.source.y = src_y;
        4195               0 :     extents.source.width  = width;
        4196               0 :     extents.source.height = height;
        4197                 :
        4198               0 :     extents.mask.x = mask_x;
        4199               0 :     extents.mask.y = mask_y;
        4200               0 :     extents.mask.width  = width;
        4201               0 :     extents.mask.height = height;
        4202                 :
        4203               0 :     extents.bounded.x = dst_x;
        4204               0 :     extents.bounded.y = dst_y;
        4205               0 :     extents.bounded.width  = width;
        4206               0 :     extents.bounded.height = height;
        4207                 :
        4208               0 :     extents.unbounded.x = 0;
        4209               0 :     extents.unbounded.y = 0;
        4210               0 :     extents.unbounded.width  = dst->width;
        4211               0 :     extents.unbounded.height = dst->height;
        4212                 :
        4213               0 :     if (clip_region != NULL) {
        4214                 :         cairo_rectangle_int_t rect;
        4215                 :
        4216               0 :         cairo_region_get_extents (clip_region, &rect);
        4217               0 :         if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
        4218               0 :             return CAIRO_STATUS_SUCCESS;
        4219                 :     }
        4220                 :
        4221               0 :     extents.is_bounded = _cairo_operator_bounded_by_either (op);
        4222                 :
        4223               0 :     src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, &src_offset_x, &src_offset_y);
        4224               0 :     if (unlikely (src == NULL))
        4225               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        4226                 :
        4227               0 :     status = CAIRO_STATUS_SUCCESS;
        4228               0 :     if (mask_pattern != NULL) {
        4229                 :         pixman_image_t *mask;
        4230                 :         int mask_offset_x, mask_offset_y;
        4231                 :
        4232               0 :         mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, &mask_offset_x, &mask_offset_y);
        4233               0 :         if (unlikely (mask == NULL)) {
        4234               0 :             pixman_image_unref (src);
        4235               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        4236                 :         }
        4237                 :
        4238               0 :         pixman_image_composite32 (_pixman_operator (op),
        4239                 :                                   src, mask, dst->pixman_image,
        4240                 :                                   src_x + src_offset_x,
        4241                 :                                   src_y + src_offset_y,
        4242                 :                                   mask_x + mask_offset_x,
        4243                 :                                   mask_y + mask_offset_y,
        4244                 :                                   dst_x, dst_y, width, height);
        4245                 :
        4246               0 :         pixman_image_unref (mask);
        4247                 :     } else {
        4248               0 :         pixman_image_composite32 (_pixman_operator (op),
        4249                 :                                   src, NULL, dst->pixman_image,
        4250                 :                                   src_x + src_offset_x,
        4251                 :                                   src_y + src_offset_y,
        4252                 :                                   0, 0,
        4253                 :                                   dst_x, dst_y, width, height);
        4254                 :     }
        4255                 :
        4256               0 :     pixman_image_unref (src);
        4257                 :
        4258               0 :     if (! extents.is_bounded)
        4259               0 :         status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
        4260                 :
        4261               0 :     if (clip_region != NULL)
        4262               0 :         _cairo_image_surface_unset_clip_region (dst);
        4263                 :
        4264               0 :     return status;
        4265                 : }
        4266                 :
        4267                 : static cairo_int_status_t
        4268               0 : _cairo_image_surface_fill_rectangles (void                    *abstract_surface,
        4269                 :                                       cairo_operator_t         op,
        4270                 :                                       const cairo_color_t     *color,
        4271                 :                                       cairo_rectangle_int_t   *rects,
        4272                 :                                       int                      num_rects)
        4273                 : {
        4274               0 :     cairo_image_surface_t *surface = abstract_surface;
        4275                 :
        4276                 :     pixman_color_t pixman_color;
        4277                 :     pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
        4278               0 :     pixman_box32_t *pixman_boxes = stack_boxes;
        4279                 :     int i;
        4280                 :
        4281                 :     cairo_int_status_t status;
        4282                 :
        4283                 :     if (CAIRO_INJECT_FAULT ())
        4284                 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        4285                 :
        4286               0 :     pixman_color.red   = color->red_short;
        4287               0 :     pixman_color.green = color->green_short;
        4288               0 :     pixman_color.blue  = color->blue_short;
        4289               0 :     pixman_color.alpha = color->alpha_short;
        4290                 :
        4291               0 :     if (num_rects > ARRAY_LENGTH (stack_boxes)) {
        4292               0 :         pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t));
        4293               0 :         if (unlikely (pixman_boxes == NULL))
        4294               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        4295                 :     }
        4296                 :
        4297               0 :     for (i = 0; i < num_rects; i++) {
        4298               0 :         pixman_boxes[i].x1 = rects[i].x;
        4299               0 :         pixman_boxes[i].y1 = rects[i].y;
        4300               0 :         pixman_boxes[i].x2 = rects[i].x + rects[i].width;
        4301               0 :         pixman_boxes[i].y2 = rects[i].y + rects[i].height;
        4302                 :     }
        4303                 :
        4304               0 :     status = CAIRO_STATUS_SUCCESS;
        4305               0 :     if (! pixman_image_fill_boxes (_pixman_operator (op),
        4306                 :                                    surface->pixman_image,
        4307                 :                                    &pixman_color,
        4308                 :                                    num_rects,
        4309                 :                                    pixman_boxes))
        4310                 :     {
        4311               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        4312                 :     }
        4313                 :
        4314               0 :     if (pixman_boxes != stack_boxes)
        4315               0 :         free (pixman_boxes);
        4316                 :
        4317               0 :     return status;
        4318                 : }
        4319                 :
        4320                 : static cairo_int_status_t
        4321               0 : _cairo_image_surface_composite_trapezoids (cairo_operator_t     op,
        4322                 :                                            const cairo_pattern_t *pattern,
        4323                 :                                            void                 *abstract_dst,
        4324                 :                                            cairo_antialias_t    antialias,
        4325                 :                                            int                  src_x,
        4326                 :                                            int                  src_y,
        4327                 :                                            int                  dst_x,
        4328                 :                                            int                  dst_y,
        4329                 :                                            unsigned int         width,
        4330                 :                                            unsigned int         height,
        4331                 :                                            cairo_trapezoid_t    *traps,
        4332                 :                                            int                  num_traps,
        4333                 :                                            cairo_region_t       *clip_region)
        4334                 : {
        4335               0 :     cairo_image_surface_t       *dst = abstract_dst;
        4336                 :     cairo_composite_rectangles_t extents;
        4337                 :     cairo_pattern_union_t        source_pattern;
        4338                 :     composite_traps_info_t       info;
        4339                 :     cairo_status_t               status;
        4340                 :
        4341               0 :     if (height == 0 || width == 0)
        4342               0 :         return CAIRO_STATUS_SUCCESS;
        4343                 :
        4344                 :     if (CAIRO_INJECT_FAULT ())
        4345                 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        4346                 :
        4347               0 :     extents.source.x = src_x;
        4348               0 :     extents.source.y = src_y;
        4349               0 :     extents.source.width  = width;
        4350               0 :     extents.source.height = height;
        4351                 :
        4352               0 :     extents.mask.x = dst_x;
        4353               0 :     extents.mask.y = dst_y;
        4354               0 :     extents.mask.width  = width;
        4355               0 :     extents.mask.height = height;
        4356                 :
        4357               0 :     extents.bounded.x = dst_x;
        4358               0 :     extents.bounded.y = dst_y;
        4359               0 :     extents.bounded.width  = width;
        4360               0 :     extents.bounded.height = height;
        4361                 :
        4362               0 :     extents.unbounded.x = 0;
        4363               0 :     extents.unbounded.y = 0;
        4364               0 :     extents.unbounded.width  = dst->width;
        4365               0 :     extents.unbounded.height = dst->height;
        4366                 :
        4367               0 :     if (clip_region != NULL) {
        4368                 :         cairo_rectangle_int_t rect;
        4369                 :
        4370               0 :         cairo_region_get_extents (clip_region, &rect);
        4371               0 :         if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
        4372               0 :             return CAIRO_STATUS_SUCCESS;
        4373                 :     }
        4374                 :
        4375               0 :     extents.is_bounded = _cairo_operator_bounded_by_either (op);
        4376                 :
        4377               0 :     if (clip_region != NULL) {
        4378               0 :         status = _cairo_image_surface_set_clip_region (dst, clip_region);
        4379               0 :         if (unlikely (status))
        4380               0 :             return status;
        4381                 :     }
        4382                 :
        4383               0 :     _cairo_pattern_init_static_copy (&source_pattern.base, pattern);
        4384               0 :     cairo_matrix_translate (&source_pattern.base.matrix,
        4385               0 :                             src_x - extents.bounded.x,
        4386               0 :                             src_y - extents.bounded.y);
        4387                 :
        4388               0 :     info.traps = traps;
        4389               0 :     info.num_traps = num_traps;
        4390               0 :     info.antialias = antialias;
        4391               0 :     status = _composite_traps (&info,
        4392                 :                                dst->pixman_image,
        4393                 :                                dst->pixman_format,
        4394                 :                                op,
        4395                 :                                &source_pattern.base,
        4396                 :                                0, 0,
        4397                 :                                &extents.bounded,
        4398                 :                                clip_region);
        4399                 :
        4400               0 :     if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
        4401               0 :         status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
        4402                 :
        4403               0 :     if (clip_region != NULL)
        4404               0 :         _cairo_image_surface_unset_clip_region (dst);
        4405                 :
        4406               0 :     return status;
        4407                 : }
        4408                 :
        4409                 : typedef struct _legacy_image_surface_span_renderer {
        4410                 :     cairo_span_renderer_t base;
        4411                 :
        4412                 :     cairo_operator_t op;
        4413                 :     const cairo_pattern_t *pattern;
        4414                 :     cairo_antialias_t antialias;
        4415                 :     cairo_region_t *clip_region;
        4416                 :
        4417                 :     pixman_image_t *mask;
        4418                 :     uint8_t *mask_data;
        4419                 :     uint32_t mask_stride;
        4420                 :
        4421                 :     cairo_image_surface_t *dst;
        4422                 :     cairo_composite_rectangles_t composite_rectangles;
        4423                 : } legacy_image_surface_span_renderer_t;
        4424                 :
        4425                 : void
        4426               0 : _cairo_image_surface_span_render_row (
        4427                 :     int                                  y,
        4428                 :     const cairo_half_open_span_t        *spans,
        4429                 :     unsigned                             num_spans,
        4430                 :     uint8_t                             *data,
        4431                 :     uint32_t                             stride)
        4432                 : {
        4433                 :     uint8_t *row;
        4434                 :     unsigned i;
        4435                 :
        4436               0 :     if (num_spans == 0)
        4437               0 :         return;
        4438                 :
        4439               0 :     row = data + y * stride;
        4440               0 :     for (i = 0; i < num_spans - 1; i++) {
        4441               0 :         if (! spans[i].coverage)
        4442               0 :             continue;
        4443                 :
        4444                 :         /* We implement setting the most common single pixel wide
        4445                 :          * span case to avoid the overhead of a memset call.
        4446                 :          * Open coding setting longer spans didn't show a
        4447                 :          * noticeable improvement over memset.
        4448                 :          */
        4449               0 :         if (spans[i+1].x == spans[i].x + 1) {
        4450               0 :             row[spans[i].x] = spans[i].coverage;
        4451                 :         } else {
        4452               0 :             memset (row + spans[i].x,
        4453               0 :                     spans[i].coverage,
        4454               0 :                     spans[i+1].x - spans[i].x);
        4455                 :         }
        4456                 :     }
        4457                 : }
        4458                 :
        4459                 : static cairo_status_t
        4460               0 : _cairo_image_surface_span_renderer_render_rows (
        4461                 :     void                                *abstract_renderer,
        4462                 :     int                                  y,
        4463                 :     int                                  height,
        4464                 :     const cairo_half_open_span_t        *spans,
        4465                 :     unsigned                             num_spans)
        4466                 : {
        4467               0 :     legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
        4468               0 :     while (height--)
        4469               0 :         _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
        4470               0 :     return CAIRO_STATUS_SUCCESS;
        4471                 : }
        4472                 :
        4473                 : static void
        4474               0 : _cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
        4475                 : {
        4476               0 :     legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
        4477               0 :     if (renderer == NULL)
        4478               0 :         return;
        4479                 :
        4480               0 :     pixman_image_unref (renderer->mask);
        4481                 :
        4482               0 :     free (renderer);
        4483                 : }
        4484                 :
        4485                 : static cairo_status_t
        4486               0 : _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
        4487                 : {
        4488               0 :     legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
        4489               0 :     cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
        4490               0 :     cairo_image_surface_t *dst = renderer->dst;
        4491                 :     pixman_image_t *src;
        4492                 :     int src_x, src_y;
        4493                 :     cairo_status_t status;
        4494                 :
        4495               0 :     if (renderer->clip_region != NULL) {
        4496               0 :         status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
        4497               0 :         if (unlikely (status))
        4498               0 :             return status;
        4499                 :     }
        4500                 :
        4501               0 :     src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, &src_x, &src_y);
        4502               0 :     if (src == NULL)
        4503               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
        4504                 :
        4505               0 :     status = CAIRO_STATUS_SUCCESS;
        4506               0 :     pixman_image_composite32 (_pixman_operator (renderer->op),
        4507                 :                               src,
        4508                 :                               renderer->mask,
        4509                 :                               dst->pixman_image,
        4510               0 :                               rects->bounded.x + src_x,
        4511               0 :                               rects->bounded.y + src_y,
        4512                 :                               0, 0,
        4513                 :                               rects->bounded.x, rects->bounded.y,
        4514                 :                               rects->bounded.width, rects->bounded.height);
        4515                 :
        4516               0 :     if (! rects->is_bounded)
        4517               0 :         status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
        4518                 :
        4519               0 :     if (renderer->clip_region != NULL)
        4520               0 :          _cairo_image_surface_unset_clip_region (dst);
        4521                 :
        4522               0 :     return status;
        4523                 : }
        4524                 :
        4525                 : static cairo_bool_t
        4526               0 : _cairo_image_surface_check_span_renderer (cairo_operator_t        op,
        4527                 :                                           const cairo_pattern_t  *pattern,
        4528                 :                                           void                   *abstract_dst,
        4529                 :                                           cairo_antialias_t       antialias)
        4530                 : {
        4531               0 :     return TRUE;
        4532                 :     (void) op;
        4533                 :     (void) pattern;
        4534                 :     (void) abstract_dst;
        4535                 :     (void) antialias;
        4536                 : }
        4537                 :
        4538                 : static cairo_span_renderer_t *
        4539               0 : _cairo_image_surface_create_span_renderer (cairo_operator_t      op,
        4540                 :                                            const cairo_pattern_t  *pattern,
        4541                 :                                            void                 *abstract_dst,
        4542                 :                                            cairo_antialias_t     antialias,
        4543                 :                                            const cairo_composite_rectangles_t *rects,
        4544                 :                                            cairo_region_t *clip_region)
        4545                 : {
        4546               0 :     cairo_image_surface_t *dst = abstract_dst;
        4547                 :     legacy_image_surface_span_renderer_t *renderer;
        4548                 :
        4549               0 :     renderer = calloc(1, sizeof(*renderer));
        4550               0 :     if (unlikely (renderer == NULL))
        4551               0 :         return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
        4552                 :
        4553               0 :     renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
        4554               0 :     renderer->base.finish = _cairo_image_surface_span_renderer_finish;
        4555               0 :     renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
        4556               0 :     renderer->op = op;
        4557               0 :     renderer->pattern = pattern;
        4558               0 :     renderer->antialias = antialias;
        4559               0 :     renderer->dst = dst;
        4560               0 :     renderer->clip_region = clip_region;
        4561                 :
        4562               0 :     renderer->composite_rectangles = *rects;
        4563                 :
        4564                 :     /* TODO: support rendering to A1 surfaces (or: go add span
        4565                 :      * compositing to pixman.) */
        4566               0 :     renderer->mask = pixman_image_create_bits (PIXMAN_a8,
        4567                 :                                                rects->bounded.width,
        4568                 :                                                rects->bounded.height,
        4569                 :                                                NULL, 0);
        4570               0 :     if (renderer->mask == NULL) {
        4571               0 :         free (renderer);
        4572               0 :         return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
        4573                 :     }
        4574                 :
        4575               0 :     renderer->mask_stride = pixman_image_get_stride (renderer->mask);
        4576               0 :     renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
        4577                 :
        4578               0 :     return &renderer->base;
        4579                 : }
        4580                 :
        4581                 : /**
        4582                 :  * _cairo_surface_is_image:
        4583                 :  * @surface: a #cairo_surface_t
        4584                 :  *
        4585                 :  * Checks if a surface is an #cairo_image_surface_t
        4586                 :  *
        4587                 :  * Return value: %TRUE if the surface is an image surface
        4588                 :  **/
        4589                 : cairo_bool_t
        4590               0 : _cairo_surface_is_image (const cairo_surface_t *surface)
        4591                 : {
        4592               0 :     return surface->backend == &_cairo_image_surface_backend;
        4593                 : }
        4594                 :
        4595                 : const cairo_surface_backend_t _cairo_image_surface_backend = {
        4596                 :     CAIRO_SURFACE_TYPE_IMAGE,
        4597                 :     _cairo_image_surface_create_similar,
        4598                 :     _cairo_image_surface_finish,
        4599                 :     _cairo_image_surface_acquire_source_image,
        4600                 :     _cairo_image_surface_release_source_image,
        4601                 :     _cairo_image_surface_acquire_dest_image,
        4602                 :     _cairo_image_surface_release_dest_image,
        4603                 :     _cairo_image_surface_clone_similar,
        4604                 :     _cairo_image_surface_composite,
        4605                 :     _cairo_image_surface_fill_rectangles,
        4606                 :     _cairo_image_surface_composite_trapezoids,
        4607                 :     _cairo_image_surface_create_span_renderer,
        4608                 :     _cairo_image_surface_check_span_renderer,
        4609                 :
        4610                 :     NULL, /* copy_page */
        4611                 :     NULL, /* show_page */
        4612                 :     _cairo_image_surface_get_extents,
        4613                 :     NULL, /* old_show_glyphs */
        4614                 :     _cairo_image_surface_get_font_options,
        4615                 :     NULL, /* flush */
        4616                 :     NULL, /* mark dirty */
        4617                 :     NULL, /* font_fini */
        4618                 :     NULL, /* glyph_fini */
        4619                 :
        4620                 :     _cairo_image_surface_paint,
        4621                 :     _cairo_image_surface_mask,
        4622                 :     _cairo_image_surface_stroke,
        4623                 :     _cairo_image_surface_fill,
        4624                 :     _cairo_image_surface_glyphs,
        4625                 :     NULL, /* show_text_glyphs */
        4626                 :     NULL, /* snapshot */
        4627                 :     NULL, /* is_similar */
        4628                 : };
        4629                 :
        4630                 : /* A convenience function for when one needs to coerce an image
        4631                 :  * surface to an alternate format. */
        4632                 : cairo_image_surface_t *
        4633               0 : _cairo_image_surface_coerce (cairo_image_surface_t *surface)
        4634                 : {
        4635               0 :     return _cairo_image_surface_coerce_to_format (surface,
        4636                 :                                                   _cairo_format_from_content (surface->base.content));
        4637                 :
        4638                 : }
        4639                 :
        4640                 : /* A convenience function for when one needs to coerce an image
        4641                 :  * surface to an alternate format. */
        4642                 : cairo_image_surface_t *
        4643               0 : _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
        4644                 :                                        cairo_format_t         format)
        4645                 : {
        4646                 :     cairo_image_surface_t *clone;
        4647                 :     cairo_status_t status;
        4648                 :
        4649               0 :     status = surface->base.status;
        4650               0 :     if (unlikely (status))
        4651               0 :         return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
        4652                 :
        4653               0 :     if (surface->format == format)
        4654               0 :         return (cairo_image_surface_t *)cairo_surface_reference(&surface->base);
        4655                 :
        4656               0 :     clone = (cairo_image_surface_t *)
        4657               0 :         cairo_image_surface_create (format, surface->width, surface->height);
        4658               0 :     if (unlikely (clone->base.status))
        4659               0 :         return clone;
        4660                 :
        4661               0 :     pixman_image_composite32 (PIXMAN_OP_SRC,
        4662                 :                               surface->pixman_image, NULL, clone->pixman_image,
        4663                 :                               0, 0,
        4664                 :                               0, 0,
        4665                 :                               0, 0,
        4666                 :                               surface->width, surface->height);
        4667               0 :     clone->base.is_clear = FALSE;
        4668                 :
        4669               0 :     clone->base.device_transform =
        4670                 :         surface->base.device_transform;
        4671               0 :     clone->base.device_transform_inverse =
        4672                 :         surface->base.device_transform_inverse;
        4673                 :
        4674               0 :     return clone;
        4675                 : }
        4676                 :
        4677                 : cairo_image_transparency_t
        4678               0 : _cairo_image_analyze_transparency (cairo_image_surface_t      *image)
        4679                 : {
        4680                 :     int x, y;
        4681                 :
        4682               0 :     if (image->transparency != CAIRO_IMAGE_UNKNOWN)
        4683               0 :         return image->transparency;
        4684                 :
        4685               0 :     if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0)
        4686               0 :         return image->transparency = CAIRO_IMAGE_IS_OPAQUE;
        4687                 :
        4688               0 :     if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) {
        4689               0 :         if (image->format == CAIRO_FORMAT_A1)
        4690               0 :             return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
        4691                 :         else
        4692               0 :             return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
        4693                 :     }
        4694                 :
        4695               0 :     if (image->format == CAIRO_FORMAT_RGB16_565) {
        4696               0 :         image->transparency = CAIRO_IMAGE_IS_OPAQUE;
        4697               0 :         return CAIRO_IMAGE_IS_OPAQUE;
        4698                 :     }
        4699                 :
        4700               0 :     if (image->format != CAIRO_FORMAT_ARGB32)
        4701               0 :         return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
        4702                 :
        4703               0 :     image->transparency = CAIRO_IMAGE_IS_OPAQUE;
        4704               0 :     for (y = 0; y < image->height; y++) {
        4705               0 :         uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
        4706                 :
        4707               0 :         for (x = 0; x < image->width; x++, pixel++) {
        4708               0 :             int a = (*pixel & 0xff000000) >> 24;
        4709               0 :             if (a > 0 && a < 255) {
        4710               0 :                 return image->transparency = CAIRO_IMAGE_HAS_ALPHA;
        4711               0 :             } else if (a == 0) {
        4712               0 :                 image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
        4713                 :             }
        4714                 :         }
        4715                 :     }
        4716                 :
        4717               0 :     return image->transparency;
        4718                 : }

Generated by: LCOV version 1.7