LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-surface-fallback.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 638 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 26 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
       2             : /* cairo - a vector graphics library with display and print output
       3             :  *
       4             :  * Copyright © 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.13