LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-surface.c (source / functions) Found Hit Coverage
Test: app.info Lines: 953 145 15.2 %
Date: 2012-06-02 Functions: 108 24 22.2 %

       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                 :  */
      38                 : 
      39                 : #include "cairoint.h"
      40                 : 
      41                 : #include "cairo-surface-fallback-private.h"
      42                 : #include "cairo-clip-private.h"
      43                 : #include "cairo-device-private.h"
      44                 : #include "cairo-error-private.h"
      45                 : #include "cairo-recording-surface-private.h"
      46                 : #include "cairo-region-private.h"
      47                 : #include "cairo-tee-surface-private.h"
      48                 : 
      49                 : /**
      50                 :  * SECTION:cairo-surface
      51                 :  * @Title: cairo_surface_t
      52                 :  * @Short_Description: Base class for surfaces
      53                 :  * @See_Also: #cairo_t, #cairo_pattern_t
      54                 :  *
      55                 :  * #cairo_surface_t is the abstract type representing all different drawing
      56                 :  * targets that cairo can render to.  The actual drawings are
      57                 :  * performed using a cairo <firstterm>context</firstterm>.
      58                 :  *
      59                 :  * A cairo surface is created by using <firstterm>backend</firstterm>-specific
      60                 :  * constructors, typically of the form
      61                 :  * cairo_<emphasis>backend</emphasis>_surface_create().
      62                 :  *
      63                 :  * Most surface types allow accessing the surface without using Cairo
      64                 :  * functions. If you do this, keep in mind that it is mandatory that you call
      65                 :  * cairo_surface_flush() before reading from or writing to the surface and that
      66                 :  * you must use cairo_surface_mark_dirty() after modifying it.
      67                 :  * <example>
      68                 :  * <title>Directly modifying an image surface</title>
      69                 :  * <programlisting>
      70                 :  * void
      71                 :  * modify_image_surface (cairo_surface_t *surface)
      72                 :  * {
      73                 :  *   unsigned char *data;
      74                 :  *   int width, height, stride;
      75                 :  *
      76                 :  *   // flush to ensure all writing to the image was done
      77                 :  *   cairo_surface_flush (surface);
      78                 :  *
      79                 :  *   // modify the image
      80                 :  *   data = cairo_image_surface_get_data (surface);
      81                 :  *   width = cairo_image_surface_get_width (surface);
      82                 :  *   height = cairo_image_surface_get_height (surface);
      83                 :  *   stride = cairo_image_surface_get_stride (surface);
      84                 :  *   modify_image_data (data, width, height, stride);
      85                 :  *
      86                 :  *   // mark the image dirty so Cairo clears its caches.
      87                 :  *   cairo_surface_mark_dirty (surface);
      88                 :  * }
      89                 :  * </programlisting>
      90                 :  * </example>
      91                 :  * Note that for other surface types it might be necessary to acquire the
      92                 :  * surface's device first. See cairo_device_acquire() for a discussion of
      93                 :  * devices.
      94                 :  */
      95                 : 
      96                 : #define DEFINE_NIL_SURFACE(status, name)                        \
      97                 : const cairo_surface_t name = {                                  \
      98                 :     NULL,                               /* backend */           \
      99                 :     NULL,                               /* device */            \
     100                 :     CAIRO_SURFACE_TYPE_IMAGE,           /* type */              \
     101                 :     CAIRO_CONTENT_COLOR,                /* content */           \
     102                 :     CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */         \
     103                 :     status,                             /* status */            \
     104                 :     0,                                  /* unique id */         \
     105                 :     FALSE,                              /* finished */          \
     106                 :     TRUE,                               /* is_clear */          \
     107                 :     FALSE,                              /* has_font_options */  \
     108                 :     FALSE,                              /* owns_device */       \
     109                 :     FALSE,                              /* permit_subpixel_antialiasing */ \
     110                 :     { 0, 0, 0, NULL, },                 /* user_data */         \
     111                 :     { 0, 0, 0, NULL, },                 /* mime_data */         \
     112                 :     { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },   /* device_transform */  \
     113                 :     { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },   /* device_transform_inverse */  \
     114                 :     { NULL, NULL },                     /* device_transform_observers */ \
     115                 :     0.0,                                /* x_resolution */      \
     116                 :     0.0,                                /* y_resolution */      \
     117                 :     0.0,                                /* x_fallback_resolution */     \
     118                 :     0.0,                                /* y_fallback_resolution */     \
     119                 :     NULL,                               /* snapshot_of */       \
     120                 :     NULL,                               /* snapshot_detach */   \
     121                 :     { NULL, NULL },                     /* snapshots */         \
     122                 :     { NULL, NULL },                     /* snapshot */          \
     123                 :     { CAIRO_ANTIALIAS_DEFAULT,          /* antialias */         \
     124                 :       CAIRO_SUBPIXEL_ORDER_DEFAULT,     /* subpixel_order */    \
     125                 :       CAIRO_LCD_FILTER_DEFAULT,         /* lcd_filter */        \
     126                 :       CAIRO_HINT_STYLE_DEFAULT,         /* hint_style */        \
     127                 :       CAIRO_HINT_METRICS_DEFAULT,       /* hint_metrics */      \
     128                 :       CAIRO_ROUND_GLYPH_POS_DEFAULT     /* round_glyph_positions */     \
     129                 :     }                                   /* font_options */      \
     130                 : }
     131                 : 
     132                 : /* XXX error object! */
     133                 : 
     134                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil);
     135                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_SURFACE_TYPE_MISMATCH, _cairo_surface_nil_surface_type_mismatch);
     136                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STATUS, _cairo_surface_nil_invalid_status);
     137                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_CONTENT, _cairo_surface_nil_invalid_content);
     138                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_FORMAT, _cairo_surface_nil_invalid_format);
     139                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_VISUAL, _cairo_surface_nil_invalid_visual);
     140                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_FILE_NOT_FOUND, _cairo_surface_nil_file_not_found);
     141                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_TEMP_FILE_ERROR, _cairo_surface_nil_temp_file_error);
     142                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error);
     143                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error);
     144                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride);
     145                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size);
     146                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_TYPE_MISMATCH, _cairo_surface_nil_device_type_mismatch);
     147                 : static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_ERROR, _cairo_surface_nil_device_error);
     148                 : 
     149                 : /**
     150                 :  * _cairo_surface_set_error:
     151                 :  * @surface: a surface
     152                 :  * @status: a status value indicating an error
     153                 :  *
     154                 :  * Atomically sets surface->status to @status and calls _cairo_error;
     155                 :  * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
     156                 :  * status values.
     157                 :  *
     158                 :  * All assignments of an error status to surface->status should happen
     159                 :  * through _cairo_surface_set_error(). Note that due to the nature of
     160                 :  * the atomic operation, it is not safe to call this function on the
     161                 :  * nil objects.
     162                 :  *
     163                 :  * The purpose of this function is to allow the user to set a
     164                 :  * breakpoint in _cairo_error() to generate a stack trace for when the
     165                 :  * user causes cairo to detect an error.
     166                 :  *
     167                 :  * Return value: the error status.
     168                 :  **/
     169                 : cairo_status_t
     170              64 : _cairo_surface_set_error (cairo_surface_t *surface,
     171                 :                           cairo_status_t status)
     172                 : {
     173              64 :     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
     174               0 :         status = CAIRO_STATUS_SUCCESS;
     175                 : 
     176              64 :     if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
     177              64 :         return status;
     178                 : 
     179                 :     /* Don't overwrite an existing error. This preserves the first
     180                 :      * error, which is the most significant. */
     181               0 :     _cairo_status_set_error (&surface->status, status);
     182                 : 
     183               0 :     return _cairo_error (status);
     184                 : }
     185                 : 
     186                 : /**
     187                 :  * cairo_surface_get_type:
     188                 :  * @surface: a #cairo_surface_t
     189                 :  *
     190                 :  * This function returns the type of the backend used to create
     191                 :  * a surface. See #cairo_surface_type_t for available types.
     192                 :  *
     193                 :  * Return value: The type of @surface.
     194                 :  *
     195                 :  * Since: 1.2
     196                 :  **/
     197                 : cairo_surface_type_t
     198             130 : cairo_surface_get_type (cairo_surface_t *surface)
     199                 : {
     200                 :     /* We don't use surface->backend->type here so that some of the
     201                 :      * special "wrapper" surfaces such as cairo_paginated_surface_t
     202                 :      * can override surface->type with the type of the "child"
     203                 :      * surface. */
     204             130 :     return surface->type;
     205                 : }
     206                 : slim_hidden_def (cairo_surface_get_type);
     207                 : 
     208                 : /**
     209                 :  * cairo_surface_get_content:
     210                 :  * @surface: a #cairo_surface_t
     211                 :  *
     212                 :  * This function returns the content type of @surface which indicates
     213                 :  * whether the surface contains color and/or alpha information. See
     214                 :  * #cairo_content_t.
     215                 :  *
     216                 :  * Return value: The content type of @surface.
     217                 :  *
     218                 :  * Since: 1.2
     219                 :  **/
     220                 : cairo_content_t
     221              65 : cairo_surface_get_content (cairo_surface_t *surface)
     222                 : {
     223              65 :     return surface->content;
     224                 : }
     225                 : slim_hidden_def(cairo_surface_get_content);
     226                 : 
     227                 : /**
     228                 :  * cairo_surface_status:
     229                 :  * @surface: a #cairo_surface_t
     230                 :  *
     231                 :  * Checks whether an error has previously occurred for this
     232                 :  * surface.
     233                 :  *
     234                 :  * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER,
     235                 :  * %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR,
     236                 :  * %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALID_FORMAT, or
     237                 :  * %CAIRO_STATUS_INVALID_VISUAL.
     238                 :  **/
     239                 : cairo_status_t
     240             113 : cairo_surface_status (cairo_surface_t *surface)
     241                 : {
     242             113 :     return surface->status;
     243                 : }
     244                 : slim_hidden_def (cairo_surface_status);
     245                 : 
     246                 : static unsigned int
     247              65 : _cairo_surface_allocate_unique_id (void)
     248                 : {
     249                 :     static cairo_atomic_int_t unique_id;
     250                 : 
     251                 : #if CAIRO_NO_MUTEX
     252              65 :     if (++unique_id == 0)
     253               0 :         unique_id = 1;
     254              65 :     return unique_id;
     255                 : #else
     256                 :     cairo_atomic_int_t old, id;
     257                 : 
     258                 :     do {
     259                 :         old = _cairo_atomic_uint_get (&unique_id);
     260                 :         id = old + 1;
     261                 :         if (id == 0)
     262                 :             id = 1;
     263                 :     } while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id));
     264                 : 
     265                 :     return id;
     266                 : #endif
     267                 : }
     268                 : 
     269                 : /**
     270                 :  * cairo_surface_get_device:
     271                 :  * @surface: a #cairo_surface_t
     272                 :  *
     273                 :  * This function returns the device for a @surface.
     274                 :  * See #cairo_device_t.
     275                 :  *
     276                 :  * Return value: The device for @surface or %NULL if the surface does
     277                 :  *               not have an associated device.
     278                 :  *
     279                 :  * Since: 1.10
     280                 :  **/
     281                 : cairo_device_t *
     282               0 : cairo_surface_get_device (cairo_surface_t *surface)
     283                 : {
     284               0 :     if (unlikely (surface->status))
     285               0 :         return _cairo_device_create_in_error (surface->status);
     286                 : 
     287               0 :     return surface->device;
     288                 : }
     289                 : 
     290                 : static cairo_bool_t
     291             321 : _cairo_surface_has_snapshots (cairo_surface_t *surface)
     292                 : {
     293             321 :     return ! cairo_list_is_empty (&surface->snapshots);
     294                 : }
     295                 : 
     296                 : static cairo_bool_t
     297              91 : _cairo_surface_has_mime_data (cairo_surface_t *surface)
     298                 : {
     299              91 :     return surface->mime_data.num_elements != 0;
     300                 : }
     301                 : 
     302                 : static void
     303              64 : _cairo_surface_detach_mime_data (cairo_surface_t *surface)
     304                 : {
     305              64 :     if (! _cairo_surface_has_mime_data (surface))
     306              64 :         return;
     307                 : 
     308               0 :     _cairo_user_data_array_fini (&surface->mime_data);
     309               0 :     _cairo_user_data_array_init (&surface->mime_data);
     310                 : }
     311                 : 
     312                 : static void
     313             294 : cairo_surface_detach_snapshots (cairo_surface_t *surface)
     314                 : {
     315             588 :     while (_cairo_surface_has_snapshots (surface)) {
     316               0 :         cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
     317                 :                                                                 cairo_surface_t,
     318                 :                                                                 snapshot));
     319                 :     }
     320             294 : }
     321                 : 
     322                 : void
     323               0 : cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
     324                 : {
     325               0 :     assert (snapshot->snapshot_of != NULL);
     326                 : 
     327               0 :     snapshot->snapshot_of = NULL;
     328               0 :     cairo_list_del (&snapshot->snapshot);
     329                 : 
     330               0 :     if (snapshot->snapshot_detach != NULL)
     331               0 :         snapshot->snapshot_detach (snapshot);
     332                 : 
     333               0 :     cairo_surface_destroy (snapshot);
     334               0 : }
     335                 : 
     336                 : void
     337               0 : cairo_surface_attach_snapshot (cairo_surface_t *surface,
     338                 :                                  cairo_surface_t *snapshot,
     339                 :                                  cairo_surface_func_t detach_func)
     340                 : {
     341               0 :     assert (surface != snapshot);
     342               0 :     assert (snapshot->snapshot_of != surface);
     343                 : 
     344               0 :     cairo_surface_reference (snapshot);
     345                 : 
     346               0 :     if (snapshot->snapshot_of != NULL)
     347               0 :         cairo_surface_detach_snapshot (snapshot);
     348                 : 
     349               0 :     snapshot->snapshot_of = surface;
     350               0 :     snapshot->snapshot_detach = detach_func;
     351                 : 
     352               0 :     cairo_list_add (&snapshot->snapshot, &surface->snapshots);
     353                 : 
     354               0 :     assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
     355               0 : }
     356                 : 
     357                 : cairo_surface_t *
     358               0 : _cairo_surface_has_snapshot (cairo_surface_t *surface,
     359                 :                              const cairo_surface_backend_t *backend)
     360                 : {
     361                 :     cairo_surface_t *snapshot;
     362                 : 
     363               0 :     cairo_list_foreach_entry (snapshot, cairo_surface_t,
     364                 :                               &surface->snapshots, snapshot)
     365                 :     {
     366                 :         /* XXX is_similar? */
     367               0 :         if (snapshot->backend == backend)
     368               0 :             return snapshot;
     369                 :     }
     370                 : 
     371               0 :     return NULL;
     372                 : }
     373                 : 
     374                 : static cairo_bool_t
     375               0 : _cairo_surface_is_writable (cairo_surface_t *surface)
     376                 : {
     377               0 :     return ! surface->finished &&
     378               0 :            surface->snapshot_of == NULL &&
     379               0 :            ! _cairo_surface_has_snapshots (surface) &&
     380               0 :            ! _cairo_surface_has_mime_data (surface);
     381                 : }
     382                 : 
     383                 : static void
     384              64 : _cairo_surface_begin_modification (cairo_surface_t *surface)
     385                 : {
     386              64 :     assert (surface->status == CAIRO_STATUS_SUCCESS);
     387              64 :     assert (! surface->finished);
     388              64 :     assert (surface->snapshot_of == NULL);
     389                 : 
     390              64 :     cairo_surface_detach_snapshots (surface);
     391              64 :     _cairo_surface_detach_mime_data (surface);
     392              64 : }
     393                 : 
     394                 : void
     395              65 : _cairo_surface_init (cairo_surface_t                    *surface,
     396                 :                      const cairo_surface_backend_t      *backend,
     397                 :                      cairo_device_t                     *device,
     398                 :                      cairo_content_t                     content)
     399                 : {
     400                 :     CAIRO_MUTEX_INITIALIZE ();
     401                 : 
     402              65 :     surface->backend = backend;
     403              65 :     surface->device = cairo_device_reference (device);
     404              65 :     surface->content = content;
     405              65 :     surface->type = backend->type;
     406                 : 
     407              65 :     CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1);
     408              65 :     surface->status = CAIRO_STATUS_SUCCESS;
     409              65 :     surface->unique_id = _cairo_surface_allocate_unique_id ();
     410              65 :     surface->finished = FALSE;
     411              65 :     surface->is_clear = FALSE;
     412              65 :     surface->owns_device = (device != NULL);
     413              65 :     surface->has_font_options = FALSE;
     414              65 :     surface->permit_subpixel_antialiasing = TRUE;
     415                 : 
     416              65 :     _cairo_user_data_array_init (&surface->user_data);
     417              65 :     _cairo_user_data_array_init (&surface->mime_data);
     418                 : 
     419              65 :     cairo_matrix_init_identity (&surface->device_transform);
     420              65 :     cairo_matrix_init_identity (&surface->device_transform_inverse);
     421              65 :     cairo_list_init (&surface->device_transform_observers);
     422                 : 
     423              65 :     surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
     424              65 :     surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT;
     425                 : 
     426              65 :     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     427              65 :     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     428                 : 
     429              65 :     cairo_list_init (&surface->snapshots);
     430              65 :     surface->snapshot_of = NULL;
     431              65 : }
     432                 : 
     433                 : static void
     434               0 : _cairo_surface_copy_similar_properties (cairo_surface_t *surface,
     435                 :                                         cairo_surface_t *other)
     436                 : {
     437               0 :     if (other->has_font_options || other->backend != surface->backend) {
     438                 :         cairo_font_options_t options;
     439                 : 
     440               0 :         cairo_surface_get_font_options (other, &options);
     441               0 :         _cairo_surface_set_font_options (surface, &options);
     442                 :     }
     443                 : 
     444               0 :     surface->permit_subpixel_antialiasing = other->permit_subpixel_antialiasing;
     445                 : 
     446               0 :     cairo_surface_set_fallback_resolution (surface,
     447                 :                                            other->x_fallback_resolution,
     448                 :                                            other->y_fallback_resolution);
     449               0 : }
     450                 : 
     451                 : cairo_surface_t *
     452               0 : _cairo_surface_create_similar_scratch (cairo_surface_t *other,
     453                 :                                        cairo_content_t  content,
     454                 :                                        int              width,
     455                 :                                        int              height)
     456                 : {
     457                 :     cairo_surface_t *surface;
     458                 : 
     459               0 :     if (unlikely (other->status))
     460               0 :         return _cairo_surface_create_in_error (other->status);
     461                 : 
     462               0 :     if (other->backend->create_similar == NULL)
     463               0 :         return NULL;
     464                 : 
     465               0 :     surface = other->backend->create_similar (other,
     466                 :                                               content, width, height);
     467               0 :     if (surface == NULL || surface->status)
     468               0 :         return surface;
     469                 : 
     470               0 :     _cairo_surface_copy_similar_properties (surface, other);
     471                 : 
     472               0 :     return surface;
     473                 : }
     474                 : 
     475                 : /**
     476                 :  * cairo_surface_create_similar:
     477                 :  * @other: an existing surface used to select the backend of the new surface
     478                 :  * @content: the content for the new surface
     479                 :  * @width: width of the new surface, (in device-space units)
     480                 :  * @height: height of the new surface (in device-space units)
     481                 :  *
     482                 :  * Create a new surface that is as compatible as possible with an
     483                 :  * existing surface. For example the new surface will have the same
     484                 :  * fallback resolution and font options as @other. Generally, the new
     485                 :  * surface will also use the same backend as @other, unless that is
     486                 :  * not possible for some reason. The type of the returned surface may
     487                 :  * be examined with cairo_surface_get_type().
     488                 :  *
     489                 :  * Initially the surface contents are all 0 (transparent if contents
     490                 :  * have transparency, black otherwise.)
     491                 :  *
     492                 :  * Return value: a pointer to the newly allocated surface. The caller
     493                 :  * owns the surface and should call cairo_surface_destroy() when done
     494                 :  * with it.
     495                 :  *
     496                 :  * This function always returns a valid pointer, but it will return a
     497                 :  * pointer to a "nil" surface if @other is already in an error state
     498                 :  * or any other error occurs.
     499                 :  **/
     500                 : cairo_surface_t *
     501               0 : cairo_surface_create_similar (cairo_surface_t  *other,
     502                 :                               cairo_content_t   content,
     503                 :                               int               width,
     504                 :                               int               height)
     505                 : {
     506               0 :     if (unlikely (other->status))
     507               0 :         return _cairo_surface_create_in_error (other->status);
     508               0 :     if (unlikely (other->finished))
     509               0 :         return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
     510                 : 
     511               0 :     if (unlikely (! CAIRO_CONTENT_VALID (content)))
     512               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
     513                 : 
     514               0 :     return _cairo_surface_create_similar_solid (other,
     515                 :                                                 content, width, height,
     516                 :                                                 CAIRO_COLOR_TRANSPARENT,
     517                 :                                                 TRUE);
     518                 : }
     519                 : 
     520                 : cairo_surface_t *
     521               0 : _cairo_surface_create_similar_solid (cairo_surface_t     *other,
     522                 :                                      cairo_content_t      content,
     523                 :                                      int                  width,
     524                 :                                      int                  height,
     525                 :                                      const cairo_color_t *color,
     526                 :                                      cairo_bool_t allow_fallback)
     527                 : {
     528                 :     cairo_status_t status;
     529                 :     cairo_surface_t *surface;
     530                 :     cairo_solid_pattern_t pattern;
     531                 : 
     532               0 :     surface = _cairo_surface_create_similar_scratch (other, content,
     533                 :                                                      width, height);
     534               0 :     if (surface == NULL && allow_fallback)
     535               0 :         surface = _cairo_image_surface_create_with_content (content,
     536                 :                                                             width, height);
     537               0 :     if (surface == NULL || surface->status)
     538               0 :         return surface;
     539                 : 
     540               0 :     _cairo_pattern_init_solid (&pattern, color);
     541               0 :     status = _cairo_surface_paint (surface,
     542               0 :                                    color == CAIRO_COLOR_TRANSPARENT ?
     543                 :                                    CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
     544                 :                                    &pattern.base, NULL);
     545               0 :     if (unlikely (status)) {
     546               0 :         cairo_surface_destroy (surface);
     547               0 :         surface = _cairo_surface_create_in_error (status);
     548                 :     }
     549                 : 
     550               0 :     return surface;
     551                 : }
     552                 : 
     553                 : cairo_surface_t *
     554               0 : _cairo_surface_create_solid_pattern_surface (cairo_surface_t       *other,
     555                 :                                              const cairo_solid_pattern_t *solid_pattern)
     556                 : {
     557               0 :     if (other->backend->create_solid_pattern_surface != NULL) {
     558                 :         cairo_surface_t *surface;
     559                 : 
     560               0 :         surface = other->backend->create_solid_pattern_surface (other,
     561                 :                                                                 solid_pattern);
     562               0 :         if (surface)
     563               0 :             return surface;
     564                 :     }
     565                 : 
     566               0 :     return _cairo_surface_create_similar_solid (other,
     567                 :                                                 _cairo_color_get_content (&solid_pattern->color),
     568                 :                                                 1, 1,
     569                 :                                                 &solid_pattern->color,
     570                 :                                                 FALSE);
     571                 : }
     572                 : 
     573                 : cairo_int_status_t
     574               0 : _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t       *other,
     575                 :                                               cairo_surface_t       *solid_surface,
     576                 :                                               const cairo_solid_pattern_t *solid_pattern)
     577                 : {
     578                 :     /* Solid pattern surface for these backends are special and not trivial
     579                 :      * to repaint.  Skip repainting.
     580                 :      *
     581                 :      * This does not work optimally with things like analysis surface that
     582                 :      * are proxies.  But returning UNSUPPORTED is *safe* as it only
     583                 :      * disables some caching.
     584                 :      */
     585               0 :     if (other->backend->create_solid_pattern_surface != NULL &&
     586               0 :         ! other->backend->can_repaint_solid_pattern_surface (solid_surface,
     587                 :                                                              solid_pattern))
     588                 :     {
     589               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
     590                 :     }
     591                 : 
     592               0 :     return _cairo_surface_paint (solid_surface,
     593                 :                                  CAIRO_OPERATOR_SOURCE,
     594                 :                                  &solid_pattern->base,
     595                 :                                  NULL);
     596                 : }
     597                 : 
     598                 : /**
     599                 :  * cairo_surface_reference:
     600                 :  * @surface: a #cairo_surface_t
     601                 :  *
     602                 :  * Increases the reference count on @surface by one. This prevents
     603                 :  * @surface from being destroyed until a matching call to
     604                 :  * cairo_surface_destroy() is made.
     605                 :  *
     606                 :  * The number of references to a #cairo_surface_t can be get using
     607                 :  * cairo_surface_get_reference_count().
     608                 :  *
     609                 :  * Return value: the referenced #cairo_surface_t.
     610                 :  **/
     611                 : cairo_surface_t *
     612             253 : cairo_surface_reference (cairo_surface_t *surface)
     613                 : {
     614             506 :     if (surface == NULL ||
     615             253 :             CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
     616               0 :         return surface;
     617                 : 
     618             253 :     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
     619                 : 
     620             253 :     _cairo_reference_count_inc (&surface->ref_count);
     621                 : 
     622             253 :     return surface;
     623                 : }
     624                 : slim_hidden_def (cairo_surface_reference);
     625                 : 
     626                 : /**
     627                 :  * cairo_surface_destroy:
     628                 :  * @surface: a #cairo_surface_t
     629                 :  *
     630                 :  * Decreases the reference count on @surface by one. If the result is
     631                 :  * zero, then @surface and all associated resources are freed.  See
     632                 :  * cairo_surface_reference().
     633                 :  **/
     634                 : void
     635             382 : cairo_surface_destroy (cairo_surface_t *surface)
     636                 : {
     637             700 :     if (surface == NULL ||
     638             318 :             CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
     639              64 :         return;
     640                 : 
     641             318 :     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
     642                 : 
     643             318 :     if (! _cairo_reference_count_dec_and_test (&surface->ref_count))
     644             253 :         return;
     645                 : 
     646              65 :     assert (surface->snapshot_of == NULL);
     647                 : 
     648              65 :     if (! surface->finished)
     649              65 :         cairo_surface_finish (surface);
     650                 : 
     651                 :     /* paranoid check that nobody took a reference whilst finishing */
     652              65 :     assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
     653                 : 
     654              65 :     _cairo_user_data_array_fini (&surface->user_data);
     655              65 :     _cairo_user_data_array_fini (&surface->mime_data);
     656                 : 
     657              65 :     if (surface->owns_device)
     658               0 :         cairo_device_destroy (surface->device);
     659                 : 
     660              65 :     free (surface);
     661                 : }
     662                 : slim_hidden_def(cairo_surface_destroy);
     663                 : 
     664                 : /**
     665                 :  * cairo_surface_get_reference_count:
     666                 :  * @surface: a #cairo_surface_t
     667                 :  *
     668                 :  * Returns the current reference count of @surface.
     669                 :  *
     670                 :  * Return value: the current reference count of @surface.  If the
     671                 :  * object is a nil object, 0 will be returned.
     672                 :  *
     673                 :  * Since: 1.4
     674                 :  **/
     675                 : unsigned int
     676             286 : cairo_surface_get_reference_count (cairo_surface_t *surface)
     677                 : {
     678             572 :     if (surface == NULL ||
     679             286 :             CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
     680               0 :         return 0;
     681                 : 
     682             286 :     return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count);
     683                 : }
     684                 : 
     685                 : /**
     686                 :  * cairo_surface_finish:
     687                 :  * @surface: the #cairo_surface_t to finish
     688                 :  *
     689                 :  * This function finishes the surface and drops all references to
     690                 :  * external resources.  For example, for the Xlib backend it means
     691                 :  * that cairo will no longer access the drawable, which can be freed.
     692                 :  * After calling cairo_surface_finish() the only valid operations on a
     693                 :  * surface are getting and setting user, referencing and
     694                 :  * destroying, and flushing and finishing it.
     695                 :  * Further drawing to the surface will not affect the
     696                 :  * surface but will instead trigger a %CAIRO_STATUS_SURFACE_FINISHED
     697                 :  * error.
     698                 :  *
     699                 :  * When the last call to cairo_surface_destroy() decreases the
     700                 :  * reference count to zero, cairo will call cairo_surface_finish() if
     701                 :  * it hasn't been called already, before freeing the resources
     702                 :  * associated with the surface.
     703                 :  **/
     704                 : void
     705              65 : cairo_surface_finish (cairo_surface_t *surface)
     706                 : {
     707                 :     cairo_status_t status;
     708                 : 
     709              65 :     if (surface == NULL)
     710               0 :         return;
     711                 : 
     712              65 :     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
     713               0 :         return;
     714                 : 
     715              65 :     if (surface->finished)
     716               0 :         return;
     717                 : 
     718                 :     /* update the snapshots *before* we declare the surface as finished */
     719              65 :     cairo_surface_detach_snapshots (surface);
     720              65 :     if (surface->snapshot_of != NULL)
     721               0 :         cairo_surface_detach_snapshot (surface);
     722                 : 
     723              65 :     cairo_surface_flush (surface);
     724              65 :     surface->finished = TRUE;
     725                 : 
     726                 :     /* call finish even if in error mode */
     727              65 :     if (surface->backend->finish) {
     728              65 :         status = surface->backend->finish (surface);
     729              65 :         if (unlikely (status))
     730               0 :             status = _cairo_surface_set_error (surface, status);
     731                 :     }
     732                 : }
     733                 : slim_hidden_def (cairo_surface_finish);
     734                 : 
     735                 : /**
     736                 :  * _cairo_surface_release_device_reference:
     737                 :  * @surface: a #cairo_surface_t
     738                 :  *
     739                 :  * This function makes @surface release the reference to its device. The
     740                 :  * function is intended to be used for avoiding cycling references for
     741                 :  * surfaces that are owned by their device, for example cache surfaces.
     742                 :  * Note that the @surface will still assume that the device is available.
     743                 :  * So it is the caller's responsibility to ensure the device stays around
     744                 :  * until the @surface is destroyed. Just calling cairo_surface_finish() is
     745                 :  * not enough.
     746                 :  **/
     747                 : void
     748               0 : _cairo_surface_release_device_reference (cairo_surface_t *surface)
     749                 : {
     750               0 :     assert (surface->owns_device);
     751                 : 
     752               0 :     cairo_device_destroy (surface->device);
     753               0 :     surface->owns_device = FALSE;
     754               0 : }
     755                 : 
     756                 : /**
     757                 :  * cairo_surface_get_user_data:
     758                 :  * @surface: a #cairo_surface_t
     759                 :  * @key: the address of the #cairo_user_data_key_t the user data was
     760                 :  * attached to
     761                 :  *
     762                 :  * Return user data previously attached to @surface using the specified
     763                 :  * key.  If no user data has been attached with the given key this
     764                 :  * function returns %NULL.
     765                 :  *
     766                 :  * Return value: the user data previously attached or %NULL.
     767                 :  **/
     768                 : void *
     769               0 : cairo_surface_get_user_data (cairo_surface_t             *surface,
     770                 :                              const cairo_user_data_key_t *key)
     771                 : {
     772               0 :     return _cairo_user_data_array_get_data (&surface->user_data,
     773                 :                                             key);
     774                 : }
     775                 : 
     776                 : /**
     777                 :  * cairo_surface_set_user_data:
     778                 :  * @surface: a #cairo_surface_t
     779                 :  * @key: the address of a #cairo_user_data_key_t to attach the user data to
     780                 :  * @user_data: the user data to attach to the surface
     781                 :  * @destroy: a #cairo_destroy_func_t which will be called when the
     782                 :  * surface is destroyed or when new user data is attached using the
     783                 :  * same key.
     784                 :  *
     785                 :  * Attach user data to @surface.  To remove user data from a surface,
     786                 :  * call this function with the key that was used to set it and %NULL
     787                 :  * for @data.
     788                 :  *
     789                 :  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
     790                 :  * slot could not be allocated for the user data.
     791                 :  **/
     792                 : cairo_status_t
     793              65 : cairo_surface_set_user_data (cairo_surface_t             *surface,
     794                 :                              const cairo_user_data_key_t *key,
     795                 :                              void                        *user_data,
     796                 :                              cairo_destroy_func_t        destroy)
     797                 : {
     798              65 :     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
     799               0 :         return surface->status;
     800                 : 
     801              65 :     return _cairo_user_data_array_set_data (&surface->user_data,
     802                 :                                             key, user_data, destroy);
     803                 : }
     804                 : 
     805                 : /**
     806                 :  * cairo_surface_get_mime_data:
     807                 :  * @surface: a #cairo_surface_t
     808                 :  * @mime_type: the mime type of the image data
     809                 :  * @data: the image data to attached to the surface
     810                 :  * @length: the length of the image data
     811                 :  *
     812                 :  * Return mime data previously attached to @surface using the
     813                 :  * specified mime type.  If no data has been attached with the given
     814                 :  * mime type, @data is set %NULL.
     815                 :  *
     816                 :  * Since: 1.10
     817                 :  **/
     818                 : void
     819               0 : cairo_surface_get_mime_data (cairo_surface_t            *surface,
     820                 :                              const char                 *mime_type,
     821                 :                              const unsigned char       **data,
     822                 :                              unsigned long              *length)
     823                 : {
     824                 :     cairo_user_data_slot_t *slots;
     825                 :     int i, num_slots;
     826                 : 
     827               0 :     *data = NULL;
     828               0 :     *length = 0;
     829               0 :     if (unlikely (surface->status))
     830               0 :         return;
     831                 : 
     832                 :     /* The number of mime-types attached to a surface is usually small,
     833                 :      * typically zero. Therefore it is quicker to do a strcmp() against
     834                 :      * each key than it is to intern the string (i.e. compute a hash,
     835                 :      * search the hash table, and do a final strcmp).
     836                 :      */
     837               0 :     num_slots = surface->mime_data.num_elements;
     838               0 :     slots = _cairo_array_index (&surface->mime_data, 0);
     839               0 :     for (i = 0; i < num_slots; i++) {
     840               0 :         if (strcmp ((char *) slots[i].key, mime_type) == 0) {
     841               0 :             cairo_mime_data_t *mime_data = slots[i].user_data;
     842                 : 
     843               0 :             *data = mime_data->data;
     844               0 :             *length = mime_data->length;
     845               0 :             return;
     846                 :         }
     847                 :     }
     848                 : }
     849                 : slim_hidden_def (cairo_surface_get_mime_data);
     850                 : 
     851                 : static void
     852               0 : _cairo_mime_data_destroy (void *ptr)
     853                 : {
     854               0 :     cairo_mime_data_t *mime_data = ptr;
     855                 : 
     856               0 :     if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count))
     857               0 :         return;
     858                 : 
     859               0 :     if (mime_data->destroy && mime_data->closure)
     860               0 :         mime_data->destroy (mime_data->closure);
     861                 : 
     862               0 :     free (mime_data);
     863                 : }
     864                 : 
     865                 : /**
     866                 :  * CAIRO_MIME_TYPE_JP2:
     867                 :  *
     868                 :  * The Joint Photographic Experts Group (JPEG) 2000 image coding standard (ISO/IEC 15444-1).
     869                 :  *
     870                 :  * @Since: 1.10
     871                 :  */
     872                 : 
     873                 : /**
     874                 :  * CAIRO_MIME_TYPE_JPEG:
     875                 :  *
     876                 :  * The Joint Photographic Experts Group (JPEG) image coding standard (ISO/IEC 10918-1).
     877                 :  *
     878                 :  * @Since: 1.10
     879                 :  */
     880                 : 
     881                 : /**
     882                 :  * CAIRO_MIME_TYPE_PNG:
     883                 :  *
     884                 :  * The Portable Network Graphics image file format (ISO/IEC 15948).
     885                 :  *
     886                 :  * @Since: 1.10
     887                 :  */
     888                 : 
     889                 : /**
     890                 :  * CAIRO_MIME_TYPE_URI:
     891                 :  *
     892                 :  * URI for an image file (unofficial MIME type).
     893                 :  *
     894                 :  * @Since: 1.10
     895                 :  */
     896                 : 
     897                 : /**
     898                 :  * cairo_surface_set_mime_data:
     899                 :  * @surface: a #cairo_surface_t
     900                 :  * @mime_type: the MIME type of the image data
     901                 :  * @data: the image data to attach to the surface
     902                 :  * @length: the length of the image data
     903                 :  * @destroy: a #cairo_destroy_func_t which will be called when the
     904                 :  * surface is destroyed or when new image data is attached using the
     905                 :  * same mime type.
     906                 :  * @closure: the data to be passed to the @destroy notifier
     907                 :  *
     908                 :  * Attach an image in the format @mime_type to @surface. To remove
     909                 :  * the data from a surface, call this function with same mime type
     910                 :  * and %NULL for @data.
     911                 :  *
     912                 :  * The attached image (or filename) data can later be used by backends
     913                 :  * which support it (currently: PDF, PS, SVG and Win32 Printing
     914                 :  * surfaces) to emit this data instead of making a snapshot of the
     915                 :  * @surface.  This approach tends to be faster and requires less
     916                 :  * memory and disk space.
     917                 :  *
     918                 :  * The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG,
     919                 :  * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI.
     920                 :  *
     921                 :  * See corresponding backend surface docs for details about which MIME
     922                 :  * types it can handle. Caution: the associated MIME data will be
     923                 :  * discarded if you draw on the surface afterwards. Use this function
     924                 :  * with care.
     925                 :  *
     926                 :  * Since: 1.10
     927                 :  *
     928                 :  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
     929                 :  * slot could not be allocated for the user data.
     930                 :  **/
     931                 : cairo_status_t
     932               0 : cairo_surface_set_mime_data (cairo_surface_t            *surface,
     933                 :                              const char                 *mime_type,
     934                 :                              const unsigned char        *data,
     935                 :                              unsigned long               length,
     936                 :                              cairo_destroy_func_t        destroy,
     937                 :                              void                       *closure)
     938                 : {
     939                 :     cairo_status_t status;
     940                 :     cairo_mime_data_t *mime_data;
     941                 : 
     942               0 :     if (unlikely (surface->status))
     943               0 :         return surface->status;
     944               0 :     if (surface->finished)
     945               0 :         return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
     946                 : 
     947               0 :     status = _cairo_intern_string (&mime_type, -1);
     948               0 :     if (unlikely (status))
     949               0 :         return _cairo_surface_set_error (surface, status);
     950                 : 
     951               0 :     if (data != NULL) {
     952               0 :         mime_data = malloc (sizeof (cairo_mime_data_t));
     953               0 :         if (unlikely (mime_data == NULL))
     954               0 :             return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY));
     955                 : 
     956               0 :         CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1);
     957                 : 
     958               0 :         mime_data->data = (unsigned char *) data;
     959               0 :         mime_data->length = length;
     960               0 :         mime_data->destroy = destroy;
     961               0 :         mime_data->closure = closure;
     962                 :     } else
     963               0 :         mime_data = NULL;
     964                 : 
     965               0 :     status = _cairo_user_data_array_set_data (&surface->mime_data,
     966                 :                                               (cairo_user_data_key_t *) mime_type,
     967                 :                                               mime_data,
     968                 :                                               _cairo_mime_data_destroy);
     969               0 :     if (unlikely (status)) {
     970               0 :         if (mime_data != NULL)
     971               0 :             free (mime_data);
     972                 : 
     973               0 :         return _cairo_surface_set_error (surface, status);
     974                 :     }
     975                 : 
     976               0 :     return CAIRO_STATUS_SUCCESS;
     977                 : }
     978                 : slim_hidden_def (cairo_surface_set_mime_data);
     979                 : 
     980                 : static void
     981               0 : _cairo_mime_data_reference (const void *key, void *elt, void *closure)
     982                 : {
     983               0 :     cairo_mime_data_t *mime_data = elt;
     984                 : 
     985               0 :     _cairo_reference_count_inc (&mime_data->ref_count);
     986               0 : }
     987                 : 
     988                 : cairo_status_t
     989               0 : _cairo_surface_copy_mime_data (cairo_surface_t *dst,
     990                 :                                cairo_surface_t *src)
     991                 : {
     992                 :     cairo_status_t status;
     993                 : 
     994               0 :     if (dst->status)
     995               0 :         return dst->status;
     996                 : 
     997               0 :     if (src->status)
     998               0 :         return _cairo_surface_set_error (dst, src->status);
     999                 : 
    1000                 :     /* first copy the mime-data, discarding any already set on dst */
    1001               0 :     status = _cairo_user_data_array_copy (&dst->mime_data, &src->mime_data);
    1002               0 :     if (unlikely (status))
    1003               0 :         return _cairo_surface_set_error (dst, status);
    1004                 : 
    1005                 :     /* now increment the reference counters for the copies */
    1006               0 :     _cairo_user_data_array_foreach (&dst->mime_data,
    1007                 :                                     _cairo_mime_data_reference,
    1008                 :                                     NULL);
    1009                 : 
    1010               0 :     return CAIRO_STATUS_SUCCESS;
    1011                 : }
    1012                 : 
    1013                 : /**
    1014                 :  * _cairo_surface_set_font_options:
    1015                 :  * @surface: a #cairo_surface_t
    1016                 :  * @options: a #cairo_font_options_t object that contains the
    1017                 :  *   options to use for this surface instead of backend's default
    1018                 :  *   font options.
    1019                 :  *
    1020                 :  * Sets the default font rendering options for the surface.
    1021                 :  * This is useful to correctly propagate default font options when
    1022                 :  * falling back to an image surface in a backend implementation.
    1023                 :  * This affects the options returned in cairo_surface_get_font_options().
    1024                 :  *
    1025                 :  * If @options is %NULL the surface options are reset to those of
    1026                 :  * the backend default.
    1027                 :  **/
    1028                 : void
    1029               0 : _cairo_surface_set_font_options (cairo_surface_t       *surface,
    1030                 :                                  cairo_font_options_t  *options)
    1031                 : {
    1032                 :     cairo_status_t status;
    1033                 : 
    1034               0 :     if (surface->status)
    1035               0 :         return;
    1036                 : 
    1037               0 :     assert (surface->snapshot_of == NULL);
    1038                 : 
    1039               0 :     if (surface->finished) {
    1040               0 :         status = _cairo_surface_set_error (surface,
    1041                 :                                            _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
    1042               0 :         return;
    1043                 :     }
    1044                 : 
    1045               0 :     if (options) {
    1046               0 :         surface->has_font_options = TRUE;
    1047               0 :         _cairo_font_options_init_copy (&surface->font_options, options);
    1048                 :     } else {
    1049               0 :         surface->has_font_options = FALSE;
    1050                 :     }
    1051                 : }
    1052                 : 
    1053                 : /**
    1054                 :  * cairo_surface_get_font_options:
    1055                 :  * @surface: a #cairo_surface_t
    1056                 :  * @options: a #cairo_font_options_t object into which to store
    1057                 :  *   the retrieved options. All existing values are overwritten
    1058                 :  *
    1059                 :  * Retrieves the default font rendering options for the surface.
    1060                 :  * This allows display surfaces to report the correct subpixel order
    1061                 :  * for rendering on them, print surfaces to disable hinting of
    1062                 :  * metrics and so forth. The result can then be used with
    1063                 :  * cairo_scaled_font_create().
    1064                 :  **/
    1065                 : void
    1066               0 : cairo_surface_get_font_options (cairo_surface_t       *surface,
    1067                 :                                 cairo_font_options_t  *options)
    1068                 : {
    1069               0 :     if (cairo_font_options_status (options))
    1070               0 :         return;
    1071                 : 
    1072               0 :     if (surface->status) {
    1073               0 :         _cairo_font_options_init_default (options);
    1074               0 :         return;
    1075                 :     }
    1076                 : 
    1077               0 :     if (! surface->has_font_options) {
    1078               0 :         surface->has_font_options = TRUE;
    1079                 : 
    1080               0 :         _cairo_font_options_init_default (&surface->font_options);
    1081                 : 
    1082               0 :         if (!surface->finished && surface->backend->get_font_options) {
    1083               0 :             surface->backend->get_font_options (surface, &surface->font_options);
    1084                 :         }
    1085                 :     }
    1086                 : 
    1087               0 :     _cairo_font_options_init_copy (options, &surface->font_options);
    1088                 : }
    1089                 : slim_hidden_def (cairo_surface_get_font_options);
    1090                 : 
    1091                 : /**
    1092                 :  * cairo_surface_flush:
    1093                 :  * @surface: a #cairo_surface_t
    1094                 :  *
    1095                 :  * Do any pending drawing for the surface and also restore any
    1096                 :  * temporary modifications cairo has made to the surface's
    1097                 :  * state. This function must be called before switching from
    1098                 :  * drawing on the surface with cairo to drawing on it directly
    1099                 :  * with native APIs. If the surface doesn't support direct access,
    1100                 :  * then this function does nothing.
    1101                 :  **/
    1102                 : void
    1103             165 : cairo_surface_flush (cairo_surface_t *surface)
    1104                 : {
    1105                 :     cairo_status_t status;
    1106                 : 
    1107             165 :     if (surface->status)
    1108               0 :         return;
    1109                 : 
    1110             165 :     if (surface->finished)
    1111               0 :         return;
    1112                 : 
    1113                 :     /* update the current snapshots *before* the user updates the surface */
    1114             165 :     cairo_surface_detach_snapshots (surface);
    1115                 : 
    1116             165 :     if (surface->backend->flush) {
    1117               0 :         status = surface->backend->flush (surface);
    1118               0 :         if (unlikely (status))
    1119               0 :             status = _cairo_surface_set_error (surface, status);
    1120                 :     }
    1121                 : }
    1122                 : slim_hidden_def (cairo_surface_flush);
    1123                 : 
    1124                 : /**
    1125                 :  * cairo_surface_mark_dirty:
    1126                 :  * @surface: a #cairo_surface_t
    1127                 :  *
    1128                 :  * Tells cairo that drawing has been done to surface using means other
    1129                 :  * than cairo, and that cairo should reread any cached areas. Note
    1130                 :  * that you must call cairo_surface_flush() before doing such drawing.
    1131                 :  */
    1132                 : void
    1133              27 : cairo_surface_mark_dirty (cairo_surface_t *surface)
    1134                 : {
    1135              27 :     cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1);
    1136              27 : }
    1137                 : slim_hidden_def (cairo_surface_mark_dirty);
    1138                 : 
    1139                 : /**
    1140                 :  * cairo_surface_mark_dirty_rectangle:
    1141                 :  * @surface: a #cairo_surface_t
    1142                 :  * @x: X coordinate of dirty rectangle
    1143                 :  * @y: Y coordinate of dirty rectangle
    1144                 :  * @width: width of dirty rectangle
    1145                 :  * @height: height of dirty rectangle
    1146                 :  *
    1147                 :  * Like cairo_surface_mark_dirty(), but drawing has been done only to
    1148                 :  * the specified rectangle, so that cairo can retain cached contents
    1149                 :  * for other parts of the surface.
    1150                 :  *
    1151                 :  * Any cached clip set on the surface will be reset by this function,
    1152                 :  * to make sure that future cairo calls have the clip set that they
    1153                 :  * expect.
    1154                 :  */
    1155                 : void
    1156              27 : cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
    1157                 :                                     int              x,
    1158                 :                                     int              y,
    1159                 :                                     int              width,
    1160                 :                                     int              height)
    1161                 : {
    1162                 :     cairo_status_t status;
    1163                 : 
    1164              27 :     if (surface->status)
    1165               0 :         return;
    1166                 : 
    1167              27 :     assert (surface->snapshot_of == NULL);
    1168                 : 
    1169              27 :     if (surface->finished) {
    1170               0 :         status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
    1171               0 :         return;
    1172                 :     }
    1173                 : 
    1174                 :     /* The application *should* have called cairo_surface_flush() before
    1175                 :      * modifying the surface independently of cairo (and thus having to
    1176                 :      * call mark_dirty()). */
    1177              27 :     assert (! _cairo_surface_has_snapshots (surface));
    1178              27 :     assert (! _cairo_surface_has_mime_data (surface));
    1179                 : 
    1180              27 :     surface->is_clear = FALSE;
    1181                 : 
    1182              27 :     if (surface->backend->mark_dirty_rectangle != NULL) {
    1183                 :         /* XXX: FRAGILE: We're ignoring the scaling component of
    1184                 :          * device_transform here. I don't know what the right thing to
    1185                 :          * do would actually be if there were some scaling here, but
    1186                 :          * we avoid this since device_transfom scaling is not exported
    1187                 :          * publicly and mark_dirty is not used internally. */
    1188               0 :         status = surface->backend->mark_dirty_rectangle (surface,
    1189               0 :                                                          x + surface->device_transform.x0,
    1190               0 :                                                          y + surface->device_transform.y0,
    1191                 :                                                          width, height);
    1192                 : 
    1193               0 :         if (unlikely (status))
    1194               0 :             status = _cairo_surface_set_error (surface, status);
    1195                 :     }
    1196                 : }
    1197                 : slim_hidden_def (cairo_surface_mark_dirty_rectangle);
    1198                 : 
    1199                 : /**
    1200                 :  * _cairo_surface_set_device_scale:
    1201                 :  * @surface: a #cairo_surface_t
    1202                 :  * @sx: a scale factor in the X direction
    1203                 :  * @sy: a scale factor in the Y direction
    1204                 :  *
    1205                 :  * Private function for setting an extra scale factor to affect all
    1206                 :  * drawing to a surface. This is used, for example, when replaying a
    1207                 :  * recording surface to an image fallback intended for an eventual
    1208                 :  * vector-oriented backend. Since the recording surface will record
    1209                 :  * coordinates in one backend space, but the image fallback uses a
    1210                 :  * different backend space, (differing by the fallback resolution
    1211                 :  * scale factors), we need a scale factor correction.
    1212                 :  *
    1213                 :  * Caution: Not all places we use device transform correctly handle
    1214                 :  * both a translate and a scale.  An audit would be nice.
    1215                 :  **/
    1216                 : void
    1217               0 : _cairo_surface_set_device_scale (cairo_surface_t *surface,
    1218                 :                                  double           sx,
    1219                 :                                  double           sy)
    1220                 : {
    1221                 :     cairo_status_t status;
    1222                 : 
    1223               0 :     if (surface->status)
    1224               0 :         return;
    1225                 : 
    1226               0 :     assert (surface->snapshot_of == NULL);
    1227                 : 
    1228               0 :     if (surface->finished) {
    1229               0 :         status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
    1230               0 :         return;
    1231                 :     }
    1232                 : 
    1233               0 :     _cairo_surface_begin_modification (surface);
    1234                 : 
    1235               0 :     surface->device_transform.xx = sx;
    1236               0 :     surface->device_transform.yy = sy;
    1237               0 :     surface->device_transform.xy = 0.0;
    1238               0 :     surface->device_transform.yx = 0.0;
    1239                 : 
    1240               0 :     surface->device_transform_inverse = surface->device_transform;
    1241               0 :     status = cairo_matrix_invert (&surface->device_transform_inverse);
    1242                 :     /* should always be invertible unless given pathological input */
    1243               0 :     assert (status == CAIRO_STATUS_SUCCESS);
    1244                 : 
    1245               0 :     _cairo_observers_notify (&surface->device_transform_observers, surface);
    1246                 : }
    1247                 : 
    1248                 : /**
    1249                 :  * cairo_surface_set_device_offset:
    1250                 :  * @surface: a #cairo_surface_t
    1251                 :  * @x_offset: the offset in the X direction, in device units
    1252                 :  * @y_offset: the offset in the Y direction, in device units
    1253                 :  *
    1254                 :  * Sets an offset that is added to the device coordinates determined
    1255                 :  * by the CTM when drawing to @surface. One use case for this function
    1256                 :  * is when we want to create a #cairo_surface_t that redirects drawing
    1257                 :  * for a portion of an onscreen surface to an offscreen surface in a
    1258                 :  * way that is completely invisible to the user of the cairo
    1259                 :  * API. Setting a transformation via cairo_translate() isn't
    1260                 :  * sufficient to do this, since functions like
    1261                 :  * cairo_device_to_user() will expose the hidden offset.
    1262                 :  *
    1263                 :  * Note that the offset affects drawing to the surface as well as
    1264                 :  * using the surface in a source pattern.
    1265                 :  **/
    1266                 : void
    1267               0 : cairo_surface_set_device_offset (cairo_surface_t *surface,
    1268                 :                                  double           x_offset,
    1269                 :                                  double           y_offset)
    1270                 : {
    1271                 :     cairo_status_t status;
    1272                 : 
    1273               0 :     if (surface->status)
    1274               0 :         return;
    1275                 : 
    1276               0 :     assert (surface->snapshot_of == NULL);
    1277                 : 
    1278               0 :     if (surface->finished) {
    1279               0 :         status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
    1280               0 :         return;
    1281                 :     }
    1282                 : 
    1283               0 :     _cairo_surface_begin_modification (surface);
    1284                 : 
    1285               0 :     surface->device_transform.x0 = x_offset;
    1286               0 :     surface->device_transform.y0 = y_offset;
    1287                 : 
    1288               0 :     surface->device_transform_inverse = surface->device_transform;
    1289               0 :     status = cairo_matrix_invert (&surface->device_transform_inverse);
    1290                 :     /* should always be invertible unless given pathological input */
    1291               0 :     assert (status == CAIRO_STATUS_SUCCESS);
    1292                 : 
    1293               0 :     _cairo_observers_notify (&surface->device_transform_observers, surface);
    1294                 : }
    1295                 : slim_hidden_def (cairo_surface_set_device_offset);
    1296                 : 
    1297                 : /**
    1298                 :  * cairo_surface_get_device_offset:
    1299                 :  * @surface: a #cairo_surface_t
    1300                 :  * @x_offset: the offset in the X direction, in device units
    1301                 :  * @y_offset: the offset in the Y direction, in device units
    1302                 :  *
    1303                 :  * This function returns the previous device offset set by
    1304                 :  * cairo_surface_set_device_offset().
    1305                 :  *
    1306                 :  * Since: 1.2
    1307                 :  **/
    1308                 : void
    1309               0 : cairo_surface_get_device_offset (cairo_surface_t *surface,
    1310                 :                                  double          *x_offset,
    1311                 :                                  double          *y_offset)
    1312                 : {
    1313               0 :     if (x_offset)
    1314               0 :         *x_offset = surface->device_transform.x0;
    1315               0 :     if (y_offset)
    1316               0 :         *y_offset = surface->device_transform.y0;
    1317               0 : }
    1318                 : slim_hidden_def (cairo_surface_get_device_offset);
    1319                 : 
    1320                 : /**
    1321                 :  * cairo_surface_set_fallback_resolution:
    1322                 :  * @surface: a #cairo_surface_t
    1323                 :  * @x_pixels_per_inch: horizontal setting for pixels per inch
    1324                 :  * @y_pixels_per_inch: vertical setting for pixels per inch
    1325                 :  *
    1326                 :  * Set the horizontal and vertical resolution for image fallbacks.
    1327                 :  *
    1328                 :  * When certain operations aren't supported natively by a backend,
    1329                 :  * cairo will fallback by rendering operations to an image and then
    1330                 :  * overlaying that image onto the output. For backends that are
    1331                 :  * natively vector-oriented, this function can be used to set the
    1332                 :  * resolution used for these image fallbacks, (larger values will
    1333                 :  * result in more detailed images, but also larger file sizes).
    1334                 :  *
    1335                 :  * Some examples of natively vector-oriented backends are the ps, pdf,
    1336                 :  * and svg backends.
    1337                 :  *
    1338                 :  * For backends that are natively raster-oriented, image fallbacks are
    1339                 :  * still possible, but they are always performed at the native
    1340                 :  * device resolution. So this function has no effect on those
    1341                 :  * backends.
    1342                 :  *
    1343                 :  * Note: The fallback resolution only takes effect at the time of
    1344                 :  * completing a page (with cairo_show_page() or cairo_copy_page()) so
    1345                 :  * there is currently no way to have more than one fallback resolution
    1346                 :  * in effect on a single page.
    1347                 :  *
    1348                 :  * The default fallback resoultion is 300 pixels per inch in both
    1349                 :  * dimensions.
    1350                 :  *
    1351                 :  * Since: 1.2
    1352                 :  **/
    1353                 : void
    1354               0 : cairo_surface_set_fallback_resolution (cairo_surface_t  *surface,
    1355                 :                                        double            x_pixels_per_inch,
    1356                 :                                        double            y_pixels_per_inch)
    1357                 : {
    1358                 :     cairo_status_t status;
    1359                 : 
    1360               0 :     if (surface->status)
    1361               0 :         return;
    1362                 : 
    1363               0 :     assert (surface->snapshot_of == NULL);
    1364                 : 
    1365               0 :     if (surface->finished) {
    1366               0 :         status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
    1367               0 :         return;
    1368                 :     }
    1369                 : 
    1370               0 :     if (x_pixels_per_inch <= 0 || y_pixels_per_inch <= 0) {
    1371                 :         /* XXX Could delay raising the error until we fallback, but throwing
    1372                 :          * the error here means that we can catch the real culprit.
    1373                 :          */
    1374               0 :         status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX);
    1375               0 :         return;
    1376                 :     }
    1377                 : 
    1378               0 :     _cairo_surface_begin_modification (surface);
    1379                 : 
    1380               0 :     surface->x_fallback_resolution = x_pixels_per_inch;
    1381               0 :     surface->y_fallback_resolution = y_pixels_per_inch;
    1382                 : }
    1383                 : slim_hidden_def (cairo_surface_set_fallback_resolution);
    1384                 : 
    1385                 : /**
    1386                 :  * cairo_surface_get_fallback_resolution:
    1387                 :  * @surface: a #cairo_surface_t
    1388                 :  * @x_pixels_per_inch: horizontal pixels per inch
    1389                 :  * @y_pixels_per_inch: vertical pixels per inch
    1390                 :  *
    1391                 :  * This function returns the previous fallback resolution set by
    1392                 :  * cairo_surface_set_fallback_resolution(), or default fallback
    1393                 :  * resolution if never set.
    1394                 :  *
    1395                 :  * Since: 1.8
    1396                 :  **/
    1397                 : void
    1398               0 : cairo_surface_get_fallback_resolution (cairo_surface_t  *surface,
    1399                 :                                        double           *x_pixels_per_inch,
    1400                 :                                        double           *y_pixels_per_inch)
    1401                 : {
    1402               0 :     if (x_pixels_per_inch)
    1403               0 :         *x_pixels_per_inch = surface->x_fallback_resolution;
    1404               0 :     if (y_pixels_per_inch)
    1405               0 :         *y_pixels_per_inch = surface->y_fallback_resolution;
    1406               0 : }
    1407                 : 
    1408                 : int
    1409               0 : _cairo_surface_get_text_path_fill_threshold (const cairo_surface_t *surface)
    1410                 : {
    1411               0 :     return surface->backend->fill == NULL ? 10240 : 256;
    1412                 : }
    1413                 : 
    1414                 : cairo_bool_t
    1415              94 : _cairo_surface_has_device_transform (cairo_surface_t *surface)
    1416                 : {
    1417              94 :     return ! _cairo_matrix_is_identity (&surface->device_transform);
    1418                 : }
    1419                 : 
    1420                 : /**
    1421                 :  * _cairo_surface_acquire_source_image:
    1422                 :  * @surface: a #cairo_surface_t
    1423                 :  * @image_out: location to store a pointer to an image surface that
    1424                 :  *    has identical contents to @surface. This surface could be @surface
    1425                 :  *    itself, a surface held internal to @surface, or it could be a new
    1426                 :  *    surface with a copy of the relevant portion of @surface.
    1427                 :  * @image_extra: location to store image specific backend data
    1428                 :  *
    1429                 :  * Gets an image surface to use when drawing as a fallback when drawing with
    1430                 :  * @surface as a source. _cairo_surface_release_source_image() must be called
    1431                 :  * when finished.
    1432                 :  *
    1433                 :  * Return value: %CAIRO_STATUS_SUCCESS if an image was stored in @image_out.
    1434                 :  * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified
    1435                 :  * surface. Or %CAIRO_STATUS_NO_MEMORY.
    1436                 :  **/
    1437                 : cairo_status_t
    1438               0 : _cairo_surface_acquire_source_image (cairo_surface_t         *surface,
    1439                 :                                      cairo_image_surface_t  **image_out,
    1440                 :                                      void                   **image_extra)
    1441                 : {
    1442                 :     cairo_status_t status;
    1443                 : 
    1444               0 :     if (surface->status)
    1445               0 :         return surface->status;
    1446                 : 
    1447               0 :     assert (!surface->finished);
    1448                 : 
    1449               0 :     if (surface->backend->acquire_source_image == NULL)
    1450               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1451                 : 
    1452               0 :     status = surface->backend->acquire_source_image (surface,
    1453                 :                                                      image_out, image_extra);
    1454               0 :     if (unlikely (status))
    1455               0 :         return _cairo_surface_set_error (surface, status);
    1456                 : 
    1457               0 :     if (PIXMAN_FORMAT_BPP((*image_out)->pixman_format) == 0) {
    1458                 :         volatile char* acquire_source_image_ptr[10];
    1459                 :         volatile char* crasher;
    1460                 :         int i;
    1461               0 :         for (i = 0; i < 10; i++) {
    1462               0 :             acquire_source_image_ptr[i] = (char*)surface->backend->acquire_source_image;
    1463                 :         }
    1464               0 :         crasher = NULL;
    1465               0 :         *crasher = acquire_source_image_ptr[5];
    1466                 :     }
    1467                 :     _cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
    1468                 : 
    1469               0 :     return CAIRO_STATUS_SUCCESS;
    1470                 : }
    1471                 : 
    1472                 : /**
    1473                 :  * _cairo_surface_release_source_image:
    1474                 :  * @surface: a #cairo_surface_t
    1475                 :  * @image_extra: same as return from the matching _cairo_surface_acquire_source_image()
    1476                 :  *
    1477                 :  * Releases any resources obtained with _cairo_surface_acquire_source_image()
    1478                 :  **/
    1479                 : void
    1480               0 : _cairo_surface_release_source_image (cairo_surface_t        *surface,
    1481                 :                                      cairo_image_surface_t  *image,
    1482                 :                                      void                   *image_extra)
    1483                 : {
    1484               0 :     assert (!surface->finished);
    1485                 : 
    1486               0 :     if (surface->backend->release_source_image)
    1487               0 :         surface->backend->release_source_image (surface, image, image_extra);
    1488               0 : }
    1489                 : 
    1490                 : /**
    1491                 :  * _cairo_surface_acquire_dest_image:
    1492                 :  * @surface: a #cairo_surface_t
    1493                 :  * @interest_rect: area of @surface for which fallback drawing is being done.
    1494                 :  *    A value of %NULL indicates that the entire surface is desired.
    1495                 :  *    XXXX I'd like to get rid of being able to pass %NULL here (nothing seems to)
    1496                 :  * @image_out: location to store a pointer to an image surface that includes at least
    1497                 :  *    the intersection of @interest_rect with the visible area of @surface.
    1498                 :  *    This surface could be @surface itself, a surface held internal to @surface,
    1499                 :  *    or it could be a new surface with a copy of the relevant portion of @surface.
    1500                 :  *    If a new surface is created, it should have the same channels and depth
    1501                 :  *    as @surface so that copying to and from it is exact.
    1502                 :  * @image_rect: location to store area of the original surface occupied
    1503                 :  *    by the surface stored in @image.
    1504                 :  * @image_extra: location to store image specific backend data
    1505                 :  *
    1506                 :  * Retrieves a local image for a surface for implementing a fallback drawing
    1507                 :  * operation. After calling this function, the implementation of the fallback
    1508                 :  * drawing operation draws the primitive to the surface stored in @image_out
    1509                 :  * then calls _cairo_surface_release_dest_image(),
    1510                 :  * which, if a temporary surface was created, copies the bits back to the
    1511                 :  * main surface and frees the temporary surface.
    1512                 :  *
    1513                 :  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
    1514                 :  *  %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that
    1515                 :  *  the backend can't draw with fallbacks. It's possible for the routine
    1516                 :  *  to store %NULL in @local_out and return %CAIRO_STATUS_SUCCESS;
    1517                 :  *  that indicates that no part of @interest_rect is visible, so no drawing
    1518                 :  *  is necessary. _cairo_surface_release_dest_image() should not be called in that
    1519                 :  *  case.
    1520                 :  **/
    1521                 : cairo_status_t
    1522               0 : _cairo_surface_acquire_dest_image (cairo_surface_t         *surface,
    1523                 :                                    cairo_rectangle_int_t   *interest_rect,
    1524                 :                                    cairo_image_surface_t  **image_out,
    1525                 :                                    cairo_rectangle_int_t   *image_rect,
    1526                 :                                    void                   **image_extra)
    1527                 : {
    1528                 :     cairo_status_t status;
    1529                 : 
    1530               0 :     if (surface->status)
    1531               0 :         return surface->status;
    1532                 : 
    1533               0 :     assert (_cairo_surface_is_writable (surface));
    1534                 : 
    1535               0 :     if (surface->backend->acquire_dest_image == NULL)
    1536               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1537                 : 
    1538               0 :     status = surface->backend->acquire_dest_image (surface,
    1539                 :                                                    interest_rect,
    1540                 :                                                    image_out,
    1541                 :                                                    image_rect,
    1542                 :                                                    image_extra);
    1543               0 :     if (unlikely (status))
    1544               0 :         return _cairo_surface_set_error (surface, status);
    1545                 : 
    1546                 :     _cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
    1547                 : 
    1548               0 :     return CAIRO_STATUS_SUCCESS;
    1549                 : }
    1550                 : 
    1551                 : /**
    1552                 :  * _cairo_surface_release_dest_image:
    1553                 :  * @surface: a #cairo_surface_t
    1554                 :  * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image()
    1555                 :  * @image: same as returned from the matching _cairo_surface_acquire_dest_image()
    1556                 :  * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image()
    1557                 :  * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
    1558                 :  *
    1559                 :  * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if
    1560                 :  * necessary, copying the image from @image back to @surface and freeing any
    1561                 :  * resources that were allocated.
    1562                 :  **/
    1563                 : void
    1564               0 : _cairo_surface_release_dest_image (cairo_surface_t         *surface,
    1565                 :                                    cairo_rectangle_int_t   *interest_rect,
    1566                 :                                    cairo_image_surface_t   *image,
    1567                 :                                    cairo_rectangle_int_t   *image_rect,
    1568                 :                                    void                    *image_extra)
    1569                 : {
    1570               0 :     assert (_cairo_surface_is_writable (surface));
    1571                 : 
    1572               0 :     if (surface->backend->release_dest_image)
    1573               0 :         surface->backend->release_dest_image (surface, interest_rect,
    1574                 :                                               image, image_rect, image_extra);
    1575               0 : }
    1576                 : 
    1577                 : static cairo_status_t
    1578               0 : _cairo_recording_surface_clone_similar (cairo_surface_t  *surface,
    1579                 :                                         cairo_surface_t  *src,
    1580                 :                                         int               src_x,
    1581                 :                                         int               src_y,
    1582                 :                                         int               width,
    1583                 :                                         int               height,
    1584                 :                                         int              *clone_offset_x,
    1585                 :                                         int              *clone_offset_y,
    1586                 :                                         cairo_surface_t **clone_out)
    1587                 : {
    1588               0 :     cairo_recording_surface_t *recorder = (cairo_recording_surface_t *) src;
    1589                 :     cairo_surface_t *similar;
    1590                 :     cairo_status_t status;
    1591                 : 
    1592               0 :     similar = _cairo_surface_has_snapshot (src, surface->backend);
    1593               0 :     if (similar != NULL) {
    1594               0 :         *clone_out = cairo_surface_reference (similar);
    1595               0 :         *clone_offset_x = 0;
    1596               0 :         *clone_offset_y = 0;
    1597               0 :         return CAIRO_STATUS_SUCCESS;
    1598                 :     }
    1599                 : 
    1600               0 :     if (recorder->unbounded ||
    1601               0 :         width*height*8 < recorder->extents.width*recorder->extents.height)
    1602                 :     {
    1603               0 :         similar = _cairo_surface_create_similar_solid (surface,
    1604                 :                                                        src->content,
    1605                 :                                                        width, height,
    1606                 :                                                        CAIRO_COLOR_TRANSPARENT,
    1607                 :                                                        FALSE);
    1608               0 :         if (similar == NULL)
    1609               0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
    1610               0 :         if (unlikely (similar->status))
    1611               0 :             return similar->status;
    1612                 : 
    1613               0 :         cairo_surface_set_device_offset (similar, -src_x, -src_y);
    1614                 : 
    1615               0 :         status = _cairo_recording_surface_replay (src, similar);
    1616               0 :         if (unlikely (status)) {
    1617               0 :             cairo_surface_destroy (similar);
    1618               0 :             return status;
    1619                 :         }
    1620                 :     } else {
    1621               0 :         similar = _cairo_surface_create_similar_scratch (surface,
    1622                 :                                                          src->content,
    1623                 :                                                          recorder->extents.width,
    1624                 :                                                          recorder->extents.height);
    1625               0 :         if (similar == NULL)
    1626               0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
    1627               0 :         if (unlikely (similar->status))
    1628               0 :             return similar->status;
    1629                 : 
    1630               0 :         status = _cairo_recording_surface_replay (src, similar);
    1631               0 :         if (unlikely (status)) {
    1632               0 :             cairo_surface_destroy (similar);
    1633               0 :             return status;
    1634                 :         }
    1635                 : 
    1636               0 :         cairo_surface_attach_snapshot (src, similar, NULL);
    1637                 : 
    1638               0 :         src_x = src_y = 0;
    1639                 :     }
    1640                 : 
    1641               0 :     *clone_out = similar;
    1642               0 :     *clone_offset_x = src_x;
    1643               0 :     *clone_offset_y = src_y;
    1644               0 :     return CAIRO_STATUS_SUCCESS;
    1645                 : }
    1646                 : 
    1647                 : struct acquire_source_image_data
    1648                 : {
    1649                 :     cairo_surface_t *src;
    1650                 :     cairo_image_surface_t *image;
    1651                 :     void *image_extra;
    1652                 : };
    1653                 : 
    1654                 : static void
    1655               0 : _wrap_release_source_image (void *data)
    1656                 : {
    1657               0 :     struct acquire_source_image_data *acquire_data = data;
    1658               0 :     _cairo_surface_release_source_image (acquire_data->src,
    1659                 :                                          acquire_data->image,
    1660                 :                                          acquire_data->image_extra);
    1661               0 :     free(data);
    1662               0 : }
    1663                 : 
    1664                 : static cairo_status_t
    1665               0 : _wrap_image (cairo_surface_t *src,
    1666                 :              cairo_image_surface_t *image,
    1667                 :              void *image_extra,
    1668                 :              cairo_image_surface_t **out)
    1669                 : {
    1670                 :     static cairo_user_data_key_t wrap_image_key;
    1671                 :     cairo_image_surface_t *surface;
    1672                 :     cairo_status_t status;
    1673                 : 
    1674               0 :     struct acquire_source_image_data *data = malloc (sizeof (*data));
    1675               0 :     if (unlikely (data == NULL))
    1676               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1677               0 :     data->src = src;
    1678               0 :     data->image = image;
    1679               0 :     data->image_extra = image_extra;
    1680                 : 
    1681               0 :     surface = (cairo_image_surface_t*)
    1682               0 :         _cairo_image_surface_create_with_pixman_format (image->data,
    1683                 :                                                         image->pixman_format,
    1684                 :                                                         image->width,
    1685                 :                                                         image->height,
    1686                 :                                                         image->stride);
    1687               0 :     status = surface->base.status;
    1688               0 :     if (status) {
    1689               0 :         free (data);
    1690               0 :         return status;
    1691                 :     }
    1692                 : 
    1693               0 :     status = _cairo_user_data_array_set_data (&surface->base.user_data,
    1694                 :                                               &wrap_image_key,
    1695                 :                                               data,
    1696                 :                                               _wrap_release_source_image);
    1697               0 :     if (status) {
    1698               0 :         cairo_surface_destroy (&surface->base);
    1699               0 :         free (data);
    1700               0 :         return status;
    1701                 :     }
    1702                 : 
    1703               0 :     pixman_image_set_component_alpha (
    1704                 :         surface->pixman_image,
    1705                 :         pixman_image_get_component_alpha (image->pixman_image));
    1706                 : 
    1707               0 :     *out = surface;
    1708               0 :     return CAIRO_STATUS_SUCCESS;
    1709                 : }
    1710                 : 
    1711                 : /**
    1712                 :  * _cairo_surface_clone_similar:
    1713                 :  * @surface: a #cairo_surface_t
    1714                 :  * @src: the source image
    1715                 :  * @src_x: extent for the rectangle in src we actually care about
    1716                 :  * @src_y: extent for the rectangle in src we actually care about
    1717                 :  * @width: extent for the rectangle in src we actually care about
    1718                 :  * @height: extent for the rectangle in src we actually care about
    1719                 :  * @clone_out: location to store a surface compatible with @surface
    1720                 :  *   and with contents identical to @src. The caller must call
    1721                 :  *   cairo_surface_destroy() on the result.
    1722                 :  *
    1723                 :  * Creates a surface with contents identical to @src but that
    1724                 :  *   can be used efficiently with @surface. If @surface and @src are
    1725                 :  *   already compatible then it may return a new reference to @src.
    1726                 :  *
    1727                 :  * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored
    1728                 :  *   in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another
    1729                 :  *   error like %CAIRO_STATUS_NO_MEMORY.
    1730                 :  **/
    1731                 : cairo_status_t
    1732               0 : _cairo_surface_clone_similar (cairo_surface_t  *surface,
    1733                 :                               cairo_surface_t  *src,
    1734                 :                               int               src_x,
    1735                 :                               int               src_y,
    1736                 :                               int               width,
    1737                 :                               int               height,
    1738                 :                               int              *clone_offset_x,
    1739                 :                               int              *clone_offset_y,
    1740                 :                               cairo_surface_t **clone_out)
    1741                 : {
    1742               0 :     cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
    1743                 :     cairo_image_surface_t *image;
    1744                 :     void *image_extra;
    1745                 : 
    1746               0 :     if (unlikely (surface->status))
    1747               0 :         return surface->status;
    1748                 : 
    1749               0 :     if (unlikely (surface->finished))
    1750               0 :         return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
    1751                 : 
    1752                 : #if CAIRO_HAS_TEE_SURFACE
    1753                 : 
    1754               0 :     if (src->type == CAIRO_SURFACE_TYPE_TEE) {
    1755                 :         cairo_surface_t *match;
    1756                 : 
    1757               0 :         match = _cairo_tee_surface_find_match (src,
    1758                 :                                                surface->backend,
    1759                 :                                                src->content);
    1760               0 :         if (match != NULL)
    1761               0 :             src = match;
    1762                 :     }
    1763                 : 
    1764                 : #endif
    1765                 : 
    1766               0 :     if (surface->backend->clone_similar != NULL) {
    1767               0 :         status = surface->backend->clone_similar (surface, src,
    1768                 :                                                   src_x, src_y,
    1769                 :                                                   width, height,
    1770                 :                                                   clone_offset_x,
    1771                 :                                                   clone_offset_y,
    1772                 :                                                   clone_out);
    1773               0 :         if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
    1774               0 :             if (_cairo_surface_is_image (src))
    1775               0 :                 return CAIRO_INT_STATUS_UNSUPPORTED;
    1776                 : 
    1777                 :             /* First check to see if we can replay to a similar surface */
    1778               0 :             if (_cairo_surface_is_recording (src)) {
    1779               0 :                 return _cairo_recording_surface_clone_similar (surface, src,
    1780                 :                                                                src_x, src_y,
    1781                 :                                                                width, height,
    1782                 :                                                                clone_offset_x,
    1783                 :                                                                clone_offset_y,
    1784                 :                                                                clone_out);
    1785                 :             }
    1786                 : 
    1787                 :             /* If we failed, try again with an image surface */
    1788               0 :             status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
    1789               0 :             if (status == CAIRO_STATUS_SUCCESS) {
    1790               0 :                 status = _wrap_image(src, image, image_extra, &image);
    1791               0 :                 if (status != CAIRO_STATUS_SUCCESS) {
    1792               0 :                     _cairo_surface_release_source_image (src, image, image_extra);
    1793                 :                 } else {
    1794               0 :                     status =
    1795               0 :                         surface->backend->clone_similar (surface, &image->base,
    1796                 :                                                          src_x, src_y,
    1797                 :                                                          width, height,
    1798                 :                                                          clone_offset_x,
    1799                 :                                                          clone_offset_y,
    1800                 :                                                          clone_out);
    1801               0 :                     cairo_surface_destroy(&image->base);
    1802                 :                 }
    1803                 :             }
    1804                 :         }
    1805                 :     }
    1806                 : 
    1807                 :     /* If we're still unsupported, hit our fallback path to get a clone */
    1808               0 :     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
    1809               0 :         status =
    1810                 :             _cairo_surface_fallback_clone_similar (surface, src,
    1811                 :                                                    src_x, src_y,
    1812                 :                                                    width, height,
    1813                 :                                                    clone_offset_x,
    1814                 :                                                    clone_offset_y,
    1815                 :                                                    clone_out);
    1816                 :     }
    1817                 : 
    1818               0 :     if (unlikely (status))
    1819               0 :         return status;
    1820                 : 
    1821                 :     /* Update the clone's device_transform (which the underlying surface
    1822                 :      * backend knows nothing about) */
    1823               0 :     if (*clone_out != src) {
    1824               0 :         (*clone_out)->device_transform = src->device_transform;
    1825               0 :         (*clone_out)->device_transform_inverse = src->device_transform_inverse;
    1826                 :     }
    1827                 : 
    1828               0 :     return status;
    1829                 : }
    1830                 : 
    1831                 : /**
    1832                 :  * _cairo_surface_is_similar
    1833                 :  * @surface_a: a #cairo_surface_t
    1834                 :  * @surface_b: a #cairo_surface_t
    1835                 :  * @content: a #cairo_content_t
    1836                 :  *
    1837                 :  * Find out whether the given surfaces share the same backend,
    1838                 :  * and if so, whether they can be considered similar.
    1839                 :  *
    1840                 :  * The definition of "similar" depends on the backend. In
    1841                 :  * general, it means that the surface is equivalent to one
    1842                 :  * that would have been generated by a call to cairo_surface_create_similar().
    1843                 :  *
    1844                 :  * Return value: %TRUE if the surfaces are similar.
    1845                 :  **/
    1846                 : cairo_bool_t
    1847               0 : _cairo_surface_is_similar (cairo_surface_t *surface_a,
    1848                 :                            cairo_surface_t *surface_b)
    1849                 : {
    1850               0 :     if (surface_a->backend != surface_b->backend)
    1851               0 :         return FALSE;
    1852                 : 
    1853               0 :     if (surface_a->backend->is_similar != NULL)
    1854               0 :         return surface_a->backend->is_similar (surface_a, surface_b);
    1855                 : 
    1856               0 :     return TRUE;
    1857                 : }
    1858                 : 
    1859                 : cairo_status_t
    1860               0 : _cairo_surface_composite (cairo_operator_t      op,
    1861                 :                           const cairo_pattern_t *src,
    1862                 :                           const cairo_pattern_t *mask,
    1863                 :                           cairo_surface_t       *dst,
    1864                 :                           int                   src_x,
    1865                 :                           int                   src_y,
    1866                 :                           int                   mask_x,
    1867                 :                           int                   mask_y,
    1868                 :                           int                   dst_x,
    1869                 :                           int                   dst_y,
    1870                 :                           unsigned int          width,
    1871                 :                           unsigned int          height,
    1872                 :                           cairo_region_t        *clip_region)
    1873                 : {
    1874                 :     cairo_int_status_t status;
    1875                 : 
    1876               0 :     if (unlikely (dst->status))
    1877               0 :         return dst->status;
    1878                 : 
    1879               0 :     assert (_cairo_surface_is_writable (dst));
    1880                 : 
    1881               0 :     if (mask) {
    1882                 :         /* These operators aren't interpreted the same way by the backends;
    1883                 :          * they are implemented in terms of other operators in cairo-gstate.c
    1884                 :          */
    1885               0 :         assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
    1886                 :     }
    1887                 : 
    1888               0 :     if (dst->backend->composite) {
    1889               0 :         status = dst->backend->composite (op,
    1890                 :                                           src, mask, dst,
    1891                 :                                           src_x, src_y,
    1892                 :                                           mask_x, mask_y,
    1893                 :                                           dst_x, dst_y,
    1894                 :                                           width, height,
    1895                 :                                           clip_region);
    1896               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    1897               0 :             return _cairo_surface_set_error (dst, status);
    1898                 :     }
    1899                 : 
    1900               0 :     return _cairo_surface_set_error (dst,
    1901                 :             _cairo_surface_fallback_composite (op,
    1902                 :                                               src, mask, dst,
    1903                 :                                               src_x, src_y,
    1904                 :                                               mask_x, mask_y,
    1905                 :                                               dst_x, dst_y,
    1906                 :                                               width, height,
    1907                 :                                               clip_region));
    1908                 : }
    1909                 : 
    1910                 : /**
    1911                 :  * _cairo_surface_fill_rectangle:
    1912                 :  * @surface: a #cairo_surface_t
    1913                 :  * @op: the operator to apply to the rectangle
    1914                 :  * @color: the source color
    1915                 :  * @x: X coordinate of rectangle, in backend coordinates
    1916                 :  * @y: Y coordinate of rectangle, in backend coordinates
    1917                 :  * @width: width of rectangle, in backend coordinates
    1918                 :  * @height: height of rectangle, in backend coordinates
    1919                 :  *
    1920                 :  * Applies an operator to a rectangle using a solid color as the source.
    1921                 :  * See _cairo_surface_fill_rectangles() for full details.
    1922                 :  *
    1923                 :  * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
    1924                 :  **/
    1925                 : cairo_status_t
    1926               0 : _cairo_surface_fill_rectangle (cairo_surface_t     *surface,
    1927                 :                                cairo_operator_t     op,
    1928                 :                                const cairo_color_t *color,
    1929                 :                                int                  x,
    1930                 :                                int                  y,
    1931                 :                                int                  width,
    1932                 :                                int                  height)
    1933                 : {
    1934                 :     cairo_rectangle_int_t rect;
    1935                 : 
    1936               0 :     if (surface->status)
    1937               0 :         return surface->status;
    1938                 : 
    1939               0 :     assert (_cairo_surface_is_writable (surface));
    1940                 : 
    1941               0 :     rect.x = x;
    1942               0 :     rect.y = y;
    1943               0 :     rect.width = width;
    1944               0 :     rect.height = height;
    1945                 : 
    1946               0 :     return _cairo_surface_fill_rectangles (surface, op, color, &rect, 1);
    1947                 : }
    1948                 : 
    1949                 : /**
    1950                 :  * _cairo_surface_fill_region:
    1951                 :  * @surface: a #cairo_surface_t
    1952                 :  * @op: the operator to apply to the region
    1953                 :  * @color: the source color
    1954                 :  * @region: the region to modify, in backend coordinates
    1955                 :  *
    1956                 :  * Applies an operator to a set of rectangles specified as a
    1957                 :  * #cairo_region_t using a solid color as the source.
    1958                 :  * See _cairo_surface_fill_rectangles() for full details.
    1959                 :  *
    1960                 :  * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
    1961                 :  **/
    1962                 : cairo_status_t
    1963               0 : _cairo_surface_fill_region (cairo_surface_t        *surface,
    1964                 :                             cairo_operator_t        op,
    1965                 :                             const cairo_color_t    *color,
    1966                 :                             cairo_region_t         *region)
    1967                 : {
    1968                 :     int num_rects;
    1969                 :     cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
    1970               0 :     cairo_rectangle_int_t *rects = stack_rects;
    1971                 :     cairo_status_t status;
    1972                 :     int i;
    1973                 : 
    1974               0 :     if (surface->status)
    1975               0 :         return surface->status;
    1976                 : 
    1977               0 :     assert (_cairo_surface_is_writable (surface));
    1978                 : 
    1979               0 :     num_rects = cairo_region_num_rectangles (region);
    1980               0 :     if (num_rects == 0)
    1981               0 :         return CAIRO_STATUS_SUCCESS;
    1982                 : 
    1983                 :     /* catch a common reduction of _cairo_clip_combine_with_surface() */
    1984               0 :     if (op == CAIRO_OPERATOR_IN &&
    1985               0 :         _cairo_color_equal (color, CAIRO_COLOR_WHITE))
    1986                 :     {
    1987               0 :         return CAIRO_STATUS_SUCCESS;
    1988                 :     }
    1989                 : 
    1990               0 :     if (num_rects > ARRAY_LENGTH (stack_rects)) {
    1991               0 :         rects = _cairo_malloc_ab (num_rects,
    1992                 :                                   sizeof (cairo_rectangle_int_t));
    1993               0 :         if (rects == NULL) {
    1994               0 :             return _cairo_surface_set_error (surface,
    1995                 :                                              _cairo_error (CAIRO_STATUS_NO_MEMORY));
    1996                 :         }
    1997                 :     }
    1998                 : 
    1999               0 :     for (i = 0; i < num_rects; i++)
    2000               0 :         cairo_region_get_rectangle (region, i, &rects[i]);
    2001                 : 
    2002               0 :     status =  _cairo_surface_fill_rectangles (surface,
    2003                 :                                               op, color, rects, num_rects);
    2004                 : 
    2005               0 :     if (rects != stack_rects)
    2006               0 :         free (rects);
    2007                 : 
    2008               0 :     return _cairo_surface_set_error (surface, status);
    2009                 : }
    2010                 : 
    2011                 : /**
    2012                 :  * _cairo_surface_fill_rectangles:
    2013                 :  * @surface: a #cairo_surface_t
    2014                 :  * @op: the operator to apply to the region
    2015                 :  * @color: the source color
    2016                 :  * @rects: the rectangles to modify, in backend coordinates
    2017                 :  * @num_rects: the number of rectangles in @rects
    2018                 :  *
    2019                 :  * Applies an operator to a set of rectangles using a solid color
    2020                 :  * as the source. Note that even if the operator is an unbounded operator
    2021                 :  * such as %CAIRO_OPERATOR_IN, only the given set of rectangles
    2022                 :  * is affected. This differs from _cairo_surface_composite_trapezoids()
    2023                 :  * where the entire destination rectangle is cleared.
    2024                 :  *
    2025                 :  * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
    2026                 :  **/
    2027                 : cairo_status_t
    2028               0 : _cairo_surface_fill_rectangles (cairo_surface_t         *surface,
    2029                 :                                 cairo_operator_t         op,
    2030                 :                                 const cairo_color_t     *color,
    2031                 :                                 cairo_rectangle_int_t   *rects,
    2032                 :                                 int                      num_rects)
    2033                 : {
    2034                 :     cairo_int_status_t status;
    2035                 : 
    2036               0 :     if (surface->status)
    2037               0 :         return surface->status;
    2038                 : 
    2039               0 :     assert (_cairo_surface_is_writable (surface));
    2040                 : 
    2041               0 :     if (num_rects == 0)
    2042               0 :         return CAIRO_STATUS_SUCCESS;
    2043                 : 
    2044               0 :     if (surface->backend->fill_rectangles) {
    2045               0 :         status = surface->backend->fill_rectangles (surface,
    2046                 :                                                     op, color,
    2047                 :                                                     rects, num_rects);
    2048               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2049               0 :             return _cairo_surface_set_error (surface, status);
    2050                 :     }
    2051                 : 
    2052               0 :     return _cairo_surface_set_error (surface,
    2053                 :             _cairo_surface_fallback_fill_rectangles (surface,
    2054                 :                                                      op, color,
    2055                 :                                                      rects, num_rects));
    2056                 : }
    2057                 : 
    2058                 : static cairo_status_t
    2059              64 : _pattern_has_error (const cairo_pattern_t *pattern)
    2060                 : {
    2061                 :     const cairo_surface_pattern_t *spattern;
    2062                 : 
    2063              64 :     if (unlikely (pattern->status))
    2064               0 :         return pattern->status;
    2065                 : 
    2066              64 :     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
    2067              17 :         return CAIRO_STATUS_SUCCESS;
    2068                 : 
    2069              47 :     spattern = (const cairo_surface_pattern_t *) pattern;
    2070              47 :     if (unlikely (spattern->surface->status))
    2071               0 :         return spattern->surface->status;
    2072                 : 
    2073              47 :     if (unlikely (spattern->surface->finished))
    2074               0 :         return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
    2075                 : 
    2076              47 :     return CAIRO_STATUS_SUCCESS;
    2077                 : }
    2078                 : 
    2079                 : cairo_status_t
    2080              64 : _cairo_surface_paint (cairo_surface_t   *surface,
    2081                 :                       cairo_operator_t   op,
    2082                 :                       const cairo_pattern_t *source,
    2083                 :                       cairo_clip_t          *clip)
    2084                 : {
    2085                 :     cairo_status_t status;
    2086                 : 
    2087              64 :     if (unlikely (surface->status))
    2088               0 :         return surface->status;
    2089                 : 
    2090              64 :     if (clip && clip->all_clipped)
    2091               0 :         return CAIRO_STATUS_SUCCESS;
    2092                 : 
    2093              64 :     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
    2094               0 :         return CAIRO_STATUS_SUCCESS;
    2095                 : 
    2096              64 :     if (op == CAIRO_OPERATOR_OVER &&
    2097               0 :         _cairo_pattern_is_clear (source))
    2098                 :     {
    2099               0 :         return CAIRO_STATUS_SUCCESS;
    2100                 :     }
    2101                 : 
    2102              64 :     status = _pattern_has_error (source);
    2103              64 :     if (unlikely (status))
    2104               0 :         return status;
    2105                 : 
    2106              64 :     _cairo_surface_begin_modification (surface);
    2107                 : 
    2108              64 :     if (surface->backend->paint != NULL) {
    2109              64 :         status = surface->backend->paint (surface, op, source, clip);
    2110              64 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2111              64 :             goto FINISH;
    2112                 :     }
    2113                 : 
    2114               0 :     status = _cairo_surface_fallback_paint (surface, op, source, clip);
    2115                 : 
    2116                 :  FINISH:
    2117              64 :     surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
    2118                 : 
    2119              64 :     return _cairo_surface_set_error (surface, status);
    2120                 : }
    2121                 : 
    2122                 : cairo_status_t
    2123               0 : _cairo_surface_mask (cairo_surface_t            *surface,
    2124                 :                      cairo_operator_t            op,
    2125                 :                      const cairo_pattern_t      *source,
    2126                 :                      const cairo_pattern_t      *mask,
    2127                 :                      cairo_clip_t               *clip)
    2128                 : {
    2129                 :     cairo_status_t status;
    2130                 : 
    2131               0 :     if (unlikely (surface->status))
    2132               0 :         return surface->status;
    2133                 : 
    2134               0 :     if (clip && clip->all_clipped)
    2135               0 :         return CAIRO_STATUS_SUCCESS;
    2136                 : 
    2137               0 :     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
    2138               0 :         return CAIRO_STATUS_SUCCESS;
    2139                 : 
    2140                 :     /* If the mask is blank, this is just an expensive no-op */
    2141               0 :     if (_cairo_pattern_is_clear (mask) &&
    2142               0 :         _cairo_operator_bounded_by_mask (op))
    2143                 :     {
    2144               0 :         return CAIRO_STATUS_SUCCESS;
    2145                 :     }
    2146                 : 
    2147               0 :     if (op == CAIRO_OPERATOR_OVER &&
    2148               0 :         _cairo_pattern_is_clear (source))
    2149                 :     {
    2150               0 :         return CAIRO_STATUS_SUCCESS;
    2151                 :     }
    2152                 : 
    2153               0 :     status = _pattern_has_error (source);
    2154               0 :     if (unlikely (status))
    2155               0 :         return status;
    2156                 : 
    2157               0 :     status = _pattern_has_error (mask);
    2158               0 :     if (unlikely (status))
    2159               0 :         return status;
    2160                 : 
    2161               0 :     _cairo_surface_begin_modification (surface);
    2162                 : 
    2163               0 :     if (surface->backend->mask != NULL) {
    2164               0 :         status = surface->backend->mask (surface, op, source, mask, clip);
    2165               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2166               0 :             goto FINISH;
    2167                 :     }
    2168                 : 
    2169               0 :     status = _cairo_surface_fallback_mask (surface, op, source, mask, clip);
    2170                 : 
    2171                 :  FINISH:
    2172               0 :     surface->is_clear = FALSE;
    2173                 : 
    2174               0 :     return _cairo_surface_set_error (surface, status);
    2175                 : }
    2176                 : 
    2177                 : cairo_status_t
    2178               0 : _cairo_surface_fill_stroke (cairo_surface_t         *surface,
    2179                 :                             cairo_operator_t         fill_op,
    2180                 :                             const cairo_pattern_t   *fill_source,
    2181                 :                             cairo_fill_rule_t        fill_rule,
    2182                 :                             double                   fill_tolerance,
    2183                 :                             cairo_antialias_t        fill_antialias,
    2184                 :                             cairo_path_fixed_t      *path,
    2185                 :                             cairo_operator_t         stroke_op,
    2186                 :                             const cairo_pattern_t   *stroke_source,
    2187                 :                             const cairo_stroke_style_t    *stroke_style,
    2188                 :                             const cairo_matrix_t            *stroke_ctm,
    2189                 :                             const cairo_matrix_t            *stroke_ctm_inverse,
    2190                 :                             double                   stroke_tolerance,
    2191                 :                             cairo_antialias_t        stroke_antialias,
    2192                 :                             cairo_clip_t            *clip)
    2193                 : {
    2194                 :     cairo_status_t status;
    2195                 : 
    2196               0 :     if (unlikely (surface->status))
    2197               0 :         return surface->status;
    2198                 : 
    2199               0 :     if (clip && clip->all_clipped)
    2200               0 :         return CAIRO_STATUS_SUCCESS;
    2201                 : 
    2202               0 :     if (surface->is_clear &&
    2203               0 :         fill_op == CAIRO_OPERATOR_CLEAR &&
    2204                 :         stroke_op == CAIRO_OPERATOR_CLEAR)
    2205                 :     {
    2206               0 :         return CAIRO_STATUS_SUCCESS;
    2207                 :     }
    2208                 : 
    2209               0 :     status = _pattern_has_error (fill_source);
    2210               0 :     if (unlikely (status))
    2211               0 :         return status;
    2212                 : 
    2213               0 :     status = _pattern_has_error (stroke_source);
    2214               0 :     if (unlikely (status))
    2215               0 :         return status;
    2216                 : 
    2217               0 :     _cairo_surface_begin_modification (surface);
    2218                 : 
    2219               0 :     if (surface->backend->fill_stroke) {
    2220               0 :         cairo_matrix_t dev_ctm = *stroke_ctm;
    2221               0 :         cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
    2222                 : 
    2223               0 :         status = surface->backend->fill_stroke (surface,
    2224                 :                                                 fill_op, fill_source, fill_rule,
    2225                 :                                                 fill_tolerance, fill_antialias,
    2226                 :                                                 path,
    2227                 :                                                 stroke_op, stroke_source,
    2228                 :                                                 stroke_style,
    2229                 :                                                 &dev_ctm, &dev_ctm_inverse,
    2230                 :                                                 stroke_tolerance, stroke_antialias,
    2231                 :                                                 clip);
    2232                 : 
    2233               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2234               0 :             goto FINISH;
    2235                 :     }
    2236                 : 
    2237               0 :     status = _cairo_surface_fill (surface, fill_op, fill_source, path,
    2238                 :                                   fill_rule, fill_tolerance, fill_antialias,
    2239                 :                                   clip);
    2240               0 :     if (unlikely (status))
    2241               0 :         goto FINISH;
    2242                 : 
    2243               0 :     status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
    2244                 :                                     stroke_style, stroke_ctm, stroke_ctm_inverse,
    2245                 :                                     stroke_tolerance, stroke_antialias,
    2246                 :                                     clip);
    2247               0 :     if (unlikely (status))
    2248               0 :         goto FINISH;
    2249                 : 
    2250                 :   FINISH:
    2251               0 :     surface->is_clear = FALSE;
    2252                 : 
    2253               0 :     return _cairo_surface_set_error (surface, status);
    2254                 : }
    2255                 : 
    2256                 : cairo_status_t
    2257               0 : _cairo_surface_stroke (cairo_surface_t          *surface,
    2258                 :                        cairo_operator_t          op,
    2259                 :                        const cairo_pattern_t    *source,
    2260                 :                        cairo_path_fixed_t       *path,
    2261                 :                        const cairo_stroke_style_t       *stroke_style,
    2262                 :                        const cairo_matrix_t             *ctm,
    2263                 :                        const cairo_matrix_t             *ctm_inverse,
    2264                 :                        double                    tolerance,
    2265                 :                        cairo_antialias_t         antialias,
    2266                 :                        cairo_clip_t             *clip)
    2267                 : {
    2268                 :     cairo_status_t status;
    2269                 : 
    2270               0 :     if (unlikely (surface->status))
    2271               0 :         return surface->status;
    2272                 : 
    2273               0 :     if (clip && clip->all_clipped)
    2274               0 :         return CAIRO_STATUS_SUCCESS;
    2275                 : 
    2276               0 :     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
    2277               0 :         return CAIRO_STATUS_SUCCESS;
    2278                 : 
    2279               0 :     if (op == CAIRO_OPERATOR_OVER &&
    2280               0 :         _cairo_pattern_is_clear (source))
    2281                 :     {
    2282               0 :         return CAIRO_STATUS_SUCCESS;
    2283                 :     }
    2284                 : 
    2285               0 :     status = _pattern_has_error (source);
    2286               0 :     if (unlikely (status))
    2287               0 :         return status;
    2288                 : 
    2289               0 :     _cairo_surface_begin_modification (surface);
    2290                 : 
    2291               0 :     if (surface->backend->stroke != NULL) {
    2292               0 :         status = surface->backend->stroke (surface, op, source,
    2293                 :                                            path, stroke_style,
    2294                 :                                            ctm, ctm_inverse,
    2295                 :                                            tolerance, antialias,
    2296                 :                                            clip);
    2297                 : 
    2298               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2299               0 :             goto FINISH;
    2300                 :     }
    2301                 : 
    2302               0 :     status = _cairo_surface_fallback_stroke (surface, op, source,
    2303                 :                                              path, stroke_style,
    2304                 :                                              ctm, ctm_inverse,
    2305                 :                                              tolerance, antialias,
    2306                 :                                              clip);
    2307                 : 
    2308                 :  FINISH:
    2309               0 :     surface->is_clear = FALSE;
    2310                 : 
    2311               0 :     return _cairo_surface_set_error (surface, status);
    2312                 : }
    2313                 : 
    2314                 : cairo_status_t
    2315               0 : _cairo_surface_fill (cairo_surface_t    *surface,
    2316                 :                      cairo_operator_t    op,
    2317                 :                      const cairo_pattern_t *source,
    2318                 :                      cairo_path_fixed_t *path,
    2319                 :                      cairo_fill_rule_t   fill_rule,
    2320                 :                      double              tolerance,
    2321                 :                      cairo_antialias_t   antialias,
    2322                 :                      cairo_clip_t       *clip)
    2323                 : {
    2324                 :     cairo_status_t status;
    2325                 : 
    2326               0 :     if (unlikely (surface->status))
    2327               0 :         return surface->status;
    2328                 : 
    2329               0 :     if (clip && clip->all_clipped)
    2330               0 :         return CAIRO_STATUS_SUCCESS;
    2331                 : 
    2332               0 :     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
    2333               0 :         return CAIRO_STATUS_SUCCESS;
    2334                 : 
    2335               0 :     if (op == CAIRO_OPERATOR_OVER &&
    2336               0 :         _cairo_pattern_is_clear (source))
    2337                 :     {
    2338               0 :         return CAIRO_STATUS_SUCCESS;
    2339                 :     }
    2340                 : 
    2341               0 :     status = _pattern_has_error (source);
    2342               0 :     if (unlikely (status))
    2343               0 :         return status;
    2344                 : 
    2345               0 :     _cairo_surface_begin_modification (surface);
    2346                 : 
    2347               0 :     if (surface->backend->fill != NULL) {
    2348               0 :         status = surface->backend->fill (surface, op, source,
    2349                 :                                          path, fill_rule,
    2350                 :                                          tolerance, antialias,
    2351                 :                                          clip);
    2352                 : 
    2353               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2354               0 :             goto FINISH;
    2355                 :     }
    2356                 : 
    2357               0 :     status = _cairo_surface_fallback_fill (surface, op, source,
    2358                 :                                            path, fill_rule,
    2359                 :                                            tolerance, antialias,
    2360                 :                                            clip);
    2361                 : 
    2362                 :  FINISH:
    2363               0 :     surface->is_clear = FALSE;
    2364                 : 
    2365               0 :     return _cairo_surface_set_error (surface, status);
    2366                 : }
    2367                 : 
    2368                 : cairo_status_t
    2369               0 : _cairo_surface_composite_trapezoids (cairo_operator_t           op,
    2370                 :                                      const cairo_pattern_t      *pattern,
    2371                 :                                      cairo_surface_t            *dst,
    2372                 :                                      cairo_antialias_t          antialias,
    2373                 :                                      int                        src_x,
    2374                 :                                      int                        src_y,
    2375                 :                                      int                        dst_x,
    2376                 :                                      int                        dst_y,
    2377                 :                                      unsigned int               width,
    2378                 :                                      unsigned int               height,
    2379                 :                                      cairo_trapezoid_t          *traps,
    2380                 :                                      int                        num_traps,
    2381                 :                                      cairo_region_t             *clip_region)
    2382                 : {
    2383                 :     cairo_int_status_t status;
    2384                 : 
    2385               0 :     if (dst->status)
    2386               0 :         return dst->status;
    2387                 : 
    2388               0 :     assert (_cairo_surface_is_writable (dst));
    2389                 : 
    2390                 :     /* These operators aren't interpreted the same way by the backends;
    2391                 :      * they are implemented in terms of other operators in cairo-gstate.c
    2392                 :      */
    2393               0 :     assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
    2394                 : 
    2395               0 :     if (dst->backend->composite_trapezoids) {
    2396               0 :         status = dst->backend->composite_trapezoids (op,
    2397                 :                                                      pattern, dst,
    2398                 :                                                      antialias,
    2399                 :                                                      src_x, src_y,
    2400                 :                                                      dst_x, dst_y,
    2401                 :                                                      width, height,
    2402                 :                                                      traps, num_traps,
    2403                 :                                                      clip_region);
    2404               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2405               0 :             return _cairo_surface_set_error (dst, status);
    2406                 :     }
    2407                 : 
    2408               0 :     return  _cairo_surface_set_error (dst,
    2409                 :             _cairo_surface_fallback_composite_trapezoids (op, pattern, dst,
    2410                 :                                                           antialias,
    2411                 :                                                           src_x, src_y,
    2412                 :                                                           dst_x, dst_y,
    2413                 :                                                           width, height,
    2414                 :                                                           traps, num_traps,
    2415                 :                                                           clip_region));
    2416                 : }
    2417                 : 
    2418                 : cairo_span_renderer_t *
    2419               0 : _cairo_surface_create_span_renderer (cairo_operator_t            op,
    2420                 :                                      const cairo_pattern_t      *pattern,
    2421                 :                                      cairo_surface_t            *dst,
    2422                 :                                      cairo_antialias_t           antialias,
    2423                 :                                      const cairo_composite_rectangles_t *rects,
    2424                 :                                      cairo_region_t             *clip_region)
    2425                 : {
    2426               0 :     assert (dst->snapshot_of == NULL);
    2427                 : 
    2428               0 :     if (unlikely (dst->status))
    2429               0 :         return _cairo_span_renderer_create_in_error (dst->status);
    2430                 : 
    2431               0 :     if (unlikely (dst->finished))
    2432               0 :         return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
    2433                 : 
    2434               0 :     if (dst->backend->create_span_renderer) {
    2435               0 :         return dst->backend->create_span_renderer (op,
    2436                 :                                                    pattern, dst,
    2437                 :                                                    antialias,
    2438                 :                                                    rects,
    2439                 :                                                    clip_region);
    2440                 :     }
    2441               0 :     ASSERT_NOT_REACHED;
    2442               0 :     return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED);
    2443                 : }
    2444                 : 
    2445                 : cairo_bool_t
    2446               0 : _cairo_surface_check_span_renderer (cairo_operator_t             op,
    2447                 :                                     const cairo_pattern_t       *pattern,
    2448                 :                                     cairo_surface_t             *dst,
    2449                 :                                     cairo_antialias_t            antialias)
    2450                 : {
    2451               0 :     assert (dst->snapshot_of == NULL);
    2452               0 :     assert (dst->status == CAIRO_STATUS_SUCCESS);
    2453               0 :     assert (! dst->finished);
    2454                 : 
    2455                 :     /* XXX: Currently we have no mono span renderer */
    2456               0 :     if (antialias == CAIRO_ANTIALIAS_NONE)
    2457               0 :         return FALSE;
    2458                 : 
    2459               0 :     if (dst->backend->check_span_renderer != NULL)
    2460               0 :         return dst->backend->check_span_renderer (op, pattern, dst, antialias);
    2461                 : 
    2462               0 :     return FALSE;
    2463                 : }
    2464                 : 
    2465                 : /**
    2466                 :  * cairo_surface_copy_page:
    2467                 :  * @surface: a #cairo_surface_t
    2468                 :  *
    2469                 :  * Emits the current page for backends that support multiple pages,
    2470                 :  * but doesn't clear it, so that the contents of the current page will
    2471                 :  * be retained for the next page.  Use cairo_surface_show_page() if you
    2472                 :  * want to get an empty page after the emission.
    2473                 :  *
    2474                 :  * There is a convenience function for this that takes a #cairo_t,
    2475                 :  * namely cairo_copy_page().
    2476                 :  *
    2477                 :  * Since: 1.6
    2478                 :  */
    2479                 : void
    2480               0 : cairo_surface_copy_page (cairo_surface_t *surface)
    2481                 : {
    2482                 :     cairo_status_t status_ignored;
    2483                 : 
    2484               0 :     if (surface->status)
    2485               0 :         return;
    2486                 : 
    2487               0 :     assert (surface->snapshot_of == NULL);
    2488                 : 
    2489               0 :     if (surface->finished) {
    2490               0 :         status_ignored = _cairo_surface_set_error (surface,
    2491                 :                                                  CAIRO_STATUS_SURFACE_FINISHED);
    2492               0 :         return;
    2493                 :     }
    2494                 : 
    2495                 :     /* It's fine if some backends don't implement copy_page */
    2496               0 :     if (surface->backend->copy_page == NULL)
    2497               0 :         return;
    2498                 : 
    2499               0 :     status_ignored = _cairo_surface_set_error (surface,
    2500               0 :                                          surface->backend->copy_page (surface));
    2501                 : }
    2502                 : slim_hidden_def (cairo_surface_copy_page);
    2503                 : 
    2504                 : /**
    2505                 :  * cairo_surface_show_page:
    2506                 :  * @surface: a #cairo_Surface_t
    2507                 :  *
    2508                 :  * Emits and clears the current page for backends that support multiple
    2509                 :  * pages.  Use cairo_surface_copy_page() if you don't want to clear the page.
    2510                 :  *
    2511                 :  * There is a convenience function for this that takes a #cairo_t,
    2512                 :  * namely cairo_show_page().
    2513                 :  *
    2514                 :  * Since: 1.6
    2515                 :  **/
    2516                 : void
    2517               0 : cairo_surface_show_page (cairo_surface_t *surface)
    2518                 : {
    2519                 :     cairo_status_t status_ignored;
    2520                 : 
    2521               0 :     if (surface->status)
    2522               0 :         return;
    2523                 : 
    2524               0 :     if (surface->finished) {
    2525               0 :         status_ignored = _cairo_surface_set_error (surface,
    2526                 :                                                  CAIRO_STATUS_SURFACE_FINISHED);
    2527               0 :         return;
    2528                 :     }
    2529                 : 
    2530               0 :     _cairo_surface_begin_modification (surface);
    2531                 : 
    2532                 :     /* It's fine if some backends don't implement show_page */
    2533               0 :     if (surface->backend->show_page == NULL)
    2534               0 :         return;
    2535                 : 
    2536               0 :     status_ignored = _cairo_surface_set_error (surface,
    2537               0 :                                          surface->backend->show_page (surface));
    2538                 : }
    2539                 : slim_hidden_def (cairo_surface_show_page);
    2540                 : 
    2541                 : /**
    2542                 :  * _cairo_surface_get_extents:
    2543                 :  * @surface: the #cairo_surface_t to fetch extents for
    2544                 :  *
    2545                 :  * This function returns a bounding box for the surface.  The surface
    2546                 :  * bounds are defined as a region beyond which no rendering will
    2547                 :  * possibly be recorded, in other words, it is the maximum extent of
    2548                 :  * potentially usable coordinates.
    2549                 :  *
    2550                 :  * For vector surfaces, (PDF, PS, SVG and recording-surfaces), the surface
    2551                 :  * might be conceived as unbounded, but we force the user to provide a
    2552                 :  * maximum size at the time of surface_create. So get_extents uses
    2553                 :  * that size.
    2554                 :  *
    2555                 :  * Note: The coordinates returned are in "backend" space rather than
    2556                 :  * "surface" space. That is, they are relative to the true (0,0)
    2557                 :  * origin rather than the device_transform origin. This might seem a
    2558                 :  * bit inconsistent with other #cairo_surface_t interfaces, but all
    2559                 :  * current callers are within the surface layer where backend space is
    2560                 :  * desired.
    2561                 :  *
    2562                 :  * This behavior would have to be changed is we ever exported a public
    2563                 :  * variant of this function.
    2564                 :  */
    2565                 : cairo_bool_t
    2566             115 : _cairo_surface_get_extents (cairo_surface_t         *surface,
    2567                 :                             cairo_rectangle_int_t   *extents)
    2568                 : {
    2569                 :     cairo_bool_t bounded;
    2570                 : 
    2571             115 :     bounded = FALSE;
    2572             115 :     if (surface->backend->get_extents != NULL)
    2573             115 :         bounded = surface->backend->get_extents (surface, extents);
    2574                 : 
    2575             115 :     if (! bounded)
    2576               0 :         _cairo_unbounded_rectangle_init (extents);
    2577                 : 
    2578             115 :     return bounded;
    2579                 : }
    2580                 : 
    2581                 : /**
    2582                 :  * cairo_surface_has_show_text_glyphs:
    2583                 :  * @surface: a #cairo_surface_t
    2584                 :  *
    2585                 :  * Returns whether the surface supports
    2586                 :  * sophisticated cairo_show_text_glyphs() operations.  That is,
    2587                 :  * whether it actually uses the provided text and cluster data
    2588                 :  * to a cairo_show_text_glyphs() call.
    2589                 :  *
    2590                 :  * Note: Even if this function returns %FALSE, a
    2591                 :  * cairo_show_text_glyphs() operation targeted at @surface will
    2592                 :  * still succeed.  It just will
    2593                 :  * act like a cairo_show_glyphs() operation.  Users can use this
    2594                 :  * function to avoid computing UTF-8 text and cluster mapping if the
    2595                 :  * target surface does not use it.
    2596                 :  *
    2597                 :  * Return value: %TRUE if @surface supports
    2598                 :  *               cairo_show_text_glyphs(), %FALSE otherwise
    2599                 :  *
    2600                 :  * Since: 1.8
    2601                 :  **/
    2602                 : cairo_bool_t
    2603               0 : cairo_surface_has_show_text_glyphs (cairo_surface_t         *surface)
    2604                 : {
    2605                 :     cairo_status_t status_ignored;
    2606                 : 
    2607               0 :     if (surface->status)
    2608               0 :         return FALSE;
    2609                 : 
    2610               0 :     if (surface->finished) {
    2611               0 :         status_ignored = _cairo_surface_set_error (surface,
    2612                 :                                                    CAIRO_STATUS_SURFACE_FINISHED);
    2613               0 :         return FALSE;
    2614                 :     }
    2615                 : 
    2616               0 :     if (surface->backend->has_show_text_glyphs)
    2617               0 :         return surface->backend->has_show_text_glyphs (surface);
    2618                 :     else
    2619               0 :         return surface->backend->show_text_glyphs != NULL;
    2620                 : }
    2621                 : slim_hidden_def (cairo_surface_has_show_text_glyphs);
    2622                 : 
    2623                 : /**
    2624                 :  * cairo_surface_set_subpixel_antialiasing:
    2625                 :  * @surface: a #cairo_surface_t
    2626                 :  *
    2627                 :  * Sets whether the surface permits subpixel antialiasing. By default,
    2628                 :  * surfaces permit subpixel antialiasing.
    2629                 :  *
    2630                 :  * Enabling subpixel antialiasing for CONTENT_COLOR_ALPHA surfaces generally
    2631                 :  * requires that the pixels in the areas under a subpixel antialiasing
    2632                 :  * operation already be opaque.
    2633                 :  *
    2634                 :  * Since: 1.12
    2635                 :  **/
    2636                 : void
    2637              51 : cairo_surface_set_subpixel_antialiasing (cairo_surface_t *surface,
    2638                 :                                          cairo_subpixel_antialiasing_t enabled)
    2639                 : {
    2640              51 :     if (surface->status)
    2641               0 :         return;
    2642                 : 
    2643              51 :     if (surface->finished) {
    2644               0 :         _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
    2645               0 :         return;
    2646                 :     }
    2647                 : 
    2648              51 :     surface->permit_subpixel_antialiasing =
    2649              51 :         enabled == CAIRO_SUBPIXEL_ANTIALIASING_ENABLED;
    2650                 : }
    2651                 : slim_hidden_def (cairo_surface_set_subpixel_antialiasing);
    2652                 : 
    2653                 : /**
    2654                 :  * cairo_surface_get_subpixel_antialiasing:
    2655                 :  * @surface: a #cairo_surface_t
    2656                 :  *
    2657                 :  * Gets whether the surface supports subpixel antialiasing. By default,
    2658                 :  * CAIRO_CONTENT_COLOR surfaces support subpixel antialiasing but other
    2659                 :  * surfaces do not.
    2660                 :  *
    2661                 :  * Since: 1.12
    2662                 :  **/
    2663                 : cairo_subpixel_antialiasing_t
    2664               0 : cairo_surface_get_subpixel_antialiasing (cairo_surface_t *surface)
    2665                 : {
    2666               0 :     if (surface->status)
    2667               0 :         return CAIRO_SUBPIXEL_ANTIALIASING_DISABLED;
    2668                 : 
    2669               0 :     return surface->permit_subpixel_antialiasing ?
    2670               0 :         CAIRO_SUBPIXEL_ANTIALIASING_ENABLED : CAIRO_SUBPIXEL_ANTIALIASING_DISABLED;
    2671                 : }
    2672                 : slim_hidden_def (cairo_surface_get_subpixel_antialiasing);
    2673                 : 
    2674                 : /* Note: the backends may modify the contents of the glyph array as long as
    2675                 :  * they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to
    2676                 :  * avoid copying the array again and again, and edit it in-place.
    2677                 :  * Backends are in fact free to use the array as a generic buffer as they
    2678                 :  * see fit.
    2679                 :  *
    2680                 :  * For show_glyphs backend method, and NOT for show_text_glyphs method,
    2681                 :  * when they do return UNSUPPORTED, they may adjust remaining_glyphs to notify
    2682                 :  * that they have successfully rendered some of the glyphs (from the beginning
    2683                 :  * of the array), but not all.  If they don't touch remaining_glyphs, it
    2684                 :  * defaults to all glyphs.
    2685                 :  *
    2686                 :  * See commits 5a9642c5746fd677aed35ce620ce90b1029b1a0c and
    2687                 :  * 1781e6018c17909311295a9cc74b70500c6b4d0a for the rationale.
    2688                 :  */
    2689                 : cairo_status_t
    2690               0 : _cairo_surface_show_text_glyphs (cairo_surface_t            *surface,
    2691                 :                                  cairo_operator_t            op,
    2692                 :                                  const cairo_pattern_t      *source,
    2693                 :                                  const char                 *utf8,
    2694                 :                                  int                         utf8_len,
    2695                 :                                  cairo_glyph_t              *glyphs,
    2696                 :                                  int                         num_glyphs,
    2697                 :                                  const cairo_text_cluster_t *clusters,
    2698                 :                                  int                         num_clusters,
    2699                 :                                  cairo_text_cluster_flags_t  cluster_flags,
    2700                 :                                  cairo_scaled_font_t        *scaled_font,
    2701                 :                                  cairo_clip_t               *clip)
    2702                 : {
    2703                 :     cairo_status_t status;
    2704               0 :     cairo_scaled_font_t *dev_scaled_font = scaled_font;
    2705                 : 
    2706               0 :     if (unlikely (surface->status))
    2707               0 :         return surface->status;
    2708                 : 
    2709               0 :     if (num_glyphs == 0 && utf8_len == 0)
    2710               0 :         return CAIRO_STATUS_SUCCESS;
    2711                 : 
    2712               0 :     if (clip && clip->all_clipped)
    2713               0 :         return CAIRO_STATUS_SUCCESS;
    2714                 : 
    2715               0 :     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
    2716               0 :         return CAIRO_STATUS_SUCCESS;
    2717                 : 
    2718               0 :     status = _pattern_has_error (source);
    2719               0 :     if (unlikely (status))
    2720               0 :         return status;
    2721                 : 
    2722               0 :     _cairo_surface_begin_modification (surface);
    2723                 : 
    2724               0 :     if (_cairo_surface_has_device_transform (surface) &&
    2725               0 :         ! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
    2726                 :     {
    2727                 :         cairo_font_options_t font_options;
    2728                 :         cairo_matrix_t dev_ctm, font_matrix;
    2729                 : 
    2730               0 :         cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
    2731               0 :         cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
    2732               0 :         cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
    2733               0 :         cairo_scaled_font_get_font_options (scaled_font, &font_options);
    2734               0 :         dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font),
    2735                 :                                                     &font_matrix,
    2736                 :                                                     &dev_ctm,
    2737                 :                                                     &font_options);
    2738                 :     }
    2739               0 :     status = cairo_scaled_font_status (dev_scaled_font);
    2740               0 :     if (unlikely (status))
    2741               0 :         return _cairo_surface_set_error (surface, status);
    2742                 : 
    2743               0 :     status = CAIRO_INT_STATUS_UNSUPPORTED;
    2744                 : 
    2745                 :     /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
    2746                 :      * show_text_glyphs.  Keep in synch. */
    2747               0 :     if (clusters) {
    2748                 :         /* A real show_text_glyphs call.  Try show_text_glyphs backend
    2749                 :          * method first */
    2750               0 :         if (surface->backend->show_text_glyphs != NULL) {
    2751               0 :             status = surface->backend->show_text_glyphs (surface, op,
    2752                 :                                                          source,
    2753                 :                                                          utf8, utf8_len,
    2754                 :                                                          glyphs, num_glyphs,
    2755                 :                                                          clusters, num_clusters, cluster_flags,
    2756                 :                                                          dev_scaled_font,
    2757                 :                                                          clip);
    2758                 :         }
    2759               0 :         if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
    2760               0 :             surface->backend->show_glyphs)
    2761                 :         {
    2762               0 :             int remaining_glyphs = num_glyphs;
    2763               0 :             status = surface->backend->show_glyphs (surface, op,
    2764                 :                                                     source,
    2765                 :                                                     glyphs, num_glyphs,
    2766                 :                                                     dev_scaled_font,
    2767                 :                                                     clip,
    2768                 :                                                     &remaining_glyphs);
    2769               0 :             glyphs += num_glyphs - remaining_glyphs;
    2770               0 :             num_glyphs = remaining_glyphs;
    2771               0 :             if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
    2772               0 :                 status = CAIRO_STATUS_SUCCESS;
    2773                 :         }
    2774                 :     } else {
    2775                 :         /* A mere show_glyphs call.  Try show_glyphs backend method first */
    2776               0 :         if (surface->backend->show_glyphs != NULL) {
    2777               0 :             int remaining_glyphs = num_glyphs;
    2778               0 :             status = surface->backend->show_glyphs (surface, op,
    2779                 :                                                     source,
    2780                 :                                                     glyphs, num_glyphs,
    2781                 :                                                     dev_scaled_font,
    2782                 :                                                     clip,
    2783                 :                                                     &remaining_glyphs);
    2784               0 :             glyphs += num_glyphs - remaining_glyphs;
    2785               0 :             num_glyphs = remaining_glyphs;
    2786               0 :             if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
    2787               0 :                 status = CAIRO_STATUS_SUCCESS;
    2788               0 :         } else if (surface->backend->show_text_glyphs != NULL) {
    2789                 :             /* Intentionally only try show_text_glyphs method for show_glyphs
    2790                 :              * calls if backend does not have show_glyphs.  If backend has
    2791                 :              * both methods implemented, we don't fallback from show_glyphs to
    2792                 :              * show_text_glyphs, and hence the backend can assume in its
    2793                 :              * show_text_glyphs call that clusters is not NULL (which also
    2794                 :              * implies that UTF-8 is not NULL, unless the text is
    2795                 :              * zero-length).
    2796                 :              */
    2797               0 :             status = surface->backend->show_text_glyphs (surface, op,
    2798                 :                                                          source,
    2799                 :                                                          utf8, utf8_len,
    2800                 :                                                          glyphs, num_glyphs,
    2801                 :                                                          clusters, num_clusters, cluster_flags,
    2802                 :                                                          dev_scaled_font,
    2803                 :                                                          clip);
    2804                 :         }
    2805                 :     }
    2806                 : 
    2807               0 :     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
    2808               0 :         status = _cairo_surface_fallback_show_glyphs (surface, op,
    2809                 :                                                       source,
    2810                 :                                                       glyphs, num_glyphs,
    2811                 :                                                       dev_scaled_font,
    2812                 :                                                       clip);
    2813                 :     }
    2814                 : 
    2815               0 :     if (dev_scaled_font != scaled_font)
    2816               0 :         cairo_scaled_font_destroy (dev_scaled_font);
    2817                 : 
    2818               0 :     surface->is_clear = FALSE;
    2819                 : 
    2820               0 :     return _cairo_surface_set_error (surface, status);
    2821                 : }
    2822                 : 
    2823                 : /* XXX: Previously, we had a function named _cairo_surface_show_glyphs
    2824                 :  * with not-so-useful semantics. We've now got a
    2825                 :  * _cairo_surface_show_text_glyphs with the proper semantics, and its
    2826                 :  * fallback still uses this old function (which still needs to be
    2827                 :  * cleaned up in terms of both semantics and naming). */
    2828                 : cairo_status_t
    2829               0 : _cairo_surface_old_show_glyphs (cairo_scaled_font_t     *scaled_font,
    2830                 :                                 cairo_operator_t         op,
    2831                 :                                 const cairo_pattern_t   *pattern,
    2832                 :                                 cairo_surface_t         *dst,
    2833                 :                                 int                      source_x,
    2834                 :                                 int                      source_y,
    2835                 :                                 int                      dest_x,
    2836                 :                                 int                      dest_y,
    2837                 :                                 unsigned int             width,
    2838                 :                                 unsigned int             height,
    2839                 :                                 cairo_glyph_t           *glyphs,
    2840                 :                                 int                      num_glyphs,
    2841                 :                                 cairo_region_t          *clip_region)
    2842                 : {
    2843                 :     cairo_status_t status;
    2844                 : 
    2845               0 :     if (dst->status)
    2846               0 :         return dst->status;
    2847                 : 
    2848               0 :     assert (_cairo_surface_is_writable (dst));
    2849                 : 
    2850               0 :     if (dst->backend->old_show_glyphs) {
    2851               0 :         status = dst->backend->old_show_glyphs (scaled_font,
    2852                 :                                                 op, pattern, dst,
    2853                 :                                                 source_x, source_y,
    2854                 :                                                 dest_x, dest_y,
    2855                 :                                                 width, height,
    2856                 :                                                 glyphs, num_glyphs,
    2857                 :                                                 clip_region);
    2858                 :     } else
    2859               0 :         status = CAIRO_INT_STATUS_UNSUPPORTED;
    2860                 : 
    2861               0 :     return _cairo_surface_set_error (dst, status);
    2862                 : }
    2863                 : 
    2864                 : static cairo_status_t
    2865               0 : _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t         *dst,
    2866                 :                                                    cairo_rectangle_int_t   *src_rectangle,
    2867                 :                                                    cairo_rectangle_int_t   *mask_rectangle,
    2868                 :                                                    int                      dst_x,
    2869                 :                                                    int                      dst_y,
    2870                 :                                                    unsigned int             width,
    2871                 :                                                    unsigned int             height,
    2872                 :                                                    cairo_region_t           *clip_region)
    2873                 : {
    2874                 :     cairo_rectangle_int_t dst_rectangle;
    2875                 :     cairo_region_t clear_region;
    2876                 :     cairo_status_t status;
    2877                 : 
    2878                 :     /* The area that was drawn is the area in the destination rectangle but
    2879                 :      * not within the source or the mask.
    2880                 :      */
    2881               0 :     dst_rectangle.x = dst_x;
    2882               0 :     dst_rectangle.y = dst_y;
    2883               0 :     dst_rectangle.width = width;
    2884               0 :     dst_rectangle.height = height;
    2885                 : 
    2886               0 :     _cairo_region_init_rectangle (&clear_region, &dst_rectangle);
    2887                 : 
    2888               0 :     if (clip_region != NULL) {
    2889               0 :         status = cairo_region_intersect (&clear_region, clip_region);
    2890               0 :         if (unlikely (status))
    2891               0 :             goto CLEANUP_REGIONS;
    2892                 :     }
    2893                 : 
    2894               0 :     if (src_rectangle != NULL) {
    2895               0 :         if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle))
    2896               0 :             goto EMPTY;
    2897                 :     }
    2898                 : 
    2899               0 :     if (mask_rectangle != NULL) {
    2900               0 :         if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle))
    2901               0 :             goto EMPTY;
    2902                 :     }
    2903                 : 
    2904                 :     /* Now compute the area that is in dst but not drawn */
    2905               0 :     status = cairo_region_subtract_rectangle (&clear_region, &dst_rectangle);
    2906               0 :     if (unlikely (status) || cairo_region_is_empty (&clear_region))
    2907                 :         goto CLEANUP_REGIONS;
    2908                 : 
    2909                 :   EMPTY:
    2910               0 :     status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
    2911                 :                                          CAIRO_COLOR_TRANSPARENT,
    2912                 :                                          &clear_region);
    2913                 : 
    2914                 :   CLEANUP_REGIONS:
    2915               0 :     _cairo_region_fini (&clear_region);
    2916                 : 
    2917               0 :     return _cairo_surface_set_error (dst, status);
    2918                 : }
    2919                 : 
    2920                 : /**
    2921                 :  * _cairo_surface_composite_fixup_unbounded:
    2922                 :  * @dst: the destination surface
    2923                 :  * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface())
    2924                 :  * @src_width: width of source surface
    2925                 :  * @src_height: height of source surface
    2926                 :  * @mask_attr: mask surface attributes or %NULL if no mask
    2927                 :  * @mask_width: width of mask surface
    2928                 :  * @mask_height: height of mask surface
    2929                 :  * @src_x: @src_x from _cairo_surface_composite()
    2930                 :  * @src_y: @src_y from _cairo_surface_composite()
    2931                 :  * @mask_x: @mask_x from _cairo_surface_composite()
    2932                 :  * @mask_y: @mask_y from _cairo_surface_composite()
    2933                 :  * @dst_x: @dst_x from _cairo_surface_composite()
    2934                 :  * @dst_y: @dst_y from _cairo_surface_composite()
    2935                 :  * @width: @width from _cairo_surface_composite()
    2936                 :  * @height: @height_x from _cairo_surface_composite()
    2937                 :  *
    2938                 :  * Eeek! Too many parameters! This is a helper function to take care of fixing
    2939                 :  * up for bugs in libpixman and RENDER where, when asked to composite an
    2940                 :  * untransformed surface with an unbounded operator (like CLEAR or SOURCE)
    2941                 :  * only the region inside both the source and the mask is affected.
    2942                 :  * This function clears the region that should have been drawn but was wasn't.
    2943                 :  **/
    2944                 : cairo_status_t
    2945               0 : _cairo_surface_composite_fixup_unbounded (cairo_surface_t            *dst,
    2946                 :                                           cairo_surface_attributes_t *src_attr,
    2947                 :                                           int                         src_width,
    2948                 :                                           int                         src_height,
    2949                 :                                           cairo_surface_attributes_t *mask_attr,
    2950                 :                                           int                         mask_width,
    2951                 :                                           int                         mask_height,
    2952                 :                                           int                         src_x,
    2953                 :                                           int                         src_y,
    2954                 :                                           int                         mask_x,
    2955                 :                                           int                         mask_y,
    2956                 :                                           int                         dst_x,
    2957                 :                                           int                         dst_y,
    2958                 :                                           unsigned int                width,
    2959                 :                                           unsigned int                height,
    2960                 :                                           cairo_region_t             *clip_region)
    2961                 : {
    2962                 :     cairo_rectangle_int_t src_tmp, mask_tmp;
    2963               0 :     cairo_rectangle_int_t *src_rectangle = NULL;
    2964               0 :     cairo_rectangle_int_t *mask_rectangle = NULL;
    2965                 : 
    2966               0 :     if (unlikely (dst->status))
    2967               0 :         return dst->status;
    2968                 : 
    2969               0 :     assert (_cairo_surface_is_writable (dst));
    2970                 : 
    2971                 :     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
    2972                 :      * non-repeating sources and masks. Other sources and masks can be ignored.
    2973                 :      */
    2974               0 :     if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
    2975               0 :         src_attr->extend == CAIRO_EXTEND_NONE)
    2976                 :     {
    2977               0 :         src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
    2978               0 :         src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
    2979               0 :         src_tmp.width = src_width;
    2980               0 :         src_tmp.height = src_height;
    2981                 : 
    2982               0 :         src_rectangle = &src_tmp;
    2983                 :     }
    2984                 : 
    2985               0 :     if (mask_attr &&
    2986               0 :         _cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) &&
    2987               0 :         mask_attr->extend == CAIRO_EXTEND_NONE)
    2988                 :     {
    2989               0 :         mask_tmp.x = (dst_x - (mask_x + mask_attr->x_offset));
    2990               0 :         mask_tmp.y = (dst_y - (mask_y + mask_attr->y_offset));
    2991               0 :         mask_tmp.width = mask_width;
    2992               0 :         mask_tmp.height = mask_height;
    2993                 : 
    2994               0 :         mask_rectangle = &mask_tmp;
    2995                 :     }
    2996                 : 
    2997               0 :     return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
    2998                 :                                                               dst_x, dst_y, width, height,
    2999                 :                                                               clip_region);
    3000                 : }
    3001                 : 
    3002                 : /**
    3003                 :  * _cairo_surface_composite_shape_fixup_unbounded:
    3004                 :  * @dst: the destination surface
    3005                 :  * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface())
    3006                 :  * @src_width: width of source surface
    3007                 :  * @src_height: height of source surface
    3008                 :  * @mask_width: width of mask surface
    3009                 :  * @mask_height: height of mask surface
    3010                 :  * @src_x: @src_x from _cairo_surface_composite()
    3011                 :  * @src_y: @src_y from _cairo_surface_composite()
    3012                 :  * @mask_x: @mask_x from _cairo_surface_composite()
    3013                 :  * @mask_y: @mask_y from _cairo_surface_composite()
    3014                 :  * @dst_x: @dst_x from _cairo_surface_composite()
    3015                 :  * @dst_y: @dst_y from _cairo_surface_composite()
    3016                 :  * @width: @width from _cairo_surface_composite()
    3017                 :  * @height: @height_x from _cairo_surface_composite()
    3018                 :  *
    3019                 :  * Like _cairo_surface_composite_fixup_unbounded(), but instead of
    3020                 :  * handling the case where we have a source pattern and a mask
    3021                 :  * pattern, handle the case where we are compositing a source pattern
    3022                 :  * using a mask we create ourselves, as in
    3023                 :  * _cairo_surface_composite_glyphs() or _cairo_surface_composite_trapezoids()
    3024                 :  **/
    3025                 : cairo_status_t
    3026               0 : _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t            *dst,
    3027                 :                                                 cairo_surface_attributes_t *src_attr,
    3028                 :                                                 int                         src_width,
    3029                 :                                                 int                         src_height,
    3030                 :                                                 int                         mask_width,
    3031                 :                                                 int                         mask_height,
    3032                 :                                                 int                         src_x,
    3033                 :                                                 int                         src_y,
    3034                 :                                                 int                         mask_x,
    3035                 :                                                 int                         mask_y,
    3036                 :                                                 int                         dst_x,
    3037                 :                                                 int                         dst_y,
    3038                 :                                                 unsigned int                width,
    3039                 :                                                 unsigned int                height,
    3040                 :                                                 cairo_region_t      *clip_region)
    3041                 : {
    3042               0 :     cairo_rectangle_int_t src_tmp, *src= NULL;
    3043                 :     cairo_rectangle_int_t mask;
    3044                 : 
    3045               0 :     if (dst->status)
    3046               0 :         return dst->status;
    3047                 : 
    3048               0 :     assert (_cairo_surface_is_writable (dst));
    3049                 : 
    3050                 :     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
    3051                 :      * non-repeating sources and masks. Other sources and masks can be ignored.
    3052                 :      */
    3053               0 :     if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
    3054               0 :         src_attr->extend == CAIRO_EXTEND_NONE)
    3055                 :     {
    3056               0 :         src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
    3057               0 :         src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
    3058               0 :         src_tmp.width  = src_width;
    3059               0 :         src_tmp.height = src_height;
    3060                 : 
    3061               0 :         src = &src_tmp;
    3062                 :     }
    3063                 : 
    3064               0 :     mask.x = dst_x - mask_x;
    3065               0 :     mask.y = dst_y - mask_y;
    3066               0 :     mask.width  = mask_width;
    3067               0 :     mask.height = mask_height;
    3068                 : 
    3069               0 :     return _cairo_surface_composite_fixup_unbounded_internal (dst, src, &mask,
    3070                 :                                                               dst_x, dst_y, width, height,
    3071                 :                                                               clip_region);
    3072                 : }
    3073                 : 
    3074                 : /**
    3075                 :  * _cairo_surface_set_resolution
    3076                 :  * @surface: the surface
    3077                 :  * @x_res: x resolution, in dpi
    3078                 :  * @y_res: y resolution, in dpi
    3079                 :  *
    3080                 :  * Set the actual surface resolution of @surface to the given x and y DPI.
    3081                 :  * Mainly used for correctly computing the scale factor when fallback
    3082                 :  * rendering needs to take place in the paginated surface.
    3083                 :  */
    3084                 : void
    3085               0 : _cairo_surface_set_resolution (cairo_surface_t *surface,
    3086                 :                                double x_res,
    3087                 :                                double y_res)
    3088                 : {
    3089               0 :     if (surface->status)
    3090               0 :         return;
    3091                 : 
    3092               0 :     surface->x_resolution = x_res;
    3093               0 :     surface->y_resolution = y_res;
    3094                 : }
    3095                 : 
    3096                 : /* Generic methods for determining operation extents. */
    3097                 : 
    3098                 : static void
    3099               0 : _rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
    3100                 : {
    3101                 :     const cairo_rectangle_int_t *clip_extents;
    3102                 :     cairo_bool_t is_empty;
    3103                 : 
    3104               0 :     clip_extents = NULL;
    3105               0 :     if (clip != NULL)
    3106               0 :         clip_extents = _cairo_clip_get_extents (clip);
    3107                 : 
    3108               0 :     if (clip_extents != NULL)
    3109               0 :         is_empty = _cairo_rectangle_intersect (extents, clip_extents);
    3110               0 : }
    3111                 : 
    3112                 : static void
    3113               0 : _cairo_surface_operation_extents (cairo_surface_t *surface,
    3114                 :                                   cairo_operator_t op,
    3115                 :                                   const cairo_pattern_t *source,
    3116                 :                                   cairo_clip_t *clip,
    3117                 :                                   cairo_rectangle_int_t *extents)
    3118                 : {
    3119                 :     cairo_bool_t is_empty;
    3120                 : 
    3121               0 :     is_empty = _cairo_surface_get_extents (surface, extents);
    3122                 : 
    3123               0 :     if (_cairo_operator_bounded_by_source (op)) {
    3124                 :         cairo_rectangle_int_t source_extents;
    3125                 : 
    3126               0 :         _cairo_pattern_get_extents (source, &source_extents);
    3127               0 :         is_empty = _cairo_rectangle_intersect (extents, &source_extents);
    3128                 :     }
    3129                 : 
    3130               0 :     _rectangle_intersect_clip (extents, clip);
    3131               0 : }
    3132                 : 
    3133                 : cairo_status_t
    3134               0 : _cairo_surface_paint_extents (cairo_surface_t *surface,
    3135                 :                               cairo_operator_t          op,
    3136                 :                               const cairo_pattern_t     *source,
    3137                 :                               cairo_clip_t              *clip,
    3138                 :                               cairo_rectangle_int_t     *extents)
    3139                 : {
    3140               0 :     _cairo_surface_operation_extents (surface, op, source, clip, extents);
    3141               0 :     return CAIRO_STATUS_SUCCESS;
    3142                 : }
    3143                 : 
    3144                 : cairo_status_t
    3145               0 : _cairo_surface_mask_extents (cairo_surface_t *surface,
    3146                 :                              cairo_operator_t            op,
    3147                 :                              const cairo_pattern_t      *source,
    3148                 :                              const cairo_pattern_t      *mask,
    3149                 :                              cairo_clip_t               *clip,
    3150                 :                              cairo_rectangle_int_t      *extents)
    3151                 : {
    3152                 :     cairo_bool_t is_empty;
    3153                 : 
    3154               0 :     _cairo_surface_operation_extents (surface, op, source, clip, extents);
    3155                 : 
    3156               0 :     if (_cairo_operator_bounded_by_mask (op)) {
    3157                 :         cairo_rectangle_int_t mask_extents;
    3158                 : 
    3159               0 :         _cairo_pattern_get_extents (mask, &mask_extents);
    3160               0 :         is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
    3161                 :     }
    3162                 : 
    3163               0 :     return CAIRO_STATUS_SUCCESS;
    3164                 : }
    3165                 : 
    3166                 : cairo_status_t
    3167               0 : _cairo_surface_stroke_extents (cairo_surface_t *surface,
    3168                 :                                cairo_operator_t op,
    3169                 :                                const cairo_pattern_t *source,
    3170                 :                                cairo_path_fixed_t       *path,
    3171                 :                                const cairo_stroke_style_t *style,
    3172                 :                                const cairo_matrix_t *ctm,
    3173                 :                                const cairo_matrix_t *ctm_inverse,
    3174                 :                                double tolerance,
    3175                 :                                cairo_antialias_t         antialias,
    3176                 :                                cairo_clip_t *clip,
    3177                 :                                cairo_rectangle_int_t *extents)
    3178                 : {
    3179                 :     cairo_status_t status;
    3180                 :     cairo_bool_t is_empty;
    3181                 : 
    3182               0 :     _cairo_surface_operation_extents (surface, op, source, clip, extents);
    3183                 : 
    3184               0 :     if (_cairo_operator_bounded_by_mask (op)) {
    3185                 :         cairo_rectangle_int_t mask_extents;
    3186                 : 
    3187               0 :         status = _cairo_path_fixed_stroke_extents (path, style,
    3188                 :                                                    ctm, ctm_inverse,
    3189                 :                                                    tolerance,
    3190                 :                                                    &mask_extents);
    3191               0 :         if (unlikely (status))
    3192               0 :             return status;
    3193                 : 
    3194               0 :         is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
    3195                 :     }
    3196                 : 
    3197               0 :     return CAIRO_STATUS_SUCCESS;
    3198                 : }
    3199                 : 
    3200                 : cairo_status_t
    3201               0 : _cairo_surface_fill_extents (cairo_surface_t            *surface,
    3202                 :                              cairo_operator_t            op,
    3203                 :                              const cairo_pattern_t      *source,
    3204                 :                              cairo_path_fixed_t         *path,
    3205                 :                              cairo_fill_rule_t           fill_rule,
    3206                 :                              double                      tolerance,
    3207                 :                              cairo_antialias_t           antialias,
    3208                 :                              cairo_clip_t               *clip,
    3209                 :                              cairo_rectangle_int_t      *extents)
    3210                 : {
    3211                 :     cairo_bool_t is_empty;
    3212                 : 
    3213               0 :     _cairo_surface_operation_extents (surface, op, source, clip, extents);
    3214                 : 
    3215               0 :     if (_cairo_operator_bounded_by_mask (op)) {
    3216                 :         cairo_rectangle_int_t mask_extents;
    3217                 : 
    3218               0 :         _cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
    3219                 :                                         &mask_extents);
    3220               0 :         is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
    3221                 :     }
    3222                 : 
    3223               0 :     return CAIRO_STATUS_SUCCESS;
    3224                 : }
    3225                 : 
    3226                 : cairo_status_t
    3227               0 : _cairo_surface_glyphs_extents (cairo_surface_t *surface,
    3228                 :                                cairo_operator_t    op,
    3229                 :                                const cairo_pattern_t *source,
    3230                 :                                cairo_glyph_t      *glyphs,
    3231                 :                                int                 num_glyphs,
    3232                 :                                cairo_scaled_font_t  *scaled_font,
    3233                 :                                cairo_clip_t         *clip,
    3234                 :                                cairo_rectangle_int_t *extents)
    3235                 : {
    3236                 :     cairo_status_t           status;
    3237                 :     cairo_bool_t             is_empty;
    3238                 : 
    3239               0 :     _cairo_surface_operation_extents (surface, op, source, clip, extents);
    3240                 : 
    3241               0 :     if (_cairo_operator_bounded_by_mask (op)) {
    3242                 :         cairo_rectangle_int_t glyph_extents;
    3243                 : 
    3244               0 :         status = _cairo_scaled_font_glyph_device_extents (scaled_font,
    3245                 :                                                           glyphs,
    3246                 :                                                           num_glyphs,
    3247                 :                                                           &glyph_extents,
    3248                 :                                                           NULL);
    3249               0 :         if (unlikely (status))
    3250               0 :             return status;
    3251                 : 
    3252               0 :         is_empty = _cairo_rectangle_intersect (extents, &glyph_extents);
    3253                 :     }
    3254                 : 
    3255               0 :     return CAIRO_STATUS_SUCCESS;
    3256                 : }
    3257                 : 
    3258                 : cairo_surface_t *
    3259               0 : _cairo_surface_create_in_error (cairo_status_t status)
    3260                 : {
    3261               0 :     switch (status) {
    3262                 :     case CAIRO_STATUS_NO_MEMORY:
    3263               0 :         return (cairo_surface_t *) &_cairo_surface_nil;
    3264                 :     case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
    3265               0 :         return (cairo_surface_t *) &_cairo_surface_nil_surface_type_mismatch;
    3266                 :     case CAIRO_STATUS_INVALID_STATUS:
    3267               0 :         return (cairo_surface_t *) &_cairo_surface_nil_invalid_status;
    3268                 :     case CAIRO_STATUS_INVALID_CONTENT:
    3269               0 :         return (cairo_surface_t *) &_cairo_surface_nil_invalid_content;
    3270                 :     case CAIRO_STATUS_INVALID_FORMAT:
    3271               0 :         return (cairo_surface_t *) &_cairo_surface_nil_invalid_format;
    3272                 :     case CAIRO_STATUS_INVALID_VISUAL:
    3273               0 :         return (cairo_surface_t *) &_cairo_surface_nil_invalid_visual;
    3274                 :     case CAIRO_STATUS_READ_ERROR:
    3275               0 :         return (cairo_surface_t *) &_cairo_surface_nil_read_error;
    3276                 :     case CAIRO_STATUS_WRITE_ERROR:
    3277               0 :         return (cairo_surface_t *) &_cairo_surface_nil_write_error;
    3278                 :     case CAIRO_STATUS_FILE_NOT_FOUND:
    3279               0 :         return (cairo_surface_t *) &_cairo_surface_nil_file_not_found;
    3280                 :     case CAIRO_STATUS_TEMP_FILE_ERROR:
    3281               0 :         return (cairo_surface_t *) &_cairo_surface_nil_temp_file_error;
    3282                 :     case CAIRO_STATUS_INVALID_STRIDE:
    3283               0 :         return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride;
    3284                 :     case CAIRO_STATUS_INVALID_SIZE:
    3285               0 :         return (cairo_surface_t *) &_cairo_surface_nil_invalid_size;
    3286                 :     case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
    3287               0 :         return (cairo_surface_t *) &_cairo_surface_nil_device_type_mismatch;
    3288                 :     case CAIRO_STATUS_DEVICE_ERROR:
    3289               0 :         return (cairo_surface_t *) &_cairo_surface_nil_device_error;
    3290                 :     case CAIRO_STATUS_SUCCESS:
    3291                 :     case CAIRO_STATUS_LAST_STATUS:
    3292               0 :         ASSERT_NOT_REACHED;
    3293                 :         /* fall-through */
    3294                 :     case CAIRO_STATUS_INVALID_RESTORE:
    3295                 :     case CAIRO_STATUS_INVALID_POP_GROUP:
    3296                 :     case CAIRO_STATUS_NO_CURRENT_POINT:
    3297                 :     case CAIRO_STATUS_INVALID_MATRIX:
    3298                 :     case CAIRO_STATUS_NULL_POINTER:
    3299                 :     case CAIRO_STATUS_INVALID_STRING:
    3300                 :     case CAIRO_STATUS_INVALID_PATH_DATA:
    3301                 :     case CAIRO_STATUS_SURFACE_FINISHED:
    3302                 :     case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
    3303                 :     case CAIRO_STATUS_INVALID_DASH:
    3304                 :     case CAIRO_STATUS_INVALID_DSC_COMMENT:
    3305                 :     case CAIRO_STATUS_INVALID_INDEX:
    3306                 :     case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
    3307                 :     case CAIRO_STATUS_FONT_TYPE_MISMATCH:
    3308                 :     case CAIRO_STATUS_USER_FONT_IMMUTABLE:
    3309                 :     case CAIRO_STATUS_USER_FONT_ERROR:
    3310                 :     case CAIRO_STATUS_NEGATIVE_COUNT:
    3311                 :     case CAIRO_STATUS_INVALID_CLUSTERS:
    3312                 :     case CAIRO_STATUS_INVALID_SLANT:
    3313                 :     case CAIRO_STATUS_INVALID_WEIGHT:
    3314                 :     case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
    3315                 :     default:
    3316               0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
    3317               0 :         return (cairo_surface_t *) &_cairo_surface_nil;
    3318                 :     }
    3319                 : }
    3320                 : 
    3321                 : /*  LocalWords:  rasterized
    3322                 :  */

Generated by: LCOV version 1.7