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

LCOV - code coverage report
| Current view: | directory - gfx/cairo/cairo/src - cairo-surface-fallback.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 638 | 0 | 0.0 %
| Date: | 2012-07-07 | Functions: | 26 | 0 | 0.0 %

           1                 : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
           2                 : /* cairo - a vector graphics library with display and print output
           3                 :  *
           4                 :  * Copyright © 2002 University of Southern California
           5                 :  * Copyright © 2005 Red Hat, Inc.
           6                 :  *
           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                 :  *      Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
          38                 :  *      Chris Wilson <chris@chris-wilson.co.uk>
          39                 :  */
          40                 :
          41                 : #include "cairoint.h"
          42                 :
          43                 : #include "cairo-boxes-private.h"
          44                 : #include "cairo-clip-private.h"
          45                 : #include "cairo-composite-rectangles-private.h"
          46                 : #include "cairo-error-private.h"
          47                 : #include "cairo-region-private.h"
          48                 : #include "cairo-spans-private.h"
          49                 : #include "cairo-surface-fallback-private.h"
          50                 :
          51                 : typedef struct {
          52                 :     cairo_surface_t *dst;
          53                 :     cairo_rectangle_int_t extents;
          54                 :     cairo_image_surface_t *image;
          55                 :     cairo_rectangle_int_t image_rect;
          56                 :     void *image_extra;
          57                 : } fallback_state_t;
          58                 :
          59                 : /**
          60                 :  * _fallback_init:
          61                 :  *
          62                 :  * Acquire destination image surface needed for an image-based
          63                 :  * fallback.
          64                 :  *
          65                 :  * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
          66                 :  * visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all
          67                 :  * went well, or some error status otherwise.
          68                 :  **/
          69                 : static cairo_int_status_t
          70               0 : _fallback_init (fallback_state_t *state,
          71                 :                 cairo_surface_t  *dst,
          72                 :                 int               x,
          73                 :                 int               y,
          74                 :                 int               width,
          75                 :                 int               height)
          76                 : {
          77                 :     cairo_status_t status;
          78                 :
          79               0 :     state->extents.x = x;
          80               0 :     state->extents.y = y;
          81               0 :     state->extents.width = width;
          82               0 :     state->extents.height = height;
          83                 :
          84               0 :     state->dst = dst;
          85                 :
          86               0 :     status = _cairo_surface_acquire_dest_image (dst, &state->extents,
          87                 :                                                 &state->image, &state->image_rect,
          88                 :                                                 &state->image_extra);
          89               0 :     if (unlikely (status))
          90               0 :         return status;
          91                 :
          92                 :
          93                 :     /* XXX: This NULL value tucked away in state->image is a rather
          94                 :      * ugly interface. Cleaner would be to push the
          95                 :      * CAIRO_INT_STATUS_NOTHING_TO_DO value down into
          96                 :      * _cairo_surface_acquire_dest_image and its backend
          97                 :      * counterparts. */
          98               0 :     assert (state->image != NULL);
          99                 :
         100               0 :     return CAIRO_STATUS_SUCCESS;
         101                 : }
         102                 :
         103                 : static void
         104               0 : _fallback_fini (fallback_state_t *state)
         105                 : {
         106               0 :     _cairo_surface_release_dest_image (state->dst, &state->extents,
         107                 :                                        state->image, &state->image_rect,
         108                 :                                        state->image_extra);
         109               0 : }
         110                 :
         111                 : typedef cairo_status_t
         112                 : (*cairo_draw_func_t) (void                          *closure,
         113                 :                       cairo_operator_t               op,
         114                 :                       const cairo_pattern_t         *src,
         115                 :                       cairo_surface_t               *dst,
         116                 :                       int                            dst_x,
         117                 :                       int                            dst_y,
         118                 :                       const cairo_rectangle_int_t   *extents,
         119                 :                       cairo_region_t                *clip_region);
         120                 :
         121                 : static cairo_status_t
         122               0 : _create_composite_mask_pattern (cairo_surface_pattern_t       *mask_pattern,
         123                 :                                 cairo_clip_t                  *clip,
         124                 :                                 cairo_draw_func_t              draw_func,
         125                 :                                 void                          *draw_closure,
         126                 :                                 cairo_surface_t               *dst,
         127                 :                                 const cairo_rectangle_int_t   *extents)
         128                 : {
         129                 :     cairo_surface_t *mask;
         130               0 :     cairo_region_t *clip_region = NULL, *fallback_region = NULL;
         131                 :     cairo_status_t status;
         132               0 :     cairo_bool_t clip_surface = FALSE;
         133                 :
         134               0 :     if (clip != NULL) {
         135               0 :         status = _cairo_clip_get_region (clip, &clip_region);
         136               0 :         if (unlikely (_cairo_status_is_error (status) ||
         137                 :                       status == CAIRO_INT_STATUS_NOTHING_TO_DO))
         138                 :         {
         139               0 :             return status;
         140                 :         }
         141                 :
         142               0 :         clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
         143                 :     }
         144                 :
         145                 :     /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with
         146                 :      * a mask (as called via _cairo_surface_mask) triggers assertion failures.
         147                 :      */
         148               0 :     mask = _cairo_surface_create_similar_solid (dst,
         149                 :                                                 CAIRO_CONTENT_ALPHA,
         150                 :                                                 extents->width,
         151                 :                                                 extents->height,
         152                 :                                                 CAIRO_COLOR_TRANSPARENT,
         153                 :                                                 TRUE);
         154               0 :     if (unlikely (mask->status))
         155               0 :         return mask->status;
         156                 :
         157               0 :     if (clip_region && (extents->x || extents->y)) {
         158               0 :         fallback_region = cairo_region_copy (clip_region);
         159               0 :         status = fallback_region->status;
         160               0 :         if (unlikely (status))
         161               0 :             goto CLEANUP_SURFACE;
         162                 :
         163               0 :         cairo_region_translate (fallback_region,
         164               0 :                                 -extents->x,
         165               0 :                                 -extents->y);
         166               0 :         clip_region = fallback_region;
         167                 :     }
         168                 :
         169               0 :     status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
         170                 :                         &_cairo_pattern_white.base, mask,
         171                 :                         extents->x, extents->y,
         172                 :                         extents,
         173                 :                         clip_region);
         174               0 :     if (unlikely (status))
         175               0 :         goto CLEANUP_SURFACE;
         176                 :
         177               0 :     if (clip_surface)
         178               0 :         status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y);
         179                 :
         180               0 :     _cairo_pattern_init_for_surface (mask_pattern, mask);
         181                 :
         182                 :  CLEANUP_SURFACE:
         183               0 :     if (fallback_region)
         184               0 :         cairo_region_destroy (fallback_region);
         185               0 :     cairo_surface_destroy (mask);
         186                 :
         187               0 :     return status;
         188                 : }
         189                 :
         190                 : /* Handles compositing with a clip surface when the operator allows
         191                 :  * us to combine the clip with the mask
         192                 :  */
         193                 : static cairo_status_t
         194               0 : _clip_and_composite_with_mask (cairo_clip_t                  *clip,
         195                 :                                cairo_operator_t               op,
         196                 :                                const cairo_pattern_t         *src,
         197                 :                                cairo_draw_func_t              draw_func,
         198                 :                                void                          *draw_closure,
         199                 :                                cairo_surface_t               *dst,
         200                 :                                const cairo_rectangle_int_t   *extents)
         201                 : {
         202                 :     cairo_surface_pattern_t mask_pattern;
         203                 :     cairo_status_t status;
         204                 :
         205               0 :     status = _create_composite_mask_pattern (&mask_pattern,
         206                 :                                              clip,
         207                 :                                              draw_func, draw_closure,
         208                 :                                              dst, extents);
         209               0 :     if (likely (status == CAIRO_STATUS_SUCCESS)) {
         210               0 :         status = _cairo_surface_composite (op,
         211                 :                                            src, &mask_pattern.base, dst,
         212                 :                                            extents->x,     extents->y,
         213                 :                                            0,              0,
         214                 :                                            extents->x,     extents->y,
         215               0 :                                            extents->width, extents->height,
         216                 :                                            NULL);
         217                 :
         218               0 :         _cairo_pattern_fini (&mask_pattern.base);
         219                 :     }
         220                 :
         221               0 :     return status;
         222                 : }
         223                 :
         224                 : /* Handles compositing with a clip surface when we have to do the operation
         225                 :  * in two pieces and combine them together.
         226                 :  */
         227                 : static cairo_status_t
         228               0 : _clip_and_composite_combine (cairo_clip_t                  *clip,
         229                 :                              cairo_operator_t               op,
         230                 :                              const cairo_pattern_t         *src,
         231                 :                              cairo_draw_func_t              draw_func,
         232                 :                              void                          *draw_closure,
         233                 :                              cairo_surface_t               *dst,
         234                 :                              const cairo_rectangle_int_t   *extents)
         235                 : {
         236                 :     cairo_surface_t *intermediate;
         237                 :     cairo_surface_pattern_t pattern;
         238                 :     cairo_surface_pattern_t clip_pattern;
         239                 :     cairo_surface_t *clip_surface;
         240                 :     int clip_x, clip_y;
         241                 :     cairo_status_t status;
         242                 :
         243                 :     /* We'd be better off here creating a surface identical in format
         244                 :      * to dst, but we have no way of getting that information. Instead
         245                 :      * we ask the backend to create a similar surface of identical content,
         246                 :      * in the belief that the backend will do something useful - like use
         247                 :      * an identical format. For example, the xlib backend will endeavor to
         248                 :      * use a compatible depth to enable core protocol routines.
         249                 :      */
         250               0 :     intermediate =
         251               0 :         _cairo_surface_create_similar_scratch (dst, dst->content,
         252                 :                                                extents->width,
         253                 :                                                extents->height);
         254               0 :     if (intermediate == NULL) {
         255               0 :         intermediate =
         256               0 :             _cairo_image_surface_create_with_content (dst->content,
         257                 :                                                       extents->width,
         258                 :                                                       extents->width);
         259                 :     }
         260               0 :     if (unlikely (intermediate->status))
         261               0 :         return intermediate->status;
         262                 :
         263                 :     /* Initialize the intermediate surface from the destination surface */
         264               0 :     _cairo_pattern_init_for_surface (&pattern, dst);
         265               0 :     status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
         266                 :                                        &pattern.base, NULL, intermediate,
         267                 :                                        extents->x,     extents->y,
         268                 :                                        0,              0,
         269                 :                                        0,              0,
         270               0 :                                        extents->width, extents->height,
         271                 :                                        NULL);
         272               0 :     _cairo_pattern_fini (&pattern.base);
         273               0 :     if (unlikely (status))
         274               0 :         goto CLEANUP_SURFACE;
         275                 :
         276               0 :     status = (*draw_func) (draw_closure, op,
         277                 :                            src, intermediate,
         278                 :                            extents->x, extents->y,
         279                 :                            extents,
         280                 :                            NULL);
         281               0 :     if (unlikely (status))
         282               0 :         goto CLEANUP_SURFACE;
         283                 :
         284               0 :     assert (clip->path != NULL);
         285               0 :     clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
         286               0 :     if (unlikely (clip_surface->status))
         287               0 :         goto CLEANUP_SURFACE;
         288                 :
         289               0 :     _cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
         290                 :
         291                 :     /* Combine that with the clip */
         292               0 :     status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
         293                 :                                        &clip_pattern.base, NULL, intermediate,
         294               0 :                                        extents->x - clip_x,
         295               0 :                                        extents->y - clip_y,
         296                 :                                        0, 0,
         297                 :                                        0, 0,
         298               0 :                                        extents->width, extents->height,
         299                 :                                        NULL);
         300               0 :     if (unlikely (status))
         301               0 :         goto CLEANUP_CLIP;
         302                 :
         303                 :     /* Punch the clip out of the destination */
         304               0 :     status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
         305                 :                                        &clip_pattern.base, NULL, dst,
         306               0 :                                        extents->x - clip_x,
         307               0 :                                        extents->y - clip_y,
         308                 :                                        0, 0,
         309                 :                                        extents->x, extents->y,
         310               0 :                                        extents->width, extents->height,
         311                 :                                        NULL);
         312               0 :     if (unlikely (status))
         313               0 :         goto CLEANUP_CLIP;
         314                 :
         315                 :     /* Now add the two results together */
         316               0 :     _cairo_pattern_init_for_surface (&pattern, intermediate);
         317               0 :     status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
         318                 :                                        &pattern.base, NULL, dst,
         319                 :                                        0,              0,
         320                 :                                        0,              0,
         321                 :                                        extents->x,     extents->y,
         322               0 :                                        extents->width, extents->height,
         323                 :                                        NULL);
         324               0 :     _cairo_pattern_fini (&pattern.base);
         325                 :
         326                 :  CLEANUP_CLIP:
         327               0 :     _cairo_pattern_fini (&clip_pattern.base);
         328                 :  CLEANUP_SURFACE:
         329               0 :     cairo_surface_destroy (intermediate);
         330                 :
         331               0 :     return status;
         332                 : }
         333                 :
         334                 : /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
         335                 :  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
         336                 :  */
         337                 : static cairo_status_t
         338               0 : _clip_and_composite_source (cairo_clip_t                  *clip,
         339                 :                             const cairo_pattern_t         *src,
         340                 :                             cairo_draw_func_t              draw_func,
         341                 :                             void                          *draw_closure,
         342                 :                             cairo_surface_t               *dst,
         343                 :                             const cairo_rectangle_int_t   *extents)
         344                 : {
         345                 :     cairo_surface_pattern_t mask_pattern;
         346               0 :     cairo_region_t *clip_region = NULL;
         347                 :     cairo_status_t status;
         348                 :
         349               0 :     if (clip != NULL) {
         350               0 :         status = _cairo_clip_get_region (clip, &clip_region);
         351               0 :         if (unlikely (_cairo_status_is_error (status) ||
         352                 :                       status == CAIRO_INT_STATUS_NOTHING_TO_DO))
         353                 :         {
         354               0 :             return status;
         355                 :         }
         356                 :     }
         357                 :
         358                 :     /* Create a surface that is mask IN clip */
         359               0 :     status = _create_composite_mask_pattern (&mask_pattern,
         360                 :                                              clip,
         361                 :                                              draw_func, draw_closure,
         362                 :                                              dst, extents);
         363               0 :     if (unlikely (status))
         364               0 :         return status;
         365                 :
         366                 :     /* Compute dest' = dest OUT (mask IN clip) */
         367               0 :     status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
         368                 :                                        &mask_pattern.base, NULL, dst,
         369                 :                                        0,              0,
         370                 :                                        0,              0,
         371                 :                                        extents->x,     extents->y,
         372               0 :                                        extents->width, extents->height,
         373                 :                                        clip_region);
         374                 :
         375               0 :     if (unlikely (status))
         376               0 :         goto CLEANUP_MASK_PATTERN;
         377                 :
         378                 :     /* Now compute (src IN (mask IN clip)) ADD dest' */
         379               0 :     status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
         380                 :                                        src, &mask_pattern.base, dst,
         381                 :                                        extents->x,     extents->y,
         382                 :                                        0,              0,
         383                 :                                        extents->x,     extents->y,
         384               0 :                                        extents->width, extents->height,
         385                 :                                        clip_region);
         386                 :
         387                 :  CLEANUP_MASK_PATTERN:
         388               0 :     _cairo_pattern_fini (&mask_pattern.base);
         389               0 :     return status;
         390                 : }
         391                 :
         392                 : static int
         393               0 : _cairo_rectangle_empty (const cairo_rectangle_int_t *rect)
         394                 : {
         395               0 :     return rect->width == 0 || rect->height == 0;
         396                 : }
         397                 :
         398                 : /**
         399                 :  * _clip_and_composite:
         400                 :  * @clip: a #cairo_clip_t
         401                 :  * @op: the operator to draw with
         402                 :  * @src: source pattern
         403                 :  * @draw_func: function that can be called to draw with the mask onto a surface.
         404                 :  * @draw_closure: data to pass to @draw_func.
         405                 :  * @dst: destination surface
         406                 :  * @extents: rectangle holding a bounding box for the operation; this
         407                 :  *           rectangle will be used as the size for the temporary
         408                 :  *           surface.
         409                 :  *
         410                 :  * When there is a surface clip, we typically need to create an intermediate
         411                 :  * surface. This function handles the logic of creating a temporary surface
         412                 :  * drawing to it, then compositing the result onto the target surface.
         413                 :  *
         414                 :  * @draw_func is to called to draw the mask; it will be called no more
         415                 :  * than once.
         416                 :  *
         417                 :  * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
         418                 :  **/
         419                 : static cairo_status_t
         420               0 : _clip_and_composite (cairo_clip_t                  *clip,
         421                 :                      cairo_operator_t               op,
         422                 :                      const cairo_pattern_t         *src,
         423                 :                      cairo_draw_func_t              draw_func,
         424                 :                      void                          *draw_closure,
         425                 :                      cairo_surface_t               *dst,
         426                 :                      const cairo_rectangle_int_t   *extents)
         427                 : {
         428                 :     cairo_status_t status;
         429                 :
         430               0 :     if (_cairo_rectangle_empty (extents))
         431                 :         /* Nothing to do */
         432               0 :         return CAIRO_STATUS_SUCCESS;
         433                 :
         434               0 :     if (op == CAIRO_OPERATOR_CLEAR) {
         435               0 :         src = &_cairo_pattern_white.base;
         436               0 :         op = CAIRO_OPERATOR_DEST_OUT;
         437                 :     }
         438                 :
         439               0 :     if (op == CAIRO_OPERATOR_SOURCE) {
         440               0 :         status = _clip_and_composite_source (clip,
         441                 :                                              src,
         442                 :                                              draw_func, draw_closure,
         443                 :                                              dst, extents);
         444                 :     } else {
         445               0 :         cairo_bool_t clip_surface = FALSE;
         446               0 :         cairo_region_t *clip_region = NULL;
         447                 :
         448               0 :         if (clip != NULL) {
         449               0 :             status = _cairo_clip_get_region (clip, &clip_region);
         450               0 :             if (unlikely (_cairo_status_is_error (status) ||
         451                 :                           status == CAIRO_INT_STATUS_NOTHING_TO_DO))
         452                 :             {
         453               0 :                 return status;
         454                 :             }
         455                 :
         456               0 :             clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
         457                 :         }
         458                 :
         459               0 :         if (clip_surface) {
         460               0 :             if (_cairo_operator_bounded_by_mask (op)) {
         461               0 :                 status = _clip_and_composite_with_mask (clip, op,
         462                 :                                                         src,
         463                 :                                                         draw_func, draw_closure,
         464                 :                                                         dst, extents);
         465                 :             } else {
         466               0 :                 status = _clip_and_composite_combine (clip, op,
         467                 :                                                       src,
         468                 :                                                       draw_func, draw_closure,
         469                 :                                                       dst, extents);
         470                 :             }
         471                 :         } else {
         472               0 :             status = draw_func (draw_closure, op,
         473                 :                                 src, dst,
         474                 :                                 0, 0,
         475                 :                                 extents,
         476                 :                                 clip_region);
         477                 :         }
         478                 :     }
         479                 :
         480               0 :     return status;
         481                 : }
         482                 :
         483                 : /* Composites a region representing a set of trapezoids.
         484                 :  */
         485                 : static cairo_status_t
         486               0 : _composite_trap_region (cairo_clip_t            *clip,
         487                 :                         const cairo_pattern_t   *src,
         488                 :                         cairo_operator_t         op,
         489                 :                         cairo_surface_t         *dst,
         490                 :                         cairo_region_t          *trap_region,
         491                 :                         const cairo_rectangle_int_t   *extents)
         492                 : {
         493                 :     cairo_status_t status;
         494                 :     cairo_surface_pattern_t mask_pattern;
         495               0 :     cairo_pattern_t *mask = NULL;
         496               0 :     int mask_x = 0, mask_y =0;
         497                 :
         498               0 :     if (clip != NULL) {
         499               0 :         cairo_surface_t *clip_surface = NULL;
         500                 :         int clip_x, clip_y;
         501                 :
         502               0 :         clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
         503               0 :         if (unlikely (clip_surface->status))
         504               0 :             return clip_surface->status;
         505                 :
         506               0 :         if (op == CAIRO_OPERATOR_CLEAR) {
         507               0 :             src = &_cairo_pattern_white.base;
         508               0 :             op = CAIRO_OPERATOR_DEST_OUT;
         509                 :         }
         510                 :
         511               0 :         _cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
         512               0 :         mask_x = extents->x - clip_x;
         513               0 :         mask_y = extents->y - clip_y;
         514               0 :         mask = &mask_pattern.base;
         515                 :     }
         516                 :
         517               0 :     status = _cairo_surface_composite (op, src, mask, dst,
         518                 :                                        extents->x, extents->y,
         519                 :                                        mask_x, mask_y,
         520                 :                                        extents->x, extents->y,
         521               0 :                                        extents->width, extents->height,
         522                 :                                        trap_region);
         523                 :
         524               0 :     if (mask != NULL)
         525               0 :       _cairo_pattern_fini (mask);
         526                 :
         527               0 :     return status;
         528                 : }
         529                 :
         530                 : typedef struct {
         531                 :     cairo_traps_t *traps;
         532                 :     cairo_antialias_t antialias;
         533                 : } cairo_composite_traps_info_t;
         534                 :
         535                 : static cairo_status_t
         536               0 : _composite_traps_draw_func (void                          *closure,
         537                 :                             cairo_operator_t               op,
         538                 :                             const cairo_pattern_t         *src,
         539                 :                             cairo_surface_t               *dst,
         540                 :                             int                            dst_x,
         541                 :                             int                            dst_y,
         542                 :                             const cairo_rectangle_int_t   *extents,
         543                 :                             cairo_region_t                *clip_region)
         544                 : {
         545               0 :     cairo_composite_traps_info_t *info = closure;
         546                 :     cairo_status_t status;
         547               0 :     cairo_region_t *extents_region = NULL;
         548                 :
         549               0 :     if (dst_x != 0 || dst_y != 0)
         550               0 :         _cairo_traps_translate (info->traps, - dst_x, - dst_y);
         551                 :
         552               0 :     if (clip_region == NULL &&
         553               0 :         !_cairo_operator_bounded_by_source (op)) {
         554               0 :         extents_region = cairo_region_create_rectangle (extents);
         555               0 :         if (unlikely (extents_region->status))
         556               0 :             return extents_region->status;
         557               0 :         cairo_region_translate (extents_region, -dst_x, -dst_y);
         558               0 :         clip_region = extents_region;
         559                 :     }
         560                 :
         561               0 :     status = _cairo_surface_composite_trapezoids (op,
         562                 :                                                   src, dst, info->antialias,
         563                 :                                                   extents->x,         extents->y,
         564               0 :                                                   extents->x - dst_x, extents->y - dst_y,
         565               0 :                                                   extents->width,     extents->height,
         566               0 :                                                   info->traps->traps,
         567               0 :                                                   info->traps->num_traps,
         568                 :                                                   clip_region);
         569                 :
         570               0 :     if (extents_region)
         571               0 :         cairo_region_destroy (extents_region);
         572                 :
         573               0 :     return status;
         574                 : }
         575                 :
         576                 : enum {
         577                 :     HAS_CLEAR_REGION = 0x1,
         578                 : };
         579                 :
         580                 : static cairo_status_t
         581               0 : _clip_and_composite_region (const cairo_pattern_t *src,
         582                 :                             cairo_operator_t op,
         583                 :                             cairo_surface_t *dst,
         584                 :                             cairo_region_t *trap_region,
         585                 :                             cairo_clip_t *clip,
         586                 :                             cairo_rectangle_int_t *extents)
         587                 : {
         588                 :     cairo_region_t clear_region;
         589               0 :     unsigned int has_region = 0;
         590                 :     cairo_status_t status;
         591                 :
         592               0 :     if (! _cairo_operator_bounded_by_mask (op) && clip == NULL) {
         593                 :         /* If we optimize drawing with an unbounded operator to
         594                 :          * _cairo_surface_fill_rectangles() or to drawing with a
         595                 :          * clip region, then we have an additional region to clear.
         596                 :          */
         597               0 :         _cairo_region_init_rectangle (&clear_region, extents);
         598               0 :         status = cairo_region_subtract (&clear_region, trap_region);
         599               0 :         if (unlikely (status))
         600               0 :             return status;
         601                 :
         602               0 :         if (! cairo_region_is_empty (&clear_region))
         603               0 :             has_region |= HAS_CLEAR_REGION;
         604                 :     }
         605                 :
         606               0 :     if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
         607                 :         clip == NULL)
         608               0 :     {
         609                 :         const cairo_color_t *color;
         610                 :
         611               0 :         if (op == CAIRO_OPERATOR_CLEAR)
         612               0 :             color = CAIRO_COLOR_TRANSPARENT;
         613                 :         else
         614               0 :             color = &((cairo_solid_pattern_t *)src)->color;
         615                 :
         616                 :         /* Solid rectangles special case */
         617               0 :         status = _cairo_surface_fill_region (dst, op, color, trap_region);
         618                 :     } else {
         619                 :         /* For a simple rectangle, we can just use composite(), for more
         620                 :          * rectangles, we have to set a clip region. The cost of rasterizing
         621                 :          * trapezoids is pretty high for most backends currently, so it's
         622                 :          * worthwhile even if a region is needed.
         623                 :          *
         624                 :          * If we have a clip surface, we set it as the mask; this only works
         625                 :          * for bounded operators other than SOURCE; for unbounded operators,
         626                 :          * clip and mask cannot be interchanged. For SOURCE, the operator
         627                 :          * as implemented by the backends is different in its handling
         628                 :          * of the mask then what we want.
         629                 :          *
         630                 :          * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
         631                 :          * more than rectangle and the destination doesn't support clip
         632                 :          * regions. In that case, we fall through.
         633                 :          */
         634               0 :         status = _composite_trap_region (clip, src, op, dst,
         635                 :                                          trap_region, extents);
         636                 :     }
         637                 :
         638               0 :     if (has_region & HAS_CLEAR_REGION) {
         639               0 :         if (status == CAIRO_STATUS_SUCCESS) {
         640               0 :             status = _cairo_surface_fill_region (dst,
         641                 :                                                  CAIRO_OPERATOR_CLEAR,
         642                 :                                                  CAIRO_COLOR_TRANSPARENT,
         643                 :                                                  &clear_region);
         644                 :         }
         645               0 :         _cairo_region_fini (&clear_region);
         646                 :     }
         647                 :
         648               0 :     return status;
         649                 : }
         650                 :
         651                 : /* avoid using region code to re-validate boxes */
         652                 : static cairo_status_t
         653               0 : _fill_rectangles (cairo_surface_t *dst,
         654                 :                   cairo_operator_t op,
         655                 :                   const cairo_pattern_t *src,
         656                 :                   cairo_traps_t *traps,
         657                 :                   cairo_clip_t *clip)
         658                 : {
         659                 :     const cairo_color_t *color;
         660                 :     cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
         661               0 :     cairo_rectangle_int_t *rects = stack_rects;
         662                 :     cairo_status_t status;
         663                 :     int i;
         664                 :
         665               0 :     if (! traps->is_rectilinear || ! traps->maybe_region)
         666               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
         667                 :
         668                 :     /* XXX: convert clip region to geometric boxes? */
         669               0 :     if (clip != NULL)
         670               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
         671                 :
         672                 :     /* XXX: fallback for the region_subtract() operation */
         673               0 :     if (! _cairo_operator_bounded_by_mask (op))
         674               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
         675                 :
         676               0 :     if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR))
         677               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
         678                 :
         679               0 :     if (traps->has_intersections) {
         680               0 :         if (traps->is_rectangular) {
         681               0 :             status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
         682                 :         } else {
         683               0 :             status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
         684                 :         }
         685               0 :         if (unlikely (status))
         686               0 :             return status;
         687                 :     }
         688                 :
         689               0 :     for (i = 0; i < traps->num_traps; i++) {
         690               0 :         if (! _cairo_fixed_is_integer (traps->traps[i].top)          ||
         691               0 :             ! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
         692               0 :             ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
         693               0 :             ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
         694                 :         {
         695               0 :             traps->maybe_region = FALSE;
         696               0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
         697                 :         }
         698                 :     }
         699                 :
         700               0 :     if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
         701               0 :         rects = _cairo_malloc_ab (traps->num_traps,
         702                 :                                   sizeof (cairo_rectangle_int_t));
         703               0 :         if (unlikely (rects == NULL))
         704               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
         705                 :     }
         706                 :
         707               0 :     for (i = 0; i < traps->num_traps; i++) {
         708               0 :         int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
         709               0 :         int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
         710               0 :         int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
         711               0 :         int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
         712                 :
         713               0 :         rects[i].x = x1;
         714               0 :         rects[i].y = y1;
         715               0 :         rects[i].width = x2 - x1;
         716               0 :         rects[i].height = y2 - y1;
         717                 :     }
         718                 :
         719               0 :     if (op == CAIRO_OPERATOR_CLEAR)
         720               0 :         color = CAIRO_COLOR_TRANSPARENT;
         721                 :     else
         722               0 :         color = &((cairo_solid_pattern_t *)src)->color;
         723                 :
         724               0 :     status =  _cairo_surface_fill_rectangles (dst, op, color, rects, i);
         725                 :
         726               0 :     if (rects != stack_rects)
         727               0 :         free (rects);
         728                 :
         729               0 :     return status;
         730                 : }
         731                 :
         732                 : /* fast-path for very common composite of a single rectangle */
         733                 : static cairo_status_t
         734               0 : _composite_rectangle (cairo_surface_t *dst,
         735                 :                       cairo_operator_t op,
         736                 :                       const cairo_pattern_t *src,
         737                 :                       cairo_traps_t *traps,
         738                 :                       cairo_clip_t *clip)
         739                 : {
         740                 :     cairo_rectangle_int_t rect;
         741                 :
         742               0 :     if (clip != NULL)
         743               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
         744                 :
         745               0 :     if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region)
         746               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
         747                 :
         748               0 :     if (! _cairo_fixed_is_integer (traps->traps[0].top)          ||
         749               0 :         ! _cairo_fixed_is_integer (traps->traps[0].bottom)       ||
         750               0 :         ! _cairo_fixed_is_integer (traps->traps[0].left.p1.x)    ||
         751               0 :         ! _cairo_fixed_is_integer (traps->traps[0].right.p1.x))
         752                 :     {
         753               0 :         traps->maybe_region = FALSE;
         754               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
         755                 :     }
         756                 :
         757               0 :     rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x);
         758               0 :     rect.y = _cairo_fixed_integer_part (traps->traps[0].top);
         759               0 :     rect.width  = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x;
         760               0 :     rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y;
         761                 :
         762               0 :     return _cairo_surface_composite (op, src, NULL, dst,
         763                 :                                      rect.x, rect.y,
         764                 :                                      0, 0,
         765                 :                                      rect.x, rect.y,
         766               0 :                                      rect.width, rect.height,
         767                 :                                      NULL);
         768                 : }
         769                 :
         770                 : /* Warning: This call modifies the coordinates of traps */
         771                 : static cairo_status_t
         772               0 : _clip_and_composite_trapezoids (const cairo_pattern_t *src,
         773                 :                                 cairo_operator_t op,
         774                 :                                 cairo_surface_t *dst,
         775                 :                                 cairo_traps_t *traps,
         776                 :                                 cairo_antialias_t antialias,
         777                 :                                 cairo_clip_t *clip,
         778                 :                                 cairo_rectangle_int_t *extents)
         779                 : {
         780                 :     cairo_composite_traps_info_t traps_info;
         781               0 :     cairo_region_t *clip_region = NULL;
         782               0 :     cairo_bool_t clip_surface = FALSE;
         783                 :     cairo_status_t status;
         784                 :
         785               0 :     if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op))
         786               0 :         return CAIRO_STATUS_SUCCESS;
         787                 :
         788               0 :     if (clip != NULL) {
         789               0 :         status = _cairo_clip_get_region (clip, &clip_region);
         790               0 :         if (unlikely (_cairo_status_is_error (status)))
         791               0 :             return status;
         792               0 :         if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
         793               0 :             return CAIRO_STATUS_SUCCESS;
         794                 :
         795               0 :         clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
         796                 :     }
         797                 :
         798                 :     /* Use a fast path if the trapezoids consist of a simple region,
         799                 :      * but we can only do this if we do not have a clip surface, or can
         800                 :      * substitute the mask with the clip.
         801                 :      */
         802               0 :     if (! clip_surface ||
         803               0 :         (_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE))
         804                 :     {
         805               0 :         cairo_region_t *trap_region = NULL;
         806                 :
         807               0 :         if (_cairo_operator_bounded_by_source (op)) {
         808               0 :             status = _fill_rectangles (dst, op, src, traps, clip);
         809               0 :             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
         810               0 :                 return status;
         811                 :
         812               0 :             status = _composite_rectangle (dst, op, src, traps, clip);
         813               0 :             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
         814               0 :                 return status;
         815                 :         }
         816                 :
         817               0 :         status = _cairo_traps_extract_region (traps, &trap_region);
         818               0 :         if (unlikely (_cairo_status_is_error (status)))
         819               0 :             return status;
         820                 :
         821               0 :         if (trap_region != NULL) {
         822               0 :             status = cairo_region_intersect_rectangle (trap_region, extents);
         823               0 :             if (unlikely (status)) {
         824               0 :                 cairo_region_destroy (trap_region);
         825               0 :                 return status;
         826                 :             }
         827                 :
         828               0 :             if (clip_region != NULL) {
         829               0 :                 status = cairo_region_intersect (trap_region, clip_region);
         830               0 :                 if (unlikely (status)) {
         831               0 :                     cairo_region_destroy (trap_region);
         832               0 :                     return status;
         833                 :                 }
         834                 :             }
         835                 :
         836               0 :             if (_cairo_operator_bounded_by_mask (op)) {
         837                 :                 cairo_rectangle_int_t trap_extents;
         838                 :
         839               0 :                 cairo_region_get_extents (trap_region, &trap_extents);
         840               0 :                 if (! _cairo_rectangle_intersect (extents, &trap_extents)) {
         841               0 :                     cairo_region_destroy (trap_region);
         842               0 :                     return CAIRO_STATUS_SUCCESS;
         843                 :                 }
         844                 :             }
         845                 :
         846               0 :             status = _clip_and_composite_region (src, op, dst,
         847                 :                                                  trap_region,
         848                 :                                                  clip_surface ? clip : NULL,
         849                 :                                                  extents);
         850               0 :             cairo_region_destroy (trap_region);
         851                 :
         852               0 :             if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
         853               0 :                 return status;
         854                 :         }
         855                 :     }
         856                 :
         857                 :     /* No fast path, exclude self-intersections and clip trapezoids. */
         858               0 :     if (traps->has_intersections) {
         859               0 :         if (traps->is_rectangular)
         860               0 :             status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
         861               0 :         else if (traps->is_rectilinear)
         862               0 :             status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
         863                 :         else
         864               0 :             status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
         865               0 :         if (unlikely (status))
         866               0 :             return status;
         867                 :     }
         868                 :
         869                 :     /* Otherwise render the trapezoids to a mask and composite in the usual
         870                 :      * fashion.
         871                 :      */
         872               0 :     traps_info.traps = traps;
         873               0 :     traps_info.antialias = antialias;
         874                 :
         875               0 :     return _clip_and_composite (clip, op, src,
         876                 :                                 _composite_traps_draw_func,
         877                 :                                 &traps_info, dst, extents);
         878                 : }
         879                 :
         880                 : cairo_status_t
         881               0 : _cairo_surface_fallback_paint (cairo_surface_t          *surface,
         882                 :                                cairo_operator_t          op,
         883                 :                                const cairo_pattern_t    *source,
         884                 :                                cairo_clip_t             *clip)
         885                 : {
         886                 :     cairo_composite_rectangles_t extents;
         887                 :     cairo_rectangle_int_t rect;
         888               0 :     cairo_clip_path_t *clip_path = clip ? clip->path : NULL;
         889               0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
         890                 :     cairo_boxes_t  boxes;
         891               0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
         892                 :     cairo_status_t status;
         893                 :     cairo_traps_t traps;
         894                 :
         895               0 :     if (!_cairo_surface_get_extents (surface, &rect))
         896               0 :         ASSERT_NOT_REACHED;
         897                 :
         898               0 :     status = _cairo_composite_rectangles_init_for_paint (&extents,
         899                 :                                                          &rect,
         900                 :                                                          op, source,
         901                 :                                                          clip);
         902               0 :     if (unlikely (status))
         903               0 :         return status;
         904                 :
         905               0 :     if (_cairo_clip_contains_extents (clip, &extents))
         906               0 :         clip = NULL;
         907                 :
         908               0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
         909               0 :     if (unlikely (status))
         910               0 :         return status;
         911                 :
         912                 :     /* If the clip cannot be reduced to a set of boxes, we will need to
         913                 :      * use a clipmask. Paint is special as it is the only operation that
         914                 :      * does not implicitly use a mask, so we may be able to reduce this
         915                 :      * operation to a fill...
         916                 :      */
         917               0 :     if (clip != NULL && clip_path->prev == NULL &&
         918               0 :         _cairo_operator_bounded_by_mask (op))
         919                 :     {
         920               0 :         return _cairo_surface_fill (surface, op, source,
         921                 :                                     &clip_path->path,
         922                 :                                     clip_path->fill_rule,
         923                 :                                     clip_path->tolerance,
         924                 :                                     clip_path->antialias,
         925                 :                                     NULL);
         926                 :     }
         927                 :
         928                 :     /* meh, surface-fallback is dying anyway... */
         929               0 :     _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
         930               0 :     status = _cairo_traps_init_boxes (&traps, &boxes);
         931               0 :     if (unlikely (status))
         932               0 :         goto CLEANUP_BOXES;
         933                 :
         934               0 :     status = _clip_and_composite_trapezoids (source, op, surface,
         935                 :                                              &traps, CAIRO_ANTIALIAS_DEFAULT,
         936                 :                                              clip,
         937               0 :                                              extents.is_bounded ? &extents.bounded : &extents.unbounded);
         938               0 :     _cairo_traps_fini (&traps);
         939                 :
         940                 : CLEANUP_BOXES:
         941               0 :     if (clip_boxes != boxes_stack)
         942               0 :         free (clip_boxes);
         943                 :
         944               0 :     return status;
         945                 : }
         946                 :
         947                 : static cairo_status_t
         948               0 : _cairo_surface_mask_draw_func (void                        *closure,
         949                 :                                cairo_operator_t             op,
         950                 :                                const cairo_pattern_t       *src,
         951                 :                                cairo_surface_t             *dst,
         952                 :                                int                          dst_x,
         953                 :                                int                          dst_y,
         954                 :                                const cairo_rectangle_int_t *extents,
         955                 :                                cairo_region_t              *clip_region)
         956                 : {
         957               0 :     cairo_pattern_t *mask = closure;
         958                 :     cairo_status_t status;
         959               0 :     cairo_region_t *extents_region = NULL;
         960                 :
         961               0 :     if (clip_region == NULL &&
         962               0 :         !_cairo_operator_bounded_by_source (op)) {
         963               0 :         extents_region = cairo_region_create_rectangle (extents);
         964               0 :         if (unlikely (extents_region->status))
         965               0 :             return extents_region->status;
         966               0 :         cairo_region_translate (extents_region, -dst_x, -dst_y);
         967               0 :         clip_region = extents_region;
         968                 :     }
         969                 :
         970               0 :     if (src) {
         971               0 :         status = _cairo_surface_composite (op,
         972                 :                                            src, mask, dst,
         973                 :                                            extents->x,         extents->y,
         974                 :                                            extents->x,         extents->y,
         975               0 :                                            extents->x - dst_x, extents->y - dst_y,
         976               0 :                                            extents->width,     extents->height,
         977                 :                                            clip_region);
         978                 :     } else {
         979               0 :         status = _cairo_surface_composite (op,
         980                 :                                            mask, NULL, dst,
         981                 :                                            extents->x,         extents->y,
         982                 :                                            0,                  0, /* unused */
         983               0 :                                            extents->x - dst_x, extents->y - dst_y,
         984               0 :                                            extents->width,     extents->height,
         985                 :                                            clip_region);
         986                 :     }
         987                 :
         988               0 :     if (extents_region)
         989               0 :         cairo_region_destroy (extents_region);
         990                 :
         991               0 :     return status;
         992                 : }
         993                 :
         994                 : cairo_status_t
         995               0 : _cairo_surface_fallback_mask (cairo_surface_t           *surface,
         996                 :                               cairo_operator_t           op,
         997                 :                               const cairo_pattern_t     *source,
         998                 :                               const cairo_pattern_t     *mask,
         999                 :                               cairo_clip_t              *clip)
        1000                 : {
        1001                 :     cairo_composite_rectangles_t extents;
        1002                 :     cairo_rectangle_int_t rect;
        1003                 :     cairo_status_t status;
        1004                 :
        1005               0 :     if (!_cairo_surface_get_extents (surface, &rect))
        1006               0 :         ASSERT_NOT_REACHED;
        1007                 :
        1008               0 :     status = _cairo_composite_rectangles_init_for_mask (&extents,
        1009                 :                                                         &rect,
        1010                 :                                                         op, source, mask, clip);
        1011               0 :     if (unlikely (status))
        1012               0 :         return status;
        1013                 :
        1014               0 :     if (_cairo_clip_contains_extents (clip, &extents))
        1015               0 :         clip = NULL;
        1016                 :
        1017               0 :     if (clip != NULL && extents.is_bounded) {
        1018               0 :         status = _cairo_clip_rectangle (clip, &extents.bounded);
        1019               0 :         if (unlikely (status))
        1020               0 :             return status;
        1021                 :     }
        1022                 :
        1023               0 :     return _clip_and_composite (clip, op, source,
        1024                 :                                 _cairo_surface_mask_draw_func,
        1025                 :                                 (void *) mask,
        1026                 :                                 surface,
        1027               0 :                                 extents.is_bounded ? &extents.bounded : &extents.unbounded);
        1028                 : }
        1029                 :
        1030                 : cairo_status_t
        1031               0 : _cairo_surface_fallback_stroke (cairo_surface_t         *surface,
        1032                 :                                 cairo_operator_t         op,
        1033                 :                                 const cairo_pattern_t   *source,
        1034                 :                                 cairo_path_fixed_t      *path,
        1035                 :                                 const cairo_stroke_style_t      *stroke_style,
        1036                 :                                 const cairo_matrix_t            *ctm,
        1037                 :                                 const cairo_matrix_t            *ctm_inverse,
        1038                 :                                 double                   tolerance,
        1039                 :                                 cairo_antialias_t        antialias,
        1040                 :                                 cairo_clip_t            *clip)
        1041                 : {
        1042                 :     cairo_polygon_t polygon;
        1043                 :     cairo_traps_t traps;
        1044               0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
        1045               0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
        1046                 :     cairo_composite_rectangles_t extents;
        1047                 :     cairo_rectangle_int_t rect;
        1048                 :     cairo_status_t status;
        1049                 :
        1050               0 :     if (!_cairo_surface_get_extents (surface, &rect))
        1051               0 :         ASSERT_NOT_REACHED;
        1052                 :
        1053               0 :     status = _cairo_composite_rectangles_init_for_stroke (&extents,
        1054                 :                                                           &rect,
        1055                 :                                                           op, source,
        1056                 :                                                           path, stroke_style, ctm,
        1057                 :                                                           clip);
        1058               0 :     if (unlikely (status))
        1059               0 :         return status;
        1060                 :
        1061               0 :     if (_cairo_clip_contains_extents (clip, &extents))
        1062               0 :         clip = NULL;
        1063                 :
        1064               0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
        1065               0 :     if (unlikely (status))
        1066               0 :         return status;
        1067                 :
        1068               0 :     _cairo_polygon_init (&polygon);
        1069               0 :     _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
        1070                 :
        1071               0 :     _cairo_traps_init (&traps);
        1072               0 :     _cairo_traps_limit (&traps, clip_boxes, num_boxes);
        1073                 :
        1074               0 :     if (path->is_rectilinear) {
        1075               0 :         status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
        1076                 :                                                                 stroke_style,
        1077                 :                                                                 ctm,
        1078                 :                                                                 &traps);
        1079               0 :         if (likely (status == CAIRO_STATUS_SUCCESS))
        1080               0 :             goto DO_TRAPS;
        1081                 :
        1082               0 :         if (_cairo_status_is_error (status))
        1083               0 :             goto CLEANUP;
        1084                 :     }
        1085                 :
        1086               0 :     status = _cairo_path_fixed_stroke_to_polygon (path,
        1087                 :                                                   stroke_style,
        1088                 :                                                   ctm, ctm_inverse,
        1089                 :                                                   tolerance,
        1090                 :                                                   &polygon);
        1091               0 :     if (unlikely (status))
        1092               0 :         goto CLEANUP;
        1093                 :
        1094               0 :     if (polygon.num_edges == 0)
        1095               0 :         goto DO_TRAPS;
        1096                 :
        1097               0 :     if (_cairo_operator_bounded_by_mask (op)) {
        1098               0 :         _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
        1099               0 :         if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
        1100               0 :             goto CLEANUP;
        1101                 :     }
        1102                 :
        1103                 :     /* Fall back to trapezoid fills. */
        1104               0 :     status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
        1105                 :                                                         &polygon,
        1106                 :                                                         CAIRO_FILL_RULE_WINDING);
        1107               0 :     if (unlikely (status))
        1108               0 :         goto CLEANUP;
        1109                 :
        1110                 :   DO_TRAPS:
        1111               0 :     status = _clip_and_composite_trapezoids (source, op, surface,
        1112                 :                                              &traps, antialias,
        1113                 :                                              clip,
        1114               0 :                                              extents.is_bounded ? &extents.bounded : &extents.unbounded);
        1115                 :   CLEANUP:
        1116               0 :     _cairo_traps_fini (&traps);
        1117               0 :     _cairo_polygon_fini (&polygon);
        1118               0 :     if (clip_boxes != boxes_stack)
        1119               0 :         free (clip_boxes);
        1120                 :
        1121               0 :     return status;
        1122                 : }
        1123                 :
        1124                 : cairo_status_t
        1125               0 : _cairo_surface_fallback_fill (cairo_surface_t           *surface,
        1126                 :                               cairo_operator_t           op,
        1127                 :                               const cairo_pattern_t     *source,
        1128                 :                               cairo_path_fixed_t        *path,
        1129                 :                               cairo_fill_rule_t          fill_rule,
        1130                 :                               double                     tolerance,
        1131                 :                               cairo_antialias_t          antialias,
        1132                 :                               cairo_clip_t              *clip)
        1133                 : {
        1134                 :     cairo_polygon_t polygon;
        1135                 :     cairo_traps_t traps;
        1136               0 :     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
        1137               0 :     int num_boxes = ARRAY_LENGTH (boxes_stack);
        1138                 :     cairo_bool_t is_rectilinear;
        1139                 :     cairo_composite_rectangles_t extents;
        1140                 :     cairo_rectangle_int_t rect;
        1141                 :     cairo_status_t status;
        1142                 :
        1143               0 :     if (!_cairo_surface_get_extents (surface, &rect))
        1144               0 :         ASSERT_NOT_REACHED;
        1145                 :
        1146               0 :     status = _cairo_composite_rectangles_init_for_fill (&extents,
        1147                 :                                                         &rect,
        1148                 :                                                         op, source, path,
        1149                 :                                                         clip);
        1150               0 :     if (unlikely (status))
        1151               0 :         return status;
        1152                 :
        1153               0 :     if (_cairo_clip_contains_extents (clip, &extents))
        1154               0 :         clip = NULL;
        1155                 :
        1156               0 :     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
        1157               0 :     if (unlikely (status))
        1158               0 :         return status;
        1159                 :
        1160               0 :     _cairo_traps_init (&traps);
        1161               0 :     _cairo_traps_limit (&traps, clip_boxes, num_boxes);
        1162                 :
        1163               0 :     _cairo_polygon_init (&polygon);
        1164               0 :     _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
        1165                 :
        1166               0 :     if (path->is_empty_fill)
        1167               0 :         goto DO_TRAPS;
        1168                 :
        1169               0 :     is_rectilinear = _cairo_path_fixed_is_rectilinear_fill (path);
        1170               0 :     if (is_rectilinear) {
        1171               0 :         status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
        1172                 :                                                               fill_rule,
        1173                 :                                                               &traps);
        1174               0 :         if (likely (status == CAIRO_STATUS_SUCCESS))
        1175               0 :             goto DO_TRAPS;
        1176                 :
        1177               0 :         if (_cairo_status_is_error (status))
        1178               0 :             goto CLEANUP;
        1179                 :     }
        1180                 :
        1181               0 :     status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
        1182               0 :     if (unlikely (status))
        1183               0 :         goto CLEANUP;
        1184                 :
        1185               0 :     if (polygon.num_edges == 0)
        1186               0 :         goto DO_TRAPS;
        1187                 :
        1188               0 :     if (_cairo_operator_bounded_by_mask (op)) {
        1189               0 :         _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
        1190               0 :         if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
        1191               0 :             goto CLEANUP;
        1192                 :     }
        1193                 :
        1194               0 :     if (is_rectilinear) {
        1195               0 :         status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
        1196                 :                                                                         &polygon,
        1197                 :                                                                         fill_rule);
        1198               0 :         if (likely (status == CAIRO_STATUS_SUCCESS))
        1199               0 :             goto DO_TRAPS;
        1200                 :
        1201               0 :         if (unlikely (_cairo_status_is_error (status)))
        1202               0 :             goto CLEANUP;
        1203                 :     }
        1204                 :
        1205                 :     /* Fall back to trapezoid fills. */
        1206               0 :     status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
        1207                 :                                                         &polygon,
        1208                 :                                                         fill_rule);
        1209               0 :     if (unlikely (status))
        1210               0 :         goto CLEANUP;
        1211                 :
        1212                 :   DO_TRAPS:
        1213               0 :     status = _clip_and_composite_trapezoids (source, op, surface,
        1214                 :                                              &traps, antialias,
        1215                 :                                              clip,
        1216               0 :                                              extents.is_bounded ? &extents.bounded : &extents.unbounded);
        1217                 :   CLEANUP:
        1218               0 :     _cairo_traps_fini (&traps);
        1219               0 :     _cairo_polygon_fini (&polygon);
        1220               0 :     if (clip_boxes != boxes_stack)
        1221               0 :         free (clip_boxes);
        1222                 :
        1223               0 :     return status;
        1224                 : }
        1225                 :
        1226                 : typedef struct {
        1227                 :     cairo_scaled_font_t *font;
        1228                 :     cairo_glyph_t *glyphs;
        1229                 :     int num_glyphs;
        1230                 : } cairo_show_glyphs_info_t;
        1231                 :
        1232                 : static cairo_status_t
        1233               0 : _cairo_surface_old_show_glyphs_draw_func (void                          *closure,
        1234                 :                                           cairo_operator_t               op,
        1235                 :                                           const cairo_pattern_t         *src,
        1236                 :                                           cairo_surface_t               *dst,
        1237                 :                                           int                            dst_x,
        1238                 :                                           int                            dst_y,
        1239                 :                                           const cairo_rectangle_int_t   *extents,
        1240                 :                                           cairo_region_t                *clip_region)
        1241                 : {
        1242               0 :     cairo_show_glyphs_info_t *glyph_info = closure;
        1243                 :     cairo_status_t status;
        1244               0 :     cairo_region_t *extents_region = NULL;
        1245                 :
        1246               0 :     if (clip_region == NULL &&
        1247               0 :         !_cairo_operator_bounded_by_source (op)) {
        1248               0 :         extents_region = cairo_region_create_rectangle (extents);
        1249               0 :         if (unlikely (extents_region->status))
        1250               0 :             return extents_region->status;
        1251               0 :         cairo_region_translate (extents_region, -dst_x, -dst_y);
        1252               0 :         clip_region = extents_region;
        1253                 :     }
        1254                 :
        1255                 :     /* Modifying the glyph array is fine because we know that this function
        1256                 :      * will be called only once, and we've already made a copy of the
        1257                 :      * glyphs in the wrapper.
        1258                 :      */
        1259               0 :     if (dst_x != 0 || dst_y != 0) {
        1260                 :         int i;
        1261                 :
        1262               0 :         for (i = 0; i < glyph_info->num_glyphs; ++i) {
        1263               0 :             ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
        1264               0 :             ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
        1265                 :         }
        1266                 :     }
        1267                 :
        1268               0 :     status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
        1269                 :                                              dst,
        1270                 :                                              extents->x, extents->y,
        1271               0 :                                              extents->x - dst_x,
        1272               0 :                                              extents->y - dst_y,
        1273               0 :                                              extents->width,
        1274               0 :                                              extents->height,
        1275                 :                                              glyph_info->glyphs,
        1276                 :                                              glyph_info->num_glyphs,
        1277                 :                                              clip_region);
        1278                 :
        1279               0 :     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
        1280               0 :         status = _cairo_scaled_font_show_glyphs (glyph_info->font,
        1281                 :                                                  op,
        1282                 :                                                  src, dst,
        1283                 :                                                  extents->x,         extents->y,
        1284               0 :                                                  extents->x - dst_x,
        1285               0 :                                                  extents->y - dst_y,
        1286               0 :                                                  extents->width,     extents->height,
        1287                 :                                                  glyph_info->glyphs,
        1288                 :                                                  glyph_info->num_glyphs,
        1289                 :                                                  clip_region);
        1290                 :     }
        1291                 :
        1292               0 :     if (extents_region)
        1293               0 :         cairo_region_destroy (extents_region);
        1294                 :
        1295               0 :     return status;
        1296                 : }
        1297                 :
        1298                 : cairo_status_t
        1299               0 : _cairo_surface_fallback_show_glyphs (cairo_surface_t            *surface,
        1300                 :                                      cairo_operator_t            op,
        1301                 :                                      const cairo_pattern_t      *source,
        1302                 :                                      cairo_glyph_t              *glyphs,
        1303                 :                                      int                         num_glyphs,
        1304                 :                                      cairo_scaled_font_t        *scaled_font,
        1305                 :                                      cairo_clip_t               *clip)
        1306                 : {
        1307                 :     cairo_show_glyphs_info_t glyph_info;
        1308                 :     cairo_composite_rectangles_t extents;
        1309                 :     cairo_rectangle_int_t rect;
        1310                 :     cairo_status_t status;
        1311                 :
        1312               0 :     if (!_cairo_surface_get_extents (surface, &rect))
        1313               0 :         ASSERT_NOT_REACHED;
        1314                 :
        1315               0 :     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
        1316                 :                                                           &rect,
        1317                 :                                                           op, source,
        1318                 :                                                           scaled_font,
        1319                 :                                                           glyphs, num_glyphs,
        1320                 :                                                           clip,
        1321                 :                                                           NULL);
        1322               0 :     if (unlikely (status))
        1323               0 :         return status;
        1324                 :
        1325               0 :     if (_cairo_clip_contains_rectangle (clip, &extents.mask))
        1326               0 :         clip = NULL;
        1327                 :
        1328               0 :     if (clip != NULL && extents.is_bounded) {
        1329               0 :         status = _cairo_clip_rectangle (clip, &extents.bounded);
        1330               0 :         if (unlikely (status))
        1331               0 :             return status;
        1332                 :     }
        1333                 :
        1334               0 :     glyph_info.font = scaled_font;
        1335               0 :     glyph_info.glyphs = glyphs;
        1336               0 :     glyph_info.num_glyphs = num_glyphs;
        1337                 :
        1338               0 :     return _clip_and_composite (clip, op, source,
        1339                 :                                 _cairo_surface_old_show_glyphs_draw_func,
        1340                 :                                 &glyph_info,
        1341                 :                                 surface,
        1342               0 :                                 extents.is_bounded ? &extents.bounded : &extents.unbounded);
        1343                 : }
        1344                 :
        1345                 : cairo_surface_t *
        1346               0 : _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
        1347                 : {
        1348                 :     cairo_surface_t *snapshot;
        1349                 :     cairo_status_t status;
        1350                 :     cairo_format_t format;
        1351                 :     cairo_surface_pattern_t pattern;
        1352                 :     cairo_image_surface_t *image;
        1353                 :     void *image_extra;
        1354                 :
        1355               0 :     status = _cairo_surface_acquire_source_image (surface,
        1356                 :                                                   &image, &image_extra);
        1357               0 :     if (unlikely (status))
        1358               0 :         return _cairo_surface_create_in_error (status);
        1359                 :
        1360               0 :     format = image->format;
        1361               0 :     if (format == CAIRO_FORMAT_INVALID) {
        1362                 :         /* Non-standard images formats can be generated when retrieving
        1363                 :          * images from unusual xservers, for example.
        1364                 :          */
        1365               0 :         format = _cairo_format_from_content (image->base.content);
        1366                 :     }
        1367               0 :     snapshot = cairo_image_surface_create (format,
        1368               0 :                                            image->width,
        1369               0 :                                            image->height);
        1370               0 :     if (cairo_surface_status (snapshot)) {
        1371               0 :         _cairo_surface_release_source_image (surface, image, image_extra);
        1372               0 :         return snapshot;
        1373                 :     }
        1374                 :
        1375               0 :     _cairo_pattern_init_for_surface (&pattern, &image->base);
        1376               0 :     status = _cairo_surface_paint (snapshot,
        1377                 :                                    CAIRO_OPERATOR_SOURCE,
        1378                 :                                    &pattern.base,
        1379                 :                                    NULL);
        1380               0 :     _cairo_pattern_fini (&pattern.base);
        1381               0 :     _cairo_surface_release_source_image (surface, image, image_extra);
        1382               0 :     if (unlikely (status)) {
        1383               0 :         cairo_surface_destroy (snapshot);
        1384               0 :         return _cairo_surface_create_in_error (status);
        1385                 :     }
        1386                 :
        1387               0 :     return snapshot;
        1388                 : }
        1389                 :
        1390                 : cairo_status_t
        1391               0 : _cairo_surface_fallback_composite (cairo_operator_t              op,
        1392                 :                                    const cairo_pattern_t        *src,
        1393                 :                                    const cairo_pattern_t        *mask,
        1394                 :                                    cairo_surface_t              *dst,
        1395                 :                                    int                           src_x,
        1396                 :                                    int                           src_y,
        1397                 :                                    int                           mask_x,
        1398                 :                                    int                           mask_y,
        1399                 :                                    int                           dst_x,
        1400                 :                                    int                           dst_y,
        1401                 :                                    unsigned int                  width,
        1402                 :                                    unsigned int                  height,
        1403                 :                                    cairo_region_t               *clip_region)
        1404                 : {
        1405                 :     fallback_state_t state;
        1406               0 :     cairo_region_t *fallback_region = NULL;
        1407                 :     cairo_status_t status;
        1408                 :
        1409               0 :     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
        1410               0 :     if (unlikely (status))
        1411               0 :         return status;
        1412                 :
        1413                 :     /* We know this will never fail with the image backend; but
        1414                 :      * instead of calling into it directly, we call
        1415                 :      * _cairo_surface_composite so that we get the correct device
        1416                 :      * offset handling.
        1417                 :      */
        1418                 :
        1419               0 :     if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) {
        1420               0 :         fallback_region = cairo_region_copy (clip_region);
        1421               0 :         status = fallback_region->status;
        1422               0 :         if (unlikely (status))
        1423               0 :             goto FAIL;
        1424                 :
        1425               0 :         cairo_region_translate (fallback_region,
        1426               0 :                                 -state.image_rect.x,
        1427               0 :                                 -state.image_rect.y);
        1428               0 :         clip_region = fallback_region;
        1429                 :     }
        1430                 :
        1431               0 :     status = _cairo_surface_composite (op, src, mask,
        1432               0 :                                        &state.image->base,
        1433                 :                                        src_x, src_y, mask_x, mask_y,
        1434               0 :                                        dst_x - state.image_rect.x,
        1435               0 :                                        dst_y - state.image_rect.y,
        1436                 :                                        width, height,
        1437                 :                                        clip_region);
        1438                 :   FAIL:
        1439               0 :     if (fallback_region != NULL)
        1440               0 :         cairo_region_destroy (fallback_region);
        1441               0 :     _fallback_fini (&state);
        1442                 :
        1443               0 :     return status;
        1444                 : }
        1445                 :
        1446                 : cairo_status_t
        1447               0 : _cairo_surface_fallback_fill_rectangles (cairo_surface_t         *surface,
        1448                 :                                          cairo_operator_t         op,
        1449                 :                                          const cairo_color_t     *color,
        1450                 :                                          cairo_rectangle_int_t   *rects,
        1451                 :                                          int                      num_rects)
        1452                 : {
        1453                 :     fallback_state_t state;
        1454               0 :     cairo_rectangle_int_t *offset_rects = NULL;
        1455                 :     cairo_status_t status;
        1456                 :     int x1, y1, x2, y2;
        1457                 :     int i;
        1458                 :
        1459               0 :     assert (surface->snapshot_of == NULL);
        1460                 :
        1461               0 :     if (num_rects <= 0)
        1462               0 :         return CAIRO_STATUS_SUCCESS;
        1463                 :
        1464                 :     /* Compute the bounds of the rectangles, so that we know what area of the
        1465                 :      * destination surface to fetch
        1466                 :      */
        1467               0 :     x1 = rects[0].x;
        1468               0 :     y1 = rects[0].y;
        1469               0 :     x2 = rects[0].x + rects[0].width;
        1470               0 :     y2 = rects[0].y + rects[0].height;
        1471                 :
        1472               0 :     for (i = 1; i < num_rects; i++) {
        1473               0 :         if (rects[i].x < x1)
        1474               0 :             x1 = rects[i].x;
        1475               0 :         if (rects[i].y < y1)
        1476               0 :             y1 = rects[i].y;
        1477                 :
        1478               0 :         if ((int) (rects[i].x + rects[i].width) > x2)
        1479               0 :             x2 = rects[i].x + rects[i].width;
        1480               0 :         if ((int) (rects[i].y + rects[i].height) > y2)
        1481               0 :             y2 = rects[i].y + rects[i].height;
        1482                 :     }
        1483                 :
        1484               0 :     status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
        1485               0 :     if (unlikely (status))
        1486               0 :         return status;
        1487                 :
        1488                 :     /* If the fetched image isn't at 0,0, we need to offset the rectangles */
        1489                 :
        1490               0 :     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
        1491               0 :         offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
        1492               0 :         if (unlikely (offset_rects == NULL)) {
        1493               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        1494               0 :             goto DONE;
        1495                 :         }
        1496                 :
        1497               0 :         for (i = 0; i < num_rects; i++) {
        1498               0 :             offset_rects[i].x = rects[i].x - state.image_rect.x;
        1499               0 :             offset_rects[i].y = rects[i].y - state.image_rect.y;
        1500               0 :             offset_rects[i].width = rects[i].width;
        1501               0 :             offset_rects[i].height = rects[i].height;
        1502                 :         }
        1503                 :
        1504               0 :         rects = offset_rects;
        1505                 :     }
        1506                 :
        1507               0 :     status = _cairo_surface_fill_rectangles (&state.image->base,
        1508                 :                                              op, color,
        1509                 :                                              rects, num_rects);
        1510                 :
        1511               0 :     free (offset_rects);
        1512                 :
        1513                 :  DONE:
        1514               0 :     _fallback_fini (&state);
        1515                 :
        1516               0 :     return status;
        1517                 : }
        1518                 :
        1519                 : cairo_status_t
        1520               0 : _cairo_surface_fallback_composite_trapezoids (cairo_operator_t          op,
        1521                 :                                               const cairo_pattern_t    *pattern,
        1522                 :                                               cairo_surface_t          *dst,
        1523                 :                                               cairo_antialias_t         antialias,
        1524                 :                                               int                       src_x,
        1525                 :                                               int                       src_y,
        1526                 :                                               int                       dst_x,
        1527                 :                                               int                       dst_y,
        1528                 :                                               unsigned int              width,
        1529                 :                                               unsigned int              height,
        1530                 :                                               cairo_trapezoid_t        *traps,
        1531                 :                                               int                       num_traps,
        1532                 :                                               cairo_region_t            *clip_region)
        1533                 : {
        1534                 :     fallback_state_t state;
        1535               0 :     cairo_region_t *fallback_region = NULL;
        1536               0 :     cairo_trapezoid_t *offset_traps = NULL;
        1537                 :     cairo_status_t status;
        1538                 :
        1539               0 :     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
        1540               0 :     if (unlikely (status))
        1541               0 :         return status;
        1542                 :
        1543                 :     /* If the destination image isn't at 0,0, we need to offset the trapezoids */
        1544                 :
        1545               0 :     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
        1546               0 :         offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
        1547               0 :         if (offset_traps == NULL) {
        1548               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
        1549               0 :             goto FAIL;
        1550                 :         }
        1551                 :
        1552               0 :         _cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
        1553               0 :                                                     - state.image_rect.x, - state.image_rect.y,
        1554                 :                                                     1.0, 1.0);
        1555               0 :         traps = offset_traps;
        1556                 :
        1557                 :         /* similarly we need to adjust the region */
        1558               0 :         if (clip_region != NULL) {
        1559               0 :             fallback_region = cairo_region_copy (clip_region);
        1560               0 :             status = fallback_region->status;
        1561               0 :             if (unlikely (status))
        1562               0 :                 goto FAIL;
        1563                 :
        1564               0 :             cairo_region_translate (fallback_region,
        1565               0 :                                     -state.image_rect.x,
        1566               0 :                                     -state.image_rect.y);
        1567               0 :             clip_region = fallback_region;
        1568                 :         }
        1569                 :     }
        1570                 :
        1571               0 :     status = _cairo_surface_composite_trapezoids (op, pattern,
        1572               0 :                                                   &state.image->base,
        1573                 :                                                   antialias,
        1574                 :                                                   src_x, src_y,
        1575               0 :                                                   dst_x - state.image_rect.x,
        1576               0 :                                                   dst_y - state.image_rect.y,
        1577                 :                                                   width, height,
        1578                 :                                                   traps, num_traps,
        1579                 :                                                   clip_region);
        1580                 :  FAIL:
        1581               0 :     if (offset_traps != NULL)
        1582               0 :         free (offset_traps);
        1583                 :
        1584               0 :     if (fallback_region != NULL)
        1585               0 :         cairo_region_destroy (fallback_region);
        1586                 :
        1587               0 :     _fallback_fini (&state);
        1588                 :
        1589               0 :     return status;
        1590                 : }
        1591                 :
        1592                 : cairo_status_t
        1593               0 : _cairo_surface_fallback_clone_similar (cairo_surface_t  *surface,
        1594                 :                                        cairo_surface_t  *src,
        1595                 :                                        int               src_x,
        1596                 :                                        int               src_y,
        1597                 :                                        int               width,
        1598                 :                                        int               height,
        1599                 :                                        int              *clone_offset_x,
        1600                 :                                        int              *clone_offset_y,
        1601                 :                                        cairo_surface_t **clone_out)
        1602                 : {
        1603                 :     cairo_surface_t *new_surface;
        1604                 :     cairo_surface_pattern_t pattern;
        1605                 :     cairo_status_t status;
        1606                 :
        1607               0 :     new_surface = _cairo_surface_create_similar_scratch (surface,
        1608                 :                                                          src->content,
        1609                 :                                                          width, height);
        1610               0 :     if (new_surface == NULL)
        1611               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
        1612               0 :     if (unlikely (new_surface->status))
        1613               0 :         return new_surface->status;
        1614                 :
        1615                 :     /* We have to copy these here, so that the coordinate spaces are correct */
        1616               0 :     new_surface->device_transform = src->device_transform;
        1617               0 :     new_surface->device_transform_inverse = src->device_transform_inverse;
        1618                 :
        1619               0 :     _cairo_pattern_init_for_surface (&pattern, src);
        1620               0 :     cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
        1621               0 :     pattern.base.filter = CAIRO_FILTER_NEAREST;
        1622                 :
        1623               0 :     status = _cairo_surface_paint (new_surface,
        1624                 :                                    CAIRO_OPERATOR_SOURCE,
        1625                 :                                    &pattern.base,
        1626                 :                                    NULL);
        1627               0 :     _cairo_pattern_fini (&pattern.base);
        1628                 :
        1629               0 :     if (unlikely (status)) {
        1630               0 :         cairo_surface_destroy (new_surface);
        1631               0 :         return status;
        1632                 :     }
        1633                 :
        1634               0 :     *clone_offset_x = src_x;
        1635               0 :     *clone_offset_y = src_y;
        1636               0 :     *clone_out = new_surface;
        1637               0 :     return CAIRO_STATUS_SUCCESS;
        1638                 : }

Generated by: LCOV version 1.7