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

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

Generated by: LCOV version 1.7