LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-pattern.c (source / functions) Found Hit Coverage
Test: app.info Lines: 1173 128 10.9 %
Date: 2012-06-02 Functions: 90 15 16.7 %

       1                 : /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
       2                 : /* cairo - a vector graphics library with display and print output
       3                 :  *
       4                 :  * Copyright © 2004 David Reveman
       5                 :  * Copyright © 2005 Red Hat, Inc.
       6                 :  *
       7                 :  * Permission to use, copy, modify, distribute, and sell this software
       8                 :  * and its documentation for any purpose is hereby granted without
       9                 :  * fee, provided that the above copyright notice appear in all copies
      10                 :  * and that both that copyright notice and this permission notice
      11                 :  * appear in supporting documentation, and that the name of David
      12                 :  * Reveman not be used in advertising or publicity pertaining to
      13                 :  * distribution of the software without specific, written prior
      14                 :  * permission. David Reveman makes no representations about the
      15                 :  * suitability of this software for any purpose.  It is provided "as
      16                 :  * is" without express or implied warranty.
      17                 :  *
      18                 :  * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
      19                 :  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
      20                 :  * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL,
      21                 :  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
      22                 :  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
      23                 :  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
      24                 :  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      25                 :  *
      26                 :  * Authors: David Reveman <davidr@novell.com>
      27                 :  *          Keith Packard <keithp@keithp.com>
      28                 :  *          Carl Worth <cworth@cworth.org>
      29                 :  */
      30                 : 
      31                 : #include "cairoint.h"
      32                 : #include "cairo-error-private.h"
      33                 : #include "cairo-freed-pool-private.h"
      34                 : 
      35                 : /**
      36                 :  * SECTION:cairo-pattern
      37                 :  * @Title: cairo_pattern_t
      38                 :  * @Short_Description: Sources for drawing
      39                 :  * @See_Also: #cairo_t, #cairo_surface_t
      40                 :  *
      41                 :  * #cairo_pattern_t is the paint with which cairo draws.
      42                 :  * The primary use of patterns is as the source for all cairo drawing 
      43                 :  * operations, although they can also be used as masks, that is, as the 
      44                 :  * brush too.
      45                 :  *
      46                 :  * A cairo pattern is created by using one of the many constructors,
      47                 :  * of the form cairo_pattern_create_<emphasis>type</emphasis>()
      48                 :  * or implicitly through
      49                 :  * cairo_set_source_<emphasis>type</emphasis>() functions.
      50                 :  */
      51                 : 
      52                 : #if HAS_FREED_POOL
      53                 : static freed_pool_t freed_pattern_pool[4];
      54                 : #endif
      55                 : 
      56                 : static const cairo_solid_pattern_t _cairo_pattern_nil = {
      57                 :     { CAIRO_PATTERN_TYPE_SOLID,         /* type */
      58                 :       CAIRO_REFERENCE_COUNT_INVALID,    /* ref_count */
      59                 :       CAIRO_STATUS_NO_MEMORY,           /* status */
      60                 :       { 0, 0, 0, NULL },                /* user_data */
      61                 :       { 1., 0., 0., 1., 0., 0., },      /* matrix */
      62                 :       CAIRO_FILTER_DEFAULT,             /* filter */
      63                 :       CAIRO_EXTEND_GRADIENT_DEFAULT },  /* extend */
      64                 : };
      65                 : 
      66                 : static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
      67                 :     { CAIRO_PATTERN_TYPE_SOLID,         /* type */
      68                 :       CAIRO_REFERENCE_COUNT_INVALID,    /* ref_count */
      69                 :       CAIRO_STATUS_NULL_POINTER,        /* status */
      70                 :       { 0, 0, 0, NULL },                /* user_data */
      71                 :       { 1., 0., 0., 1., 0., 0., },      /* matrix */
      72                 :       CAIRO_FILTER_DEFAULT,             /* filter */
      73                 :       CAIRO_EXTEND_GRADIENT_DEFAULT },  /* extend */
      74                 : };
      75                 : 
      76                 : const cairo_solid_pattern_t _cairo_pattern_black = {
      77                 :     { CAIRO_PATTERN_TYPE_SOLID,         /* type */
      78                 :       CAIRO_REFERENCE_COUNT_INVALID,    /* ref_count */
      79                 :       CAIRO_STATUS_SUCCESS,             /* status */
      80                 :       { 0, 0, 0, NULL },                /* user_data */
      81                 :       { 1., 0., 0., 1., 0., 0., },      /* matrix */
      82                 :       CAIRO_FILTER_DEFAULT,             /* filter */
      83                 :       CAIRO_EXTEND_GRADIENT_DEFAULT},   /* extend */
      84                 :     { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */
      85                 : };
      86                 : 
      87                 : const cairo_solid_pattern_t _cairo_pattern_clear = {
      88                 :     { CAIRO_PATTERN_TYPE_SOLID,         /* type */
      89                 :       CAIRO_REFERENCE_COUNT_INVALID,    /* ref_count */
      90                 :       CAIRO_STATUS_SUCCESS,             /* status */
      91                 :       { 0, 0, 0, NULL },                /* user_data */
      92                 :       { 1., 0., 0., 1., 0., 0., },      /* matrix */
      93                 :       CAIRO_FILTER_DEFAULT,             /* filter */
      94                 :       CAIRO_EXTEND_GRADIENT_DEFAULT},   /* extend */
      95                 :     { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */
      96                 : };
      97                 : 
      98                 : const cairo_solid_pattern_t _cairo_pattern_white = {
      99                 :     { CAIRO_PATTERN_TYPE_SOLID,         /* type */
     100                 :       CAIRO_REFERENCE_COUNT_INVALID,    /* ref_count */
     101                 :       CAIRO_STATUS_SUCCESS,             /* status */
     102                 :       { 0, 0, 0, NULL },                /* user_data */
     103                 :       { 1., 0., 0., 1., 0., 0., },      /* matrix */
     104                 :       CAIRO_FILTER_DEFAULT,             /* filter */
     105                 :       CAIRO_EXTEND_GRADIENT_DEFAULT},   /* extend */
     106                 :     { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
     107                 : };
     108                 : 
     109                 : /**
     110                 :  * _cairo_pattern_set_error:
     111                 :  * @pattern: a pattern
     112                 :  * @status: a status value indicating an error
     113                 :  *
     114                 :  * Atomically sets pattern->status to @status and calls _cairo_error;
     115                 :  * Does nothing if status is %CAIRO_STATUS_SUCCESS.
     116                 :  *
     117                 :  * All assignments of an error status to pattern->status should happen
     118                 :  * through _cairo_pattern_set_error(). Note that due to the nature of
     119                 :  * the atomic operation, it is not safe to call this function on the nil
     120                 :  * objects.
     121                 :  *
     122                 :  * The purpose of this function is to allow the user to set a
     123                 :  * breakpoint in _cairo_error() to generate a stack trace for when the
     124                 :  * user causes cairo to detect an error.
     125                 :  **/
     126                 : static cairo_status_t
     127               0 : _cairo_pattern_set_error (cairo_pattern_t *pattern,
     128                 :                           cairo_status_t status)
     129                 : {
     130               0 :     if (status == CAIRO_STATUS_SUCCESS)
     131               0 :         return status;
     132                 : 
     133                 :     /* Don't overwrite an existing error. This preserves the first
     134                 :      * error, which is the most significant. */
     135               0 :     _cairo_status_set_error (&pattern->status, status);
     136                 : 
     137               0 :     return _cairo_error (status);
     138                 : }
     139                 : 
     140                 : static void
     141              47 : _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
     142                 : {
     143                 : #if HAVE_VALGRIND
     144                 :     switch (type) {
     145                 :     case CAIRO_PATTERN_TYPE_SOLID:
     146                 :         VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t));
     147                 :         break;
     148                 :     case CAIRO_PATTERN_TYPE_SURFACE:
     149                 :         VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t));
     150                 :         break;
     151                 :     case CAIRO_PATTERN_TYPE_LINEAR:
     152                 :         VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t));
     153                 :         break;
     154                 :     case CAIRO_PATTERN_TYPE_RADIAL:
     155                 :         VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t));
     156                 :         break;
     157                 :     }
     158                 : #endif
     159                 : 
     160              47 :     pattern->type      = type;
     161              47 :     pattern->status    = CAIRO_STATUS_SUCCESS;
     162                 : 
     163                 :     /* Set the reference count to zero for on-stack patterns.
     164                 :      * Callers needs to explicitly increment the count for heap allocations. */
     165              47 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
     166                 : 
     167              47 :     _cairo_user_data_array_init (&pattern->user_data);
     168                 : 
     169              47 :     if (type == CAIRO_PATTERN_TYPE_SURFACE)
     170              47 :         pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
     171                 :     else
     172               0 :         pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
     173                 : 
     174              47 :     pattern->filter    = CAIRO_FILTER_DEFAULT;
     175                 : 
     176              47 :     pattern->has_component_alpha = FALSE;
     177                 : 
     178              47 :     cairo_matrix_init_identity (&pattern->matrix);
     179              47 : }
     180                 : 
     181                 : static cairo_status_t
     182               0 : _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t       *pattern,
     183                 :                                    const cairo_gradient_pattern_t *other)
     184                 : {
     185                 :     if (CAIRO_INJECT_FAULT ())
     186                 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     187                 : 
     188               0 :     if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR)
     189                 :     {
     190               0 :         cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
     191               0 :         cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
     192                 : 
     193               0 :         *dst = *src;
     194                 :     }
     195                 :     else
     196                 :     {
     197               0 :         cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
     198               0 :         cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
     199                 : 
     200               0 :         *dst = *src;
     201                 :     }
     202                 : 
     203               0 :     if (other->stops == other->stops_embedded)
     204               0 :         pattern->stops = pattern->stops_embedded;
     205               0 :     else if (other->stops)
     206                 :     {
     207               0 :         pattern->stops = _cairo_malloc_ab (other->stops_size,
     208                 :                                            sizeof (cairo_gradient_stop_t));
     209               0 :         if (unlikely (pattern->stops == NULL)) {
     210               0 :             pattern->stops_size = 0;
     211               0 :             pattern->n_stops = 0;
     212               0 :             return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
     213                 :         }
     214                 : 
     215               0 :         memcpy (pattern->stops, other->stops,
     216               0 :                 other->n_stops * sizeof (cairo_gradient_stop_t));
     217                 :     }
     218                 : 
     219               0 :     return CAIRO_STATUS_SUCCESS;
     220                 : }
     221                 : 
     222                 : cairo_status_t
     223               0 : _cairo_pattern_init_copy (cairo_pattern_t       *pattern,
     224                 :                           const cairo_pattern_t *other)
     225                 : {
     226               0 :     if (other->status)
     227               0 :         return _cairo_pattern_set_error (pattern, other->status);
     228                 : 
     229               0 :     switch (other->type) {
     230                 :     case CAIRO_PATTERN_TYPE_SOLID: {
     231               0 :         cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
     232               0 :         cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
     233                 : 
     234                 :         VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t)));
     235                 : 
     236               0 :         *dst = *src;
     237               0 :     } break;
     238                 :     case CAIRO_PATTERN_TYPE_SURFACE: {
     239               0 :         cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
     240               0 :         cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
     241                 : 
     242                 :         VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t)));
     243                 : 
     244               0 :         *dst = *src;
     245               0 :         cairo_surface_reference (dst->surface);
     246               0 :     } break;
     247                 :     case CAIRO_PATTERN_TYPE_LINEAR:
     248                 :     case CAIRO_PATTERN_TYPE_RADIAL: {
     249               0 :         cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
     250               0 :         cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
     251                 :         cairo_status_t status;
     252                 : 
     253               0 :         if (other->type == CAIRO_PATTERN_TYPE_LINEAR) {
     254                 :             VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)));
     255                 :         } else {
     256                 :             VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)));
     257                 :         }
     258                 : 
     259               0 :         status = _cairo_gradient_pattern_init_copy (dst, src);
     260               0 :         if (unlikely (status))
     261               0 :             return status;
     262                 : 
     263               0 :     } break;
     264                 :     }
     265                 : 
     266                 :     /* The reference count and user_data array are unique to the copy. */
     267               0 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
     268               0 :     _cairo_user_data_array_init (&pattern->user_data);
     269                 : 
     270               0 :     return CAIRO_STATUS_SUCCESS;
     271                 : }
     272                 : 
     273                 : void
     274              47 : _cairo_pattern_init_static_copy (cairo_pattern_t        *pattern,
     275                 :                                  const cairo_pattern_t *other)
     276                 : {
     277                 :     int size;
     278                 : 
     279              47 :     assert (other->status == CAIRO_STATUS_SUCCESS);
     280                 : 
     281              47 :     switch (other->type) {
     282                 :     default:
     283               0 :         ASSERT_NOT_REACHED;
     284                 :     case CAIRO_PATTERN_TYPE_SOLID:
     285               0 :         size = sizeof (cairo_solid_pattern_t);
     286               0 :         break;
     287                 :     case CAIRO_PATTERN_TYPE_SURFACE:
     288              47 :         size = sizeof (cairo_surface_pattern_t);
     289              47 :         break;
     290                 :     case CAIRO_PATTERN_TYPE_LINEAR:
     291               0 :         size = sizeof (cairo_linear_pattern_t);
     292               0 :         break;
     293                 :     case CAIRO_PATTERN_TYPE_RADIAL:
     294               0 :         size = sizeof (cairo_radial_pattern_t);
     295               0 :         break;
     296                 :     }
     297                 : 
     298              47 :     memcpy (pattern, other, size);
     299                 : 
     300              47 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
     301              47 :     _cairo_user_data_array_init (&pattern->user_data);
     302              47 : }
     303                 : 
     304                 : cairo_status_t
     305               0 : _cairo_pattern_init_snapshot (cairo_pattern_t       *pattern,
     306                 :                               const cairo_pattern_t *other)
     307                 : {
     308                 :     cairo_status_t status;
     309                 : 
     310                 :     /* We don't bother doing any fancy copy-on-write implementation
     311                 :      * for the pattern's data. It's generally quite tiny. */
     312               0 :     status = _cairo_pattern_init_copy (pattern, other);
     313               0 :     if (unlikely (status))
     314               0 :         return status;
     315                 : 
     316                 :     /* But we do let the surface snapshot stuff be as fancy as it
     317                 :      * would like to be. */
     318               0 :     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
     319               0 :         cairo_surface_pattern_t *surface_pattern =
     320                 :             (cairo_surface_pattern_t *) pattern;
     321               0 :         cairo_surface_t *surface = surface_pattern->surface;
     322                 : 
     323               0 :         surface_pattern->surface = _cairo_surface_snapshot (surface);
     324                 : 
     325               0 :         cairo_surface_destroy (surface);
     326                 : 
     327               0 :         if (surface_pattern->surface->status)
     328               0 :             return surface_pattern->surface->status;
     329                 :     }
     330                 : 
     331               0 :     return CAIRO_STATUS_SUCCESS;
     332                 : }
     333                 : 
     334                 : void
     335              47 : _cairo_pattern_fini (cairo_pattern_t *pattern)
     336                 : {
     337              47 :     _cairo_user_data_array_fini (&pattern->user_data);
     338                 : 
     339              47 :     switch (pattern->type) {
     340                 :     case CAIRO_PATTERN_TYPE_SOLID:
     341               0 :         break;
     342                 :     case CAIRO_PATTERN_TYPE_SURFACE: {
     343              47 :         cairo_surface_pattern_t *surface_pattern =
     344                 :             (cairo_surface_pattern_t *) pattern;
     345                 : 
     346              47 :         cairo_surface_destroy (surface_pattern->surface);
     347              47 :     } break;
     348                 :     case CAIRO_PATTERN_TYPE_LINEAR:
     349                 :     case CAIRO_PATTERN_TYPE_RADIAL: {
     350               0 :         cairo_gradient_pattern_t *gradient =
     351                 :             (cairo_gradient_pattern_t *) pattern;
     352                 : 
     353               0 :         if (gradient->stops && gradient->stops != gradient->stops_embedded)
     354               0 :             free (gradient->stops);
     355               0 :     } break;
     356                 :     }
     357                 : 
     358                 : #if HAVE_VALGRIND
     359                 :     switch (pattern->type) {
     360                 :     case CAIRO_PATTERN_TYPE_SOLID:
     361                 :         VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_solid_pattern_t));
     362                 :         break;
     363                 :     case CAIRO_PATTERN_TYPE_SURFACE:
     364                 :         VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_surface_pattern_t));
     365                 :         break;
     366                 :     case CAIRO_PATTERN_TYPE_LINEAR:
     367                 :         VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_linear_pattern_t));
     368                 :         break;
     369                 :     case CAIRO_PATTERN_TYPE_RADIAL:
     370                 :         VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_radial_pattern_t));
     371                 :         break;
     372                 :     }
     373                 : #endif
     374              47 : }
     375                 : 
     376                 : cairo_status_t
     377               0 : _cairo_pattern_create_copy (cairo_pattern_t       **pattern_out,
     378                 :                             const cairo_pattern_t  *other)
     379                 : {
     380                 :     cairo_pattern_t *pattern;
     381                 :     cairo_status_t status;
     382                 : 
     383               0 :     if (other->status)
     384               0 :         return other->status;
     385                 : 
     386               0 :     switch (other->type) {
     387                 :     case CAIRO_PATTERN_TYPE_SOLID:
     388               0 :         pattern = malloc (sizeof (cairo_solid_pattern_t));
     389               0 :         break;
     390                 :     case CAIRO_PATTERN_TYPE_SURFACE:
     391               0 :         pattern = malloc (sizeof (cairo_surface_pattern_t));
     392               0 :         break;
     393                 :     case CAIRO_PATTERN_TYPE_LINEAR:
     394               0 :         pattern = malloc (sizeof (cairo_linear_pattern_t));
     395               0 :         break;
     396                 :     case CAIRO_PATTERN_TYPE_RADIAL:
     397               0 :         pattern = malloc (sizeof (cairo_radial_pattern_t));
     398               0 :         break;
     399                 :     default:
     400               0 :         ASSERT_NOT_REACHED;
     401               0 :         return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
     402                 :     }
     403               0 :     if (unlikely (pattern == NULL))
     404               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     405                 : 
     406               0 :     status = _cairo_pattern_init_copy (pattern, other);
     407               0 :     if (unlikely (status)) {
     408               0 :         free (pattern);
     409               0 :         return status;
     410                 :     }
     411                 : 
     412               0 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
     413               0 :     *pattern_out = pattern;
     414               0 :     return CAIRO_STATUS_SUCCESS;
     415                 : }
     416                 : 
     417                 : 
     418                 : void
     419               0 : _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
     420                 :                            const cairo_color_t   *color)
     421                 : {
     422               0 :     _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
     423               0 :     pattern->color = *color;
     424               0 : }
     425                 : 
     426                 : void
     427              47 : _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
     428                 :                                  cairo_surface_t         *surface)
     429                 : {
     430              47 :     if (surface->status) {
     431                 :         /* Force to solid to simplify the pattern_fini process. */
     432               0 :         _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
     433               0 :         _cairo_pattern_set_error (&pattern->base, surface->status);
     434               0 :         return;
     435                 :     }
     436                 : 
     437              47 :     _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE);
     438                 : 
     439              47 :     pattern->surface = cairo_surface_reference (surface);
     440                 : }
     441                 : 
     442                 : static void
     443               0 : _cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
     444                 :                               cairo_pattern_type_t     type)
     445                 : {
     446               0 :     _cairo_pattern_init (&pattern->base, type);
     447                 : 
     448               0 :     pattern->n_stops    = 0;
     449               0 :     pattern->stops_size = 0;
     450               0 :     pattern->stops      = NULL;
     451               0 : }
     452                 : 
     453                 : void
     454               0 : _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
     455                 :                             double x0, double y0, double x1, double y1)
     456                 : {
     457               0 :     _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR);
     458                 : 
     459               0 :     pattern->p1.x = _cairo_fixed_from_double (x0);
     460               0 :     pattern->p1.y = _cairo_fixed_from_double (y0);
     461               0 :     pattern->p2.x = _cairo_fixed_from_double (x1);
     462               0 :     pattern->p2.y = _cairo_fixed_from_double (y1);
     463               0 : }
     464                 : 
     465                 : void
     466               0 : _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
     467                 :                             double cx0, double cy0, double radius0,
     468                 :                             double cx1, double cy1, double radius1)
     469                 : {
     470               0 :     _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
     471                 : 
     472               0 :     pattern->c1.x = _cairo_fixed_from_double (cx0);
     473               0 :     pattern->c1.y = _cairo_fixed_from_double (cy0);
     474               0 :     pattern->r1   = _cairo_fixed_from_double (fabs (radius0));
     475               0 :     pattern->c2.x = _cairo_fixed_from_double (cx1);
     476               0 :     pattern->c2.y = _cairo_fixed_from_double (cy1);
     477               0 :     pattern->r2   = _cairo_fixed_from_double (fabs (radius1));
     478               0 : }
     479                 : 
     480                 : cairo_pattern_t *
     481               0 : _cairo_pattern_create_solid (const cairo_color_t *color)
     482                 : {
     483                 :     cairo_solid_pattern_t *pattern;
     484                 : 
     485               0 :     pattern =
     486                 :         _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
     487               0 :     if (unlikely (pattern == NULL)) {
     488                 :         /* None cached, need to create a new pattern. */
     489               0 :         pattern = malloc (sizeof (cairo_solid_pattern_t));
     490               0 :         if (unlikely (pattern == NULL)) {
     491               0 :             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     492               0 :             return (cairo_pattern_t *) &_cairo_pattern_nil;
     493                 :         }
     494                 :     }
     495                 : 
     496               0 :     _cairo_pattern_init_solid (pattern, color);
     497               0 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
     498                 : 
     499               0 :     return &pattern->base;
     500                 : }
     501                 : 
     502                 : cairo_pattern_t *
     503               0 : _cairo_pattern_create_in_error (cairo_status_t status)
     504                 : {
     505                 :     cairo_pattern_t *pattern;
     506                 : 
     507               0 :     if (status == CAIRO_STATUS_NO_MEMORY)
     508               0 :         return (cairo_pattern_t *)&_cairo_pattern_nil.base;
     509                 : 
     510                 :     CAIRO_MUTEX_INITIALIZE ();
     511                 : 
     512               0 :     pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
     513               0 :     if (pattern->status == CAIRO_STATUS_SUCCESS)
     514               0 :         status = _cairo_pattern_set_error (pattern, status);
     515                 : 
     516               0 :     return pattern;
     517                 : }
     518                 : 
     519                 : /**
     520                 :  * cairo_pattern_create_rgb:
     521                 :  * @red: red component of the color
     522                 :  * @green: green component of the color
     523                 :  * @blue: blue component of the color
     524                 :  *
     525                 :  * Creates a new #cairo_pattern_t corresponding to an opaque color.  The
     526                 :  * color components are floating point numbers in the range 0 to 1.
     527                 :  * If the values passed in are outside that range, they will be
     528                 :  * clamped.
     529                 :  *
     530                 :  * Return value: the newly created #cairo_pattern_t if successful, or
     531                 :  * an error pattern in case of no memory.  The caller owns the
     532                 :  * returned object and should call cairo_pattern_destroy() when
     533                 :  * finished with it.
     534                 :  *
     535                 :  * This function will always return a valid pointer, but if an error
     536                 :  * occurred the pattern status will be set to an error.  To inspect
     537                 :  * the status of a pattern use cairo_pattern_status().
     538                 :  **/
     539                 : cairo_pattern_t *
     540               0 : cairo_pattern_create_rgb (double red, double green, double blue)
     541                 : {
     542                 :     cairo_color_t color;
     543                 : 
     544               0 :     red   = _cairo_restrict_value (red,   0.0, 1.0);
     545               0 :     green = _cairo_restrict_value (green, 0.0, 1.0);
     546               0 :     blue  = _cairo_restrict_value (blue,  0.0, 1.0);
     547                 : 
     548               0 :     _cairo_color_init_rgb (&color, red, green, blue);
     549                 : 
     550                 :     CAIRO_MUTEX_INITIALIZE ();
     551                 : 
     552               0 :     return _cairo_pattern_create_solid (&color);
     553                 : }
     554                 : slim_hidden_def (cairo_pattern_create_rgb);
     555                 : 
     556                 : /**
     557                 :  * cairo_pattern_create_rgba:
     558                 :  * @red: red component of the color
     559                 :  * @green: green component of the color
     560                 :  * @blue: blue component of the color
     561                 :  * @alpha: alpha component of the color
     562                 :  *
     563                 :  * Creates a new #cairo_pattern_t corresponding to a translucent color.
     564                 :  * The color components are floating point numbers in the range 0 to
     565                 :  * 1.  If the values passed in are outside that range, they will be
     566                 :  * clamped.
     567                 :  *
     568                 :  * Return value: the newly created #cairo_pattern_t if successful, or
     569                 :  * an error pattern in case of no memory.  The caller owns the
     570                 :  * returned object and should call cairo_pattern_destroy() when
     571                 :  * finished with it.
     572                 :  *
     573                 :  * This function will always return a valid pointer, but if an error
     574                 :  * occurred the pattern status will be set to an error.  To inspect
     575                 :  * the status of a pattern use cairo_pattern_status().
     576                 :  **/
     577                 : cairo_pattern_t *
     578               0 : cairo_pattern_create_rgba (double red, double green, double blue,
     579                 :                            double alpha)
     580                 : {
     581                 :     cairo_color_t color;
     582                 : 
     583               0 :     red   = _cairo_restrict_value (red,   0.0, 1.0);
     584               0 :     green = _cairo_restrict_value (green, 0.0, 1.0);
     585               0 :     blue  = _cairo_restrict_value (blue,  0.0, 1.0);
     586               0 :     alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
     587                 : 
     588               0 :     _cairo_color_init_rgba (&color, red, green, blue, alpha);
     589                 : 
     590                 :     CAIRO_MUTEX_INITIALIZE ();
     591                 : 
     592               0 :     return _cairo_pattern_create_solid (&color);
     593                 : }
     594                 : slim_hidden_def (cairo_pattern_create_rgba);
     595                 : 
     596                 : /**
     597                 :  * cairo_pattern_create_for_surface:
     598                 :  * @surface: the surface
     599                 :  *
     600                 :  * Create a new #cairo_pattern_t for the given surface.
     601                 :  *
     602                 :  * Return value: the newly created #cairo_pattern_t if successful, or
     603                 :  * an error pattern in case of no memory.  The caller owns the
     604                 :  * returned object and should call cairo_pattern_destroy() when
     605                 :  * finished with it.
     606                 :  *
     607                 :  * This function will always return a valid pointer, but if an error
     608                 :  * occurred the pattern status will be set to an error.  To inspect
     609                 :  * the status of a pattern use cairo_pattern_status().
     610                 :  **/
     611                 : cairo_pattern_t *
     612              47 : cairo_pattern_create_for_surface (cairo_surface_t *surface)
     613                 : {
     614                 :     cairo_surface_pattern_t *pattern;
     615                 : 
     616              47 :     if (surface == NULL) {
     617               0 :         _cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
     618               0 :         return (cairo_pattern_t*) &_cairo_pattern_nil_null_pointer;
     619                 :     }
     620                 : 
     621              47 :     if (surface->status)
     622               0 :         return _cairo_pattern_create_in_error (surface->status);
     623                 : 
     624              47 :     pattern =
     625                 :         _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
     626              47 :     if (unlikely (pattern == NULL)) {
     627              47 :         pattern = malloc (sizeof (cairo_surface_pattern_t));
     628              47 :         if (unlikely (pattern == NULL)) {
     629               0 :             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     630               0 :             return (cairo_pattern_t *)&_cairo_pattern_nil.base;
     631                 :         }
     632                 :     }
     633                 : 
     634                 :     CAIRO_MUTEX_INITIALIZE ();
     635                 : 
     636              47 :     _cairo_pattern_init_for_surface (pattern, surface);
     637              47 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
     638                 : 
     639              47 :     return &pattern->base;
     640                 : }
     641                 : slim_hidden_def (cairo_pattern_create_for_surface);
     642                 : 
     643                 : /**
     644                 :  * cairo_pattern_create_linear:
     645                 :  * @x0: x coordinate of the start point
     646                 :  * @y0: y coordinate of the start point
     647                 :  * @x1: x coordinate of the end point
     648                 :  * @y1: y coordinate of the end point
     649                 :  *
     650                 :  * Create a new linear gradient #cairo_pattern_t along the line defined
     651                 :  * by (x0, y0) and (x1, y1).  Before using the gradient pattern, a
     652                 :  * number of color stops should be defined using
     653                 :  * cairo_pattern_add_color_stop_rgb() or
     654                 :  * cairo_pattern_add_color_stop_rgba().
     655                 :  *
     656                 :  * Note: The coordinates here are in pattern space. For a new pattern,
     657                 :  * pattern space is identical to user space, but the relationship
     658                 :  * between the spaces can be changed with cairo_pattern_set_matrix().
     659                 :  *
     660                 :  * Return value: the newly created #cairo_pattern_t if successful, or
     661                 :  * an error pattern in case of no memory.  The caller owns the
     662                 :  * returned object and should call cairo_pattern_destroy() when
     663                 :  * finished with it.
     664                 :  *
     665                 :  * This function will always return a valid pointer, but if an error
     666                 :  * occurred the pattern status will be set to an error.  To inspect
     667                 :  * the status of a pattern use cairo_pattern_status().
     668                 :  **/
     669                 : cairo_pattern_t *
     670               0 : cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
     671                 : {
     672                 :     cairo_linear_pattern_t *pattern;
     673                 : 
     674               0 :     pattern =
     675                 :         _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
     676               0 :     if (unlikely (pattern == NULL)) {
     677               0 :         pattern = malloc (sizeof (cairo_linear_pattern_t));
     678               0 :         if (unlikely (pattern == NULL)) {
     679               0 :             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     680               0 :             return (cairo_pattern_t *) &_cairo_pattern_nil.base;
     681                 :         }
     682                 :     }
     683                 : 
     684                 :     CAIRO_MUTEX_INITIALIZE ();
     685                 : 
     686               0 :     _cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
     687               0 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1);
     688                 : 
     689               0 :     return &pattern->base.base;
     690                 : }
     691                 : 
     692                 : /**
     693                 :  * cairo_pattern_create_radial:
     694                 :  * @cx0: x coordinate for the center of the start circle
     695                 :  * @cy0: y coordinate for the center of the start circle
     696                 :  * @radius0: radius of the start circle
     697                 :  * @cx1: x coordinate for the center of the end circle
     698                 :  * @cy1: y coordinate for the center of the end circle
     699                 :  * @radius1: radius of the end circle
     700                 :  *
     701                 :  * Creates a new radial gradient #cairo_pattern_t between the two
     702                 :  * circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1).  Before using the
     703                 :  * gradient pattern, a number of color stops should be defined using
     704                 :  * cairo_pattern_add_color_stop_rgb() or
     705                 :  * cairo_pattern_add_color_stop_rgba().
     706                 :  *
     707                 :  * Note: The coordinates here are in pattern space. For a new pattern,
     708                 :  * pattern space is identical to user space, but the relationship
     709                 :  * between the spaces can be changed with cairo_pattern_set_matrix().
     710                 :  *
     711                 :  * Return value: the newly created #cairo_pattern_t if successful, or
     712                 :  * an error pattern in case of no memory.  The caller owns the
     713                 :  * returned object and should call cairo_pattern_destroy() when
     714                 :  * finished with it.
     715                 :  *
     716                 :  * This function will always return a valid pointer, but if an error
     717                 :  * occurred the pattern status will be set to an error.  To inspect
     718                 :  * the status of a pattern use cairo_pattern_status().
     719                 :  **/
     720                 : cairo_pattern_t *
     721               0 : cairo_pattern_create_radial (double cx0, double cy0, double radius0,
     722                 :                              double cx1, double cy1, double radius1)
     723                 : {
     724                 :     cairo_radial_pattern_t *pattern;
     725                 : 
     726               0 :     pattern =
     727                 :         _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
     728               0 :     if (unlikely (pattern == NULL)) {
     729               0 :         pattern = malloc (sizeof (cairo_radial_pattern_t));
     730               0 :         if (unlikely (pattern == NULL)) {
     731               0 :             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     732               0 :             return (cairo_pattern_t *) &_cairo_pattern_nil.base;
     733                 :         }
     734                 :     }
     735                 : 
     736                 :     CAIRO_MUTEX_INITIALIZE ();
     737                 : 
     738               0 :     _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
     739               0 :     CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1);
     740                 : 
     741               0 :     return &pattern->base.base;
     742                 : }
     743                 : 
     744                 : /**
     745                 :  * cairo_pattern_reference:
     746                 :  * @pattern: a #cairo_pattern_t
     747                 :  *
     748                 :  * Increases the reference count on @pattern by one. This prevents
     749                 :  * @pattern from being destroyed until a matching call to
     750                 :  * cairo_pattern_destroy() is made.
     751                 :  *
     752                 :  * The number of references to a #cairo_pattern_t can be get using
     753                 :  * cairo_pattern_get_reference_count().
     754                 :  *
     755                 :  * Return value: the referenced #cairo_pattern_t.
     756                 :  **/
     757                 : cairo_pattern_t *
     758              75 : cairo_pattern_reference (cairo_pattern_t *pattern)
     759                 : {
     760             150 :     if (pattern == NULL ||
     761              75 :             CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
     762              28 :         return pattern;
     763                 : 
     764              47 :     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
     765                 : 
     766              47 :     _cairo_reference_count_inc (&pattern->ref_count);
     767                 : 
     768              47 :     return pattern;
     769                 : }
     770                 : slim_hidden_def (cairo_pattern_reference);
     771                 : 
     772                 : /**
     773                 :  * cairo_pattern_get_type:
     774                 :  * @pattern: a #cairo_pattern_t
     775                 :  *
     776                 :  * This function returns the type a pattern.
     777                 :  * See #cairo_pattern_type_t for available types.
     778                 :  *
     779                 :  * Return value: The type of @pattern.
     780                 :  *
     781                 :  * Since: 1.2
     782                 :  **/
     783                 : cairo_pattern_type_t
     784               0 : cairo_pattern_get_type (cairo_pattern_t *pattern)
     785                 : {
     786               0 :     return pattern->type;
     787                 : }
     788                 : 
     789                 : /**
     790                 :  * cairo_pattern_status:
     791                 :  * @pattern: a #cairo_pattern_t
     792                 :  *
     793                 :  * Checks whether an error has previously occurred for this
     794                 :  * pattern.
     795                 :  *
     796                 :  * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, or
     797                 :  * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
     798                 :  **/
     799                 : cairo_status_t
     800               0 : cairo_pattern_status (cairo_pattern_t *pattern)
     801                 : {
     802               0 :     return pattern->status;
     803                 : }
     804                 : 
     805                 : /**
     806                 :  * cairo_pattern_destroy:
     807                 :  * @pattern: a #cairo_pattern_t
     808                 :  *
     809                 :  * Decreases the reference count on @pattern by one. If the result is
     810                 :  * zero, then @pattern and all associated resources are freed.  See
     811                 :  * cairo_pattern_reference().
     812                 :  **/
     813                 : void
     814             186 : cairo_pattern_destroy (cairo_pattern_t *pattern)
     815                 : {
     816                 :     cairo_pattern_type_t type;
     817                 : 
     818             372 :     if (pattern == NULL ||
     819             186 :             CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
     820              92 :         return;
     821                 : 
     822              94 :     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
     823                 : 
     824              94 :     if (! _cairo_reference_count_dec_and_test (&pattern->ref_count))
     825              47 :         return;
     826                 : 
     827              47 :     type = pattern->type;
     828              47 :     _cairo_pattern_fini (pattern);
     829                 : 
     830                 :     /* maintain a small cache of freed patterns */
     831              47 :     _freed_pool_put (&freed_pattern_pool[type], pattern);
     832                 : }
     833                 : slim_hidden_def (cairo_pattern_destroy);
     834                 : 
     835                 : /**
     836                 :  * cairo_pattern_get_reference_count:
     837                 :  * @pattern: a #cairo_pattern_t
     838                 :  *
     839                 :  * Returns the current reference count of @pattern.
     840                 :  *
     841                 :  * Return value: the current reference count of @pattern.  If the
     842                 :  * object is a nil object, 0 will be returned.
     843                 :  *
     844                 :  * Since: 1.4
     845                 :  **/
     846                 : unsigned int
     847               0 : cairo_pattern_get_reference_count (cairo_pattern_t *pattern)
     848                 : {
     849               0 :     if (pattern == NULL ||
     850               0 :             CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
     851               0 :         return 0;
     852                 : 
     853               0 :     return CAIRO_REFERENCE_COUNT_GET_VALUE (&pattern->ref_count);
     854                 : }
     855                 : 
     856                 : /**
     857                 :  * cairo_pattern_get_user_data:
     858                 :  * @pattern: a #cairo_pattern_t
     859                 :  * @key: the address of the #cairo_user_data_key_t the user data was
     860                 :  * attached to
     861                 :  *
     862                 :  * Return user data previously attached to @pattern using the
     863                 :  * specified key.  If no user data has been attached with the given
     864                 :  * key this function returns %NULL.
     865                 :  *
     866                 :  * Return value: the user data previously attached or %NULL.
     867                 :  *
     868                 :  * Since: 1.4
     869                 :  **/
     870                 : void *
     871               0 : cairo_pattern_get_user_data (cairo_pattern_t             *pattern,
     872                 :                              const cairo_user_data_key_t *key)
     873                 : {
     874               0 :     return _cairo_user_data_array_get_data (&pattern->user_data,
     875                 :                                             key);
     876                 : }
     877                 : 
     878                 : /**
     879                 :  * cairo_pattern_set_user_data:
     880                 :  * @pattern: a #cairo_pattern_t
     881                 :  * @key: the address of a #cairo_user_data_key_t to attach the user data to
     882                 :  * @user_data: the user data to attach to the #cairo_pattern_t
     883                 :  * @destroy: a #cairo_destroy_func_t which will be called when the
     884                 :  * #cairo_t is destroyed or when new user data is attached using the
     885                 :  * same key.
     886                 :  *
     887                 :  * Attach user data to @pattern.  To remove user data from a surface,
     888                 :  * call this function with the key that was used to set it and %NULL
     889                 :  * for @data.
     890                 :  *
     891                 :  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
     892                 :  * slot could not be allocated for the user data.
     893                 :  *
     894                 :  * Since: 1.4
     895                 :  **/
     896                 : cairo_status_t
     897               0 : cairo_pattern_set_user_data (cairo_pattern_t             *pattern,
     898                 :                              const cairo_user_data_key_t *key,
     899                 :                              void                        *user_data,
     900                 :                              cairo_destroy_func_t         destroy)
     901                 : {
     902               0 :     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
     903               0 :         return pattern->status;
     904                 : 
     905               0 :     return _cairo_user_data_array_set_data (&pattern->user_data,
     906                 :                                             key, user_data, destroy);
     907                 : }
     908                 : 
     909                 : /* make room for at least one more color stop */
     910                 : static cairo_status_t
     911               0 : _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
     912                 : {
     913                 :     cairo_gradient_stop_t *new_stops;
     914               0 :     int old_size = pattern->stops_size;
     915               0 :     int embedded_size = ARRAY_LENGTH (pattern->stops_embedded);
     916               0 :     int new_size = 2 * MAX (old_size, 4);
     917                 : 
     918                 :     /* we have a local buffer at pattern->stops_embedded.  try to fulfill the request
     919                 :      * from there. */
     920               0 :     if (old_size < embedded_size) {
     921               0 :         pattern->stops = pattern->stops_embedded;
     922               0 :         pattern->stops_size = embedded_size;
     923               0 :         return CAIRO_STATUS_SUCCESS;
     924                 :     }
     925                 : 
     926                 :     if (CAIRO_INJECT_FAULT ())
     927                 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     928                 : 
     929               0 :     assert (pattern->n_stops <= pattern->stops_size);
     930                 : 
     931               0 :     if (pattern->stops == pattern->stops_embedded) {
     932               0 :         new_stops = _cairo_malloc_ab (new_size, sizeof (cairo_gradient_stop_t));
     933               0 :         if (new_stops)
     934               0 :             memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t));
     935                 :     } else {
     936               0 :         new_stops = _cairo_realloc_ab (pattern->stops,
     937                 :                                        new_size,
     938                 :                                        sizeof (cairo_gradient_stop_t));
     939                 :     }
     940                 : 
     941               0 :     if (unlikely (new_stops == NULL))
     942               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     943                 : 
     944               0 :     pattern->stops = new_stops;
     945               0 :     pattern->stops_size = new_size;
     946                 : 
     947               0 :     return CAIRO_STATUS_SUCCESS;
     948                 : }
     949                 : 
     950                 : static void
     951               0 : _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
     952                 :                                double                    offset,
     953                 :                                double                    red,
     954                 :                                double                    green,
     955                 :                                double                    blue,
     956                 :                                double                    alpha)
     957                 : {
     958                 :     cairo_gradient_stop_t *stops;
     959                 :     unsigned int           i;
     960                 : 
     961               0 :     if (pattern->n_stops >= pattern->stops_size) {
     962               0 :         cairo_status_t status = _cairo_pattern_gradient_grow (pattern);
     963               0 :         if (unlikely (status)) {
     964               0 :             status = _cairo_pattern_set_error (&pattern->base, status);
     965               0 :             return;
     966                 :         }
     967                 :     }
     968                 : 
     969               0 :     stops = pattern->stops;
     970                 : 
     971               0 :     for (i = 0; i < pattern->n_stops; i++)
     972                 :     {
     973               0 :         if (offset < stops[i].offset)
     974                 :         {
     975               0 :             memmove (&stops[i + 1], &stops[i],
     976               0 :                      sizeof (cairo_gradient_stop_t) * (pattern->n_stops - i));
     977                 : 
     978               0 :             break;
     979                 :         }
     980                 :     }
     981                 : 
     982               0 :     stops[i].offset = offset;
     983                 : 
     984               0 :     stops[i].color.red   = red;
     985               0 :     stops[i].color.green = green;
     986               0 :     stops[i].color.blue  = blue;
     987               0 :     stops[i].color.alpha = alpha;
     988                 : 
     989               0 :     stops[i].color.red_short   = _cairo_color_double_to_short (red);
     990               0 :     stops[i].color.green_short = _cairo_color_double_to_short (green);
     991               0 :     stops[i].color.blue_short  = _cairo_color_double_to_short (blue);
     992               0 :     stops[i].color.alpha_short = _cairo_color_double_to_short (alpha);
     993                 : 
     994               0 :     pattern->n_stops++;
     995                 : }
     996                 : 
     997                 : /**
     998                 :  * cairo_pattern_add_color_stop_rgb:
     999                 :  * @pattern: a #cairo_pattern_t
    1000                 :  * @offset: an offset in the range [0.0 .. 1.0]
    1001                 :  * @red: red component of color
    1002                 :  * @green: green component of color
    1003                 :  * @blue: blue component of color
    1004                 :  *
    1005                 :  * Adds an opaque color stop to a gradient pattern. The offset
    1006                 :  * specifies the location along the gradient's control vector. For
    1007                 :  * example, a linear gradient's control vector is from (x0,y0) to
    1008                 :  * (x1,y1) while a radial gradient's control vector is from any point
    1009                 :  * on the start circle to the corresponding point on the end circle.
    1010                 :  *
    1011                 :  * The color is specified in the same way as in cairo_set_source_rgb().
    1012                 :  *
    1013                 :  * If two (or more) stops are specified with identical offset values,
    1014                 :  * they will be sorted according to the order in which the stops are
    1015                 :  * added, (stops added earlier will compare less than stops added
    1016                 :  * later). This can be useful for reliably making sharp color
    1017                 :  * transitions instead of the typical blend.
    1018                 :  *
    1019                 :  *
    1020                 :  * Note: If the pattern is not a gradient pattern, (eg. a linear or
    1021                 :  * radial pattern), then the pattern will be put into an error status
    1022                 :  * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
    1023                 :  **/
    1024                 : void
    1025               0 : cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
    1026                 :                                   double           offset,
    1027                 :                                   double           red,
    1028                 :                                   double           green,
    1029                 :                                   double           blue)
    1030                 : {
    1031               0 :     if (pattern->status)
    1032               0 :         return;
    1033                 : 
    1034               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
    1035               0 :         pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
    1036                 :     {
    1037               0 :         _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    1038               0 :         return;
    1039                 :     }
    1040                 : 
    1041               0 :     offset = _cairo_restrict_value (offset, 0.0, 1.0);
    1042               0 :     red    = _cairo_restrict_value (red,    0.0, 1.0);
    1043               0 :     green  = _cairo_restrict_value (green,  0.0, 1.0);
    1044               0 :     blue   = _cairo_restrict_value (blue,   0.0, 1.0);
    1045                 : 
    1046               0 :     _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
    1047                 :                                    offset, red, green, blue, 1.0);
    1048                 : }
    1049                 : 
    1050                 : /**
    1051                 :  * cairo_pattern_add_color_stop_rgba:
    1052                 :  * @pattern: a #cairo_pattern_t
    1053                 :  * @offset: an offset in the range [0.0 .. 1.0]
    1054                 :  * @red: red component of color
    1055                 :  * @green: green component of color
    1056                 :  * @blue: blue component of color
    1057                 :  * @alpha: alpha component of color
    1058                 :  *
    1059                 :  * Adds a translucent color stop to a gradient pattern. The offset
    1060                 :  * specifies the location along the gradient's control vector. For
    1061                 :  * example, a linear gradient's control vector is from (x0,y0) to
    1062                 :  * (x1,y1) while a radial gradient's control vector is from any point
    1063                 :  * on the start circle to the corresponding point on the end circle.
    1064                 :  *
    1065                 :  * The color is specified in the same way as in cairo_set_source_rgba().
    1066                 :  *
    1067                 :  * If two (or more) stops are specified with identical offset values,
    1068                 :  * they will be sorted according to the order in which the stops are
    1069                 :  * added, (stops added earlier will compare less than stops added
    1070                 :  * later). This can be useful for reliably making sharp color
    1071                 :  * transitions instead of the typical blend.
    1072                 :  *
    1073                 :  * Note: If the pattern is not a gradient pattern, (eg. a linear or
    1074                 :  * radial pattern), then the pattern will be put into an error status
    1075                 :  * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
    1076                 :  */
    1077                 : void
    1078               0 : cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
    1079                 :                                    double          offset,
    1080                 :                                    double          red,
    1081                 :                                    double          green,
    1082                 :                                    double          blue,
    1083                 :                                    double          alpha)
    1084                 : {
    1085               0 :     if (pattern->status)
    1086               0 :         return;
    1087                 : 
    1088               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
    1089               0 :         pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
    1090                 :     {
    1091               0 :         _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    1092               0 :         return;
    1093                 :     }
    1094                 : 
    1095               0 :     offset = _cairo_restrict_value (offset, 0.0, 1.0);
    1096               0 :     red    = _cairo_restrict_value (red,    0.0, 1.0);
    1097               0 :     green  = _cairo_restrict_value (green,  0.0, 1.0);
    1098               0 :     blue   = _cairo_restrict_value (blue,   0.0, 1.0);
    1099               0 :     alpha  = _cairo_restrict_value (alpha,  0.0, 1.0);
    1100                 : 
    1101               0 :     _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
    1102                 :                                    offset, red, green, blue, alpha);
    1103                 : }
    1104                 : 
    1105                 : /**
    1106                 :  * cairo_pattern_set_matrix:
    1107                 :  * @pattern: a #cairo_pattern_t
    1108                 :  * @matrix: a #cairo_matrix_t
    1109                 :  *
    1110                 :  * Sets the pattern's transformation matrix to @matrix. This matrix is
    1111                 :  * a transformation from user space to pattern space.
    1112                 :  *
    1113                 :  * When a pattern is first created it always has the identity matrix
    1114                 :  * for its transformation matrix, which means that pattern space is
    1115                 :  * initially identical to user space.
    1116                 :  *
    1117                 :  * Important: Please note that the direction of this transformation
    1118                 :  * matrix is from user space to pattern space. This means that if you
    1119                 :  * imagine the flow from a pattern to user space (and on to device
    1120                 :  * space), then coordinates in that flow will be transformed by the
    1121                 :  * inverse of the pattern matrix.
    1122                 :  *
    1123                 :  * For example, if you want to make a pattern appear twice as large as
    1124                 :  * it does by default the correct code to use is:
    1125                 :  *
    1126                 :  * <informalexample><programlisting>
    1127                 :  * cairo_matrix_init_scale (&amp;matrix, 0.5, 0.5);
    1128                 :  * cairo_pattern_set_matrix (pattern, &amp;matrix);
    1129                 :  * </programlisting></informalexample>
    1130                 :  *
    1131                 :  * Meanwhile, using values of 2.0 rather than 0.5 in the code above
    1132                 :  * would cause the pattern to appear at half of its default size.
    1133                 :  *
    1134                 :  * Also, please note the discussion of the user-space locking
    1135                 :  * semantics of cairo_set_source().
    1136                 :  **/
    1137                 : void
    1138              28 : cairo_pattern_set_matrix (cairo_pattern_t      *pattern,
    1139                 :                           const cairo_matrix_t *matrix)
    1140                 : {
    1141                 :     cairo_matrix_t inverse;
    1142                 :     cairo_status_t status;
    1143                 : 
    1144              28 :     if (pattern->status)
    1145               0 :         return;
    1146                 : 
    1147              28 :     if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0)
    1148               0 :         return;
    1149                 : 
    1150              28 :     pattern->matrix = *matrix;
    1151                 : 
    1152              28 :     inverse = *matrix;
    1153              28 :     status = cairo_matrix_invert (&inverse);
    1154              28 :     if (unlikely (status))
    1155               0 :         status = _cairo_pattern_set_error (pattern, status);
    1156                 : }
    1157                 : slim_hidden_def (cairo_pattern_set_matrix);
    1158                 : 
    1159                 : /**
    1160                 :  * cairo_pattern_get_matrix:
    1161                 :  * @pattern: a #cairo_pattern_t
    1162                 :  * @matrix: return value for the matrix
    1163                 :  *
    1164                 :  * Stores the pattern's transformation matrix into @matrix.
    1165                 :  **/
    1166                 : void
    1167               0 : cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
    1168                 : {
    1169               0 :     *matrix = pattern->matrix;
    1170               0 : }
    1171                 : 
    1172                 : /**
    1173                 :  * cairo_pattern_set_filter:
    1174                 :  * @pattern: a #cairo_pattern_t
    1175                 :  * @filter: a #cairo_filter_t describing the filter to use for resizing
    1176                 :  * the pattern
    1177                 :  *
    1178                 :  * Sets the filter to be used for resizing when using this pattern.
    1179                 :  * See #cairo_filter_t for details on each filter.
    1180                 :  *
    1181                 :  * * Note that you might want to control filtering even when you do not
    1182                 :  * have an explicit #cairo_pattern_t object, (for example when using
    1183                 :  * cairo_set_source_surface()). In these cases, it is convenient to
    1184                 :  * use cairo_get_source() to get access to the pattern that cairo
    1185                 :  * creates implicitly. For example:
    1186                 :  *
    1187                 :  * <informalexample><programlisting>
    1188                 :  * cairo_set_source_surface (cr, image, x, y);
    1189                 :  * cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
    1190                 :  * </programlisting></informalexample>
    1191                 :  **/
    1192                 : void
    1193               0 : cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
    1194                 : {
    1195               0 :     if (pattern->status)
    1196               0 :         return;
    1197                 : 
    1198               0 :     pattern->filter = filter;
    1199                 : }
    1200                 : 
    1201                 : /**
    1202                 :  * cairo_pattern_get_filter:
    1203                 :  * @pattern: a #cairo_pattern_t
    1204                 :  *
    1205                 :  * Gets the current filter for a pattern.  See #cairo_filter_t
    1206                 :  * for details on each filter.
    1207                 :  *
    1208                 :  * Return value: the current filter used for resizing the pattern.
    1209                 :  **/
    1210                 : cairo_filter_t
    1211               0 : cairo_pattern_get_filter (cairo_pattern_t *pattern)
    1212                 : {
    1213               0 :     return pattern->filter;
    1214                 : }
    1215                 : 
    1216                 : /**
    1217                 :  * cairo_pattern_set_extend:
    1218                 :  * @pattern: a #cairo_pattern_t
    1219                 :  * @extend: a #cairo_extend_t describing how the area outside of the
    1220                 :  * pattern will be drawn
    1221                 :  *
    1222                 :  * Sets the mode to be used for drawing outside the area of a pattern.
    1223                 :  * See #cairo_extend_t for details on the semantics of each extend
    1224                 :  * strategy.
    1225                 :  *
    1226                 :  * The default extend mode is %CAIRO_EXTEND_NONE for surface patterns
    1227                 :  * and %CAIRO_EXTEND_PAD for gradient patterns.
    1228                 :  **/
    1229                 : void
    1230               0 : cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
    1231                 : {
    1232               0 :     if (pattern->status)
    1233               0 :         return;
    1234                 : 
    1235               0 :     pattern->extend = extend;
    1236                 : }
    1237                 : 
    1238                 : /**
    1239                 :  * cairo_pattern_get_extend:
    1240                 :  * @pattern: a #cairo_pattern_t
    1241                 :  *
    1242                 :  * Gets the current extend mode for a pattern.  See #cairo_extend_t
    1243                 :  * for details on the semantics of each extend strategy.
    1244                 :  *
    1245                 :  * Return value: the current extend strategy used for drawing the
    1246                 :  * pattern.
    1247                 :  **/
    1248                 : cairo_extend_t
    1249               0 : cairo_pattern_get_extend (cairo_pattern_t *pattern)
    1250                 : {
    1251               0 :     return pattern->extend;
    1252                 : }
    1253                 : slim_hidden_def (cairo_pattern_get_extend);
    1254                 : 
    1255                 : void
    1256              10 : _cairo_pattern_transform (cairo_pattern_t       *pattern,
    1257                 :                           const cairo_matrix_t  *ctm_inverse)
    1258                 : {
    1259              10 :     if (pattern->status)
    1260               0 :         return;
    1261                 : 
    1262              10 :     cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
    1263                 : }
    1264                 : 
    1265                 : static void
    1266               0 : _cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
    1267                 :                                 double                 offset_x,
    1268                 :                                 double                 offset_y,
    1269                 :                                 int                    width,
    1270                 :                                 int                    height,
    1271                 :                                 cairo_bool_t           *is_horizontal,
    1272                 :                                 cairo_bool_t           *is_vertical)
    1273                 : {
    1274                 :     cairo_point_double_t point0, point1;
    1275                 :     double a, b, c, d, tx, ty;
    1276                 :     double scale, start, dx, dy;
    1277                 :     cairo_fixed_t factors[3];
    1278                 :     int i;
    1279                 : 
    1280                 :     /* To classify a pattern as horizontal or vertical, we first
    1281                 :      * compute the (fixed point) factors at the corners of the
    1282                 :      * pattern. We actually only need 3/4 corners, so we skip the
    1283                 :      * fourth.
    1284                 :      */
    1285               0 :     point0.x = _cairo_fixed_to_double (pattern->p1.x);
    1286               0 :     point0.y = _cairo_fixed_to_double (pattern->p1.y);
    1287               0 :     point1.x = _cairo_fixed_to_double (pattern->p2.x);
    1288               0 :     point1.y = _cairo_fixed_to_double (pattern->p2.y);
    1289                 : 
    1290               0 :     _cairo_matrix_get_affine (&pattern->base.base.matrix,
    1291                 :                               &a, &b, &c, &d, &tx, &ty);
    1292                 : 
    1293               0 :     dx = point1.x - point0.x;
    1294               0 :     dy = point1.y - point0.y;
    1295               0 :     scale = dx * dx + dy * dy;
    1296               0 :     scale = (scale) ? 1.0 / scale : 1.0;
    1297                 : 
    1298               0 :     start = dx * point0.x + dy * point0.y;
    1299                 : 
    1300               0 :     for (i = 0; i < 3; i++) {
    1301               0 :         double qx_device = (i % 2) * (width - 1) + offset_x;
    1302               0 :         double qy_device = (i / 2) * (height - 1) + offset_y;
    1303                 : 
    1304                 :         /* transform fragment into pattern space */
    1305               0 :         double qx = a * qx_device + c * qy_device + tx;
    1306               0 :         double qy = b * qx_device + d * qy_device + ty;
    1307                 : 
    1308               0 :         factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
    1309                 :     }
    1310                 : 
    1311                 :     /* We consider a pattern to be vertical if the fixed point factor
    1312                 :      * at the two upper corners is the same. We could accept a small
    1313                 :      * change, but determining what change is acceptable would require
    1314                 :      * sorting the stops in the pattern and looking at the differences.
    1315                 :      *
    1316                 :      * Horizontal works the same way with the two left corners.
    1317                 :      */
    1318                 : 
    1319               0 :     *is_vertical = factors[1] == factors[0];
    1320               0 :     *is_horizontal = factors[2] == factors[0];
    1321               0 : }
    1322                 : 
    1323                 : static cairo_int_status_t
    1324               0 : _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pattern,
    1325                 :                                              cairo_surface_t            *dst,
    1326                 :                                              int                        x,
    1327                 :                                              int                        y,
    1328                 :                                              unsigned int               width,
    1329                 :                                              unsigned int               height,
    1330                 :                                              cairo_surface_t            **out,
    1331                 :                                              cairo_surface_attributes_t *attr)
    1332                 : {
    1333                 :     cairo_image_surface_t *image;
    1334                 :     pixman_image_t        *pixman_image;
    1335                 :     pixman_transform_t    pixman_transform;
    1336                 :     cairo_status_t        status;
    1337               0 :     cairo_bool_t          repeat = FALSE;
    1338               0 :     cairo_bool_t          opaque = TRUE;
    1339                 : 
    1340                 :     pixman_gradient_stop_t pixman_stops_static[2];
    1341               0 :     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
    1342                 :     unsigned int i;
    1343                 :     int clone_offset_x, clone_offset_y;
    1344               0 :     cairo_matrix_t matrix = pattern->base.matrix;
    1345                 : 
    1346                 :     if (CAIRO_INJECT_FAULT ())
    1347                 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1348                 : 
    1349               0 :     if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
    1350               0 :         pixman_stops = _cairo_malloc_ab (pattern->n_stops,
    1351                 :                                          sizeof(pixman_gradient_stop_t));
    1352               0 :         if (unlikely (pixman_stops == NULL))
    1353               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1354                 :     }
    1355                 : 
    1356               0 :     for (i = 0; i < pattern->n_stops; i++) {
    1357               0 :         pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
    1358               0 :         pixman_stops[i].color.red = pattern->stops[i].color.red_short;
    1359               0 :         pixman_stops[i].color.green = pattern->stops[i].color.green_short;
    1360               0 :         pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
    1361               0 :         pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
    1362               0 :         if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (pixman_stops[i].color.alpha))
    1363               0 :             opaque = FALSE;
    1364                 :     }
    1365                 : 
    1366               0 :     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
    1367                 :     {
    1368               0 :         cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
    1369                 :         pixman_point_fixed_t p1, p2;
    1370                 :         cairo_fixed_t xdim, ydim;
    1371                 : 
    1372               0 :         xdim = linear->p2.x - linear->p1.x;
    1373               0 :         ydim = linear->p2.y - linear->p1.y;
    1374                 : 
    1375                 :         /*
    1376                 :          * Transform the matrix to avoid overflow when converting between
    1377                 :          * cairo_fixed_t and pixman_fixed_t (without incurring performance
    1378                 :          * loss when the transformation is unnecessary).
    1379                 :          *
    1380                 :          * XXX: Consider converting out-of-range co-ordinates and transforms.
    1381                 :          * Having a function to compute the required transformation to
    1382                 :          * "normalize" a given bounding box would be generally useful -
    1383                 :          * cf linear patterns, gradient patterns, surface patterns...
    1384                 :          */
    1385                 : #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
    1386               0 :         if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
    1387               0 :             _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
    1388               0 :         {
    1389                 :             double sf;
    1390                 : 
    1391               0 :             if (xdim > ydim)
    1392               0 :                 sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
    1393                 :             else
    1394               0 :                 sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
    1395                 : 
    1396               0 :             p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
    1397               0 :             p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
    1398               0 :             p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
    1399               0 :             p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
    1400                 : 
    1401               0 :             cairo_matrix_scale (&matrix, sf, sf);
    1402                 :         }
    1403                 :         else
    1404                 :         {
    1405               0 :             p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
    1406               0 :             p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
    1407               0 :             p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
    1408               0 :             p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
    1409                 :         }
    1410                 : 
    1411               0 :         pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
    1412                 :                                                             pixman_stops,
    1413               0 :                                                             pattern->n_stops);
    1414                 :     }
    1415                 :     else
    1416                 :     {
    1417               0 :         cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
    1418                 :         pixman_point_fixed_t c1, c2;
    1419                 :         pixman_fixed_t r1, r2;
    1420                 : 
    1421               0 :         c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
    1422               0 :         c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
    1423               0 :         r1   = _cairo_fixed_to_16_16 (radial->r1);
    1424                 : 
    1425               0 :         c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
    1426               0 :         c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
    1427               0 :         r2   = _cairo_fixed_to_16_16 (radial->r2);
    1428                 : 
    1429               0 :         pixman_image = pixman_image_create_radial_gradient (&c1, &c2,
    1430                 :                                                             r1, r2,
    1431                 :                                                             pixman_stops,
    1432               0 :                                                             pattern->n_stops);
    1433                 :     }
    1434                 : 
    1435               0 :     if (pixman_stops != pixman_stops_static)
    1436               0 :         free (pixman_stops);
    1437                 : 
    1438               0 :     if (unlikely (pixman_image == NULL))
    1439               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1440                 : 
    1441               0 :     if (_cairo_surface_is_image (dst))
    1442                 :     {
    1443               0 :         image = (cairo_image_surface_t *)
    1444               0 :             _cairo_image_surface_create_for_pixman_image (pixman_image,
    1445                 :                                                           PIXMAN_a8r8g8b8);
    1446               0 :         if (image->base.status)
    1447                 :         {
    1448               0 :             pixman_image_unref (pixman_image);
    1449               0 :             return image->base.status;
    1450                 :         }
    1451                 : 
    1452               0 :         attr->x_offset = attr->y_offset = 0;
    1453               0 :         attr->matrix = matrix;
    1454               0 :         attr->extend = pattern->base.extend;
    1455               0 :         attr->filter = CAIRO_FILTER_NEAREST;
    1456               0 :         attr->has_component_alpha = pattern->base.has_component_alpha;
    1457                 : 
    1458               0 :         *out = &image->base;
    1459                 : 
    1460               0 :         return CAIRO_STATUS_SUCCESS;
    1461                 :     }
    1462                 : 
    1463               0 :     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
    1464                 :         cairo_bool_t is_horizontal;
    1465                 :         cairo_bool_t is_vertical;
    1466                 : 
    1467               0 :         _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
    1468                 :                                         x, y, width, height,
    1469                 :                                         &is_horizontal, &is_vertical);
    1470               0 :         if (is_horizontal) {
    1471               0 :             height = 1;
    1472               0 :             repeat = TRUE;
    1473                 :         }
    1474                 :         /* width-1 repeating patterns are quite slow with scan-line based
    1475                 :          * compositing code, so we use a wider strip and spend some extra
    1476                 :          * expense in computing the gradient. It's possible that for narrow
    1477                 :          * gradients we'd be better off using a 2 or 4 pixel strip; the
    1478                 :          * wider the gradient, the more it's worth spending extra time
    1479                 :          * computing a sample.
    1480                 :          */
    1481               0 :         if (is_vertical && width > 8) {
    1482               0 :             width = 8;
    1483               0 :             repeat = TRUE;
    1484                 :         }
    1485                 :     }
    1486                 : 
    1487               0 :     if (! pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR,
    1488                 :                                    NULL, 0))
    1489                 :     {
    1490               0 :         pixman_image_unref (pixman_image);
    1491               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1492                 :     }
    1493                 : 
    1494               0 :     image = (cairo_image_surface_t *)
    1495               0 :         cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
    1496               0 :     if (image->base.status) {
    1497               0 :         pixman_image_unref (pixman_image);
    1498               0 :         return image->base.status;
    1499                 :     }
    1500                 : 
    1501               0 :     _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform,
    1502                 :                                     width/2., height/2.);
    1503               0 :     if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
    1504               0 :         cairo_surface_destroy (&image->base);
    1505               0 :         pixman_image_unref (pixman_image);
    1506               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1507                 :     }
    1508                 : 
    1509               0 :     switch (pattern->base.extend) {
    1510                 :     case CAIRO_EXTEND_NONE:
    1511               0 :         pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE);
    1512               0 :         break;
    1513                 :     case CAIRO_EXTEND_REPEAT:
    1514               0 :         pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL);
    1515               0 :         break;
    1516                 :     case CAIRO_EXTEND_REFLECT:
    1517               0 :         pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT);
    1518               0 :         break;
    1519                 :     case CAIRO_EXTEND_PAD:
    1520               0 :         pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD);
    1521               0 :         break;
    1522                 :     }
    1523                 : 
    1524               0 :     pixman_image_composite32 (PIXMAN_OP_SRC,
    1525                 :                               pixman_image,
    1526                 :                               NULL,
    1527                 :                               image->pixman_image,
    1528                 :                               x, y,
    1529                 :                               0, 0,
    1530                 :                               0, 0,
    1531                 :                               width, height);
    1532                 : 
    1533               0 :     pixman_image_unref (pixman_image);
    1534                 : 
    1535                 :     _cairo_debug_check_image_surface_is_defined (&image->base);
    1536                 : 
    1537               0 :     status = _cairo_surface_clone_similar (dst, &image->base,
    1538                 :                                            0, 0, width, height,
    1539                 :                                            &clone_offset_x,
    1540                 :                                            &clone_offset_y,
    1541                 :                                            out);
    1542                 : 
    1543               0 :     cairo_surface_destroy (&image->base);
    1544                 : 
    1545               0 :     attr->x_offset = -x;
    1546               0 :     attr->y_offset = -y;
    1547               0 :     cairo_matrix_init_identity (&attr->matrix);
    1548               0 :     attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
    1549               0 :     attr->filter = CAIRO_FILTER_NEAREST;
    1550               0 :     attr->has_component_alpha = pattern->base.has_component_alpha;
    1551                 : 
    1552               0 :     return status;
    1553                 : }
    1554                 : 
    1555                 : /* We maintain a small cache here, because we don't want to constantly
    1556                 :  * recreate surfaces for simple solid colors. */
    1557                 : #define MAX_SURFACE_CACHE_SIZE 16
    1558                 : static struct {
    1559                 :     struct _cairo_pattern_solid_surface_cache{
    1560                 :         cairo_color_t    color;
    1561                 :         cairo_surface_t *surface;
    1562                 :     } cache[MAX_SURFACE_CACHE_SIZE];
    1563                 :     int size;
    1564                 : } solid_surface_cache;
    1565                 : 
    1566                 : static cairo_bool_t
    1567               0 : _cairo_pattern_solid_surface_matches (
    1568                 :         const struct _cairo_pattern_solid_surface_cache     *cache,
    1569                 :         const cairo_solid_pattern_t                         *pattern,
    1570                 :         cairo_surface_t                                     *dst)
    1571                 : {
    1572               0 :     if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color))
    1573               0 :         return FALSE;
    1574                 : 
    1575               0 :     if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
    1576               0 :         return FALSE;
    1577                 : 
    1578               0 :     if (! _cairo_surface_is_similar (cache->surface, dst))
    1579               0 :         return FALSE;
    1580                 : 
    1581               0 :     return TRUE;
    1582                 : }
    1583                 : 
    1584                 : static cairo_bool_t
    1585               0 : _cairo_pattern_solid_surface_matches_color (
    1586                 :         const struct _cairo_pattern_solid_surface_cache     *cache,
    1587                 :         const cairo_solid_pattern_t                         *pattern,
    1588                 :         cairo_surface_t                                     *dst)
    1589                 : {
    1590               0 :     if (! _cairo_color_equal (&cache->color, &pattern->color))
    1591               0 :         return FALSE;
    1592                 : 
    1593               0 :     return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
    1594                 : }
    1595                 : 
    1596                 : static cairo_int_status_t
    1597               0 : _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t        *pattern,
    1598                 :                                           cairo_surface_t            *dst,
    1599                 :                                           int                        x,
    1600                 :                                           int                        y,
    1601                 :                                           unsigned int               width,
    1602                 :                                           unsigned int               height,
    1603                 :                                           cairo_surface_t            **out,
    1604                 :                                           cairo_surface_attributes_t *attribs)
    1605                 : {
    1606                 :     static int i;
    1607                 : 
    1608               0 :     cairo_surface_t *surface, *to_destroy = NULL;
    1609                 :     cairo_status_t   status;
    1610                 : 
    1611                 :     CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
    1612                 : 
    1613                 :     /* Check cache first */
    1614               0 :     if (i < solid_surface_cache.size &&
    1615               0 :         _cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
    1616                 :                                                     pattern,
    1617                 :                                                     dst))
    1618                 :     {
    1619               0 :         goto DONE;
    1620                 :     }
    1621                 : 
    1622               0 :     for (i = 0 ; i < solid_surface_cache.size; i++) {
    1623               0 :         if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
    1624                 :                                                         pattern,
    1625                 :                                                         dst))
    1626                 :         {
    1627               0 :             goto DONE;
    1628                 :         }
    1629                 :     }
    1630                 : 
    1631                 :     /* Choose a surface to repaint/evict */
    1632               0 :     surface = NULL;
    1633               0 :     if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
    1634               0 :         i = rand () % MAX_SURFACE_CACHE_SIZE;
    1635               0 :         surface = solid_surface_cache.cache[i].surface;
    1636                 : 
    1637               0 :         if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
    1638                 :                                                   pattern,
    1639                 :                                                   dst))
    1640                 :         {
    1641                 :             /* Reuse the surface instead of evicting */
    1642               0 :             status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
    1643               0 :             if (unlikely (status))
    1644               0 :                 goto EVICT;
    1645                 : 
    1646               0 :             cairo_surface_reference (surface);
    1647                 :         }
    1648                 :         else
    1649                 :         {
    1650                 :           EVICT:
    1651               0 :             surface = NULL;
    1652                 :         }
    1653                 :     }
    1654                 : 
    1655               0 :     if (surface == NULL) {
    1656                 :         /* Not cached, need to create new */
    1657               0 :         surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
    1658               0 :         if (surface == NULL) {
    1659               0 :             status = CAIRO_INT_STATUS_UNSUPPORTED;
    1660               0 :             goto UNLOCK;
    1661                 :         }
    1662               0 :         if (unlikely (surface->status)) {
    1663               0 :             status = surface->status;
    1664               0 :             goto UNLOCK;
    1665                 :         }
    1666                 : 
    1667               0 :         if (unlikely (! _cairo_surface_is_similar (surface, dst)))
    1668                 :         {
    1669                 :             /* In the rare event of a substitute surface being returned,
    1670                 :              * don't cache the fallback.
    1671                 :              */
    1672               0 :             *out = surface;
    1673               0 :             goto NOCACHE;
    1674                 :         }
    1675                 :     }
    1676                 : 
    1677               0 :     if (i == solid_surface_cache.size)
    1678               0 :         solid_surface_cache.size++;
    1679                 : 
    1680               0 :     to_destroy = solid_surface_cache.cache[i].surface;
    1681               0 :     solid_surface_cache.cache[i].surface = surface;
    1682               0 :     solid_surface_cache.cache[i].color   = pattern->color;
    1683                 : 
    1684                 : DONE:
    1685               0 :     *out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
    1686                 : 
    1687                 : NOCACHE:
    1688               0 :     attribs->x_offset = attribs->y_offset = 0;
    1689               0 :     cairo_matrix_init_identity (&attribs->matrix);
    1690               0 :     attribs->extend = CAIRO_EXTEND_REPEAT;
    1691               0 :     attribs->filter = CAIRO_FILTER_NEAREST;
    1692               0 :     attribs->has_component_alpha = pattern->base.has_component_alpha;
    1693                 : 
    1694               0 :     status = CAIRO_STATUS_SUCCESS;
    1695                 : 
    1696                 : UNLOCK:
    1697                 :     CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
    1698                 : 
    1699               0 :     if (to_destroy)
    1700               0 :       cairo_surface_destroy (to_destroy);
    1701                 : 
    1702               0 :     return status;
    1703                 : }
    1704                 : 
    1705                 : static void
    1706               3 : _cairo_pattern_reset_solid_surface_cache (void)
    1707                 : {
    1708                 :     CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
    1709                 : 
    1710                 :     /* remove surfaces starting from the end so that solid_surface_cache.cache
    1711                 :      * is always in a consistent state when we release the mutex. */
    1712               6 :     while (solid_surface_cache.size) {
    1713                 :         cairo_surface_t *surface;
    1714                 : 
    1715               0 :         solid_surface_cache.size--;
    1716               0 :         surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
    1717               0 :         solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
    1718                 : 
    1719                 :         /* release the lock to avoid the possibility of a recursive
    1720                 :          * deadlock when the surface destroy closure gets called */
    1721                 :         CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
    1722               0 :         cairo_surface_destroy (surface);
    1723                 :         CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
    1724                 :     }
    1725                 : 
    1726                 :     CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
    1727               3 : }
    1728                 : 
    1729                 : static void
    1730               0 : _extents_to_linear_parameter (const cairo_linear_pattern_t *linear,
    1731                 :                               const cairo_rectangle_int_t *extents,
    1732                 :                               double t[2])
    1733                 : {
    1734                 :     double t0, tdx, tdy;
    1735                 :     double p1x, p1y, pdx, pdy, invsqnorm;
    1736                 : 
    1737               0 :     p1x = _cairo_fixed_to_double (linear->p1.x);
    1738               0 :     p1y = _cairo_fixed_to_double (linear->p1.y);
    1739               0 :     pdx = _cairo_fixed_to_double (linear->p2.x) - p1x;
    1740               0 :     pdy = _cairo_fixed_to_double (linear->p2.y) - p1y;
    1741               0 :     invsqnorm = 1.0 / (pdx * pdx + pdy * pdy);
    1742               0 :     pdx *= invsqnorm;
    1743               0 :     pdy *= invsqnorm;
    1744                 : 
    1745               0 :     t0 = (extents->x - p1x) * pdx + (extents->y - p1y) * pdy;
    1746               0 :     tdx = extents->width * pdx;
    1747               0 :     tdy = extents->height * pdy;
    1748                 : 
    1749               0 :     t[0] = t[1] = t0;
    1750               0 :     if (tdx < 0)
    1751               0 :         t[0] += tdx;
    1752                 :     else
    1753               0 :         t[1] += tdx;
    1754                 : 
    1755               0 :     if (tdy < 0)
    1756               0 :         t[0] += tdy;
    1757                 :     else
    1758               0 :         t[1] += tdy;
    1759               0 : }
    1760                 : 
    1761                 : static cairo_bool_t
    1762               0 : _linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
    1763                 : {
    1764               0 :     return linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y;
    1765                 : }
    1766                 : 
    1767                 : static cairo_bool_t
    1768               0 : _radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial)
    1769                 : {
    1770               0 :     return radial->r1 == radial->r2 &&
    1771               0 :         (radial->r1 == 0 /* && radial->r2 == 0 */ ||
    1772               0 :          (radial->c1.x == radial->c2.x && radial->c1.y == radial->c2.y));
    1773                 : }
    1774                 : 
    1775                 : static cairo_bool_t
    1776               0 : _gradient_is_clear (const cairo_gradient_pattern_t *gradient,
    1777                 :                     const cairo_rectangle_int_t *extents)
    1778                 : {
    1779                 :     unsigned int i;
    1780                 : 
    1781               0 :     assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
    1782                 :             gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
    1783                 : 
    1784               0 :     if (gradient->n_stops == 0 ||
    1785               0 :         (gradient->base.extend == CAIRO_EXTEND_NONE &&
    1786               0 :          gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
    1787               0 :         return TRUE;
    1788                 : 
    1789                 :     /* Check if the extents intersect the drawn part of the pattern. */
    1790               0 :     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
    1791               0 :         if (gradient->base.extend == CAIRO_EXTEND_NONE) {
    1792               0 :             cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
    1793                 :             /* EXTEND_NONE degenerate linear gradients are clear */
    1794               0 :             if (_linear_pattern_is_degenerate (linear))
    1795               0 :                 return TRUE;
    1796                 : 
    1797               0 :             if (extents != NULL) {
    1798                 :                 double t[2];
    1799               0 :                 _extents_to_linear_parameter (linear, extents, t);
    1800               0 :                 if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0))
    1801               0 :                     return TRUE;
    1802                 :             }
    1803                 :         }
    1804                 :     } else {
    1805               0 :         cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
    1806                 :         /* degenerate radial gradients are clear */
    1807               0 :         if (_radial_pattern_is_degenerate (radial) && FALSE)
    1808                 :             return TRUE;
    1809                 :         /* TODO: check actual intersection */
    1810                 :     }
    1811                 : 
    1812               0 :     for (i = 0; i < gradient->n_stops; i++)
    1813               0 :         if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color))
    1814               0 :             return FALSE;
    1815                 : 
    1816               0 :     return TRUE;
    1817                 : }
    1818                 : 
    1819                 : /**
    1820                 :  * _cairo_gradient_pattern_is_solid
    1821                 :  *
    1822                 :  * Convenience function to determine whether a gradient pattern is
    1823                 :  * a solid color within the given extents. In this case the color
    1824                 :  * argument is initialized to the color the pattern represents.
    1825                 :  * This functions doesn't handle completely transparent gradients,
    1826                 :  * thus it should be called only after _cairo_pattern_is_clear has
    1827                 :  * returned FALSE.
    1828                 :  *
    1829                 :  * Return value: %TRUE if the pattern is a solid color.
    1830                 :  **/
    1831                 : cairo_bool_t
    1832               0 : _cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
    1833                 :                                   const cairo_rectangle_int_t *extents,
    1834                 :                                   cairo_color_t *color)
    1835                 : {
    1836                 :     unsigned int i;
    1837                 : 
    1838               0 :     assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
    1839                 :             gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
    1840                 : 
    1841                 :     /* TODO: radial, degenerate linear */
    1842               0 :     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
    1843               0 :         if (gradient->base.extend == CAIRO_EXTEND_NONE) {
    1844               0 :             cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
    1845                 :             double t[2];
    1846                 : 
    1847                 :             /* We already know that the pattern is not clear, thus if some
    1848                 :              * part of it is clear, the whole is not solid.
    1849                 :              */
    1850                 : 
    1851               0 :             if (extents == NULL)
    1852               0 :                 return FALSE;
    1853                 : 
    1854               0 :             _extents_to_linear_parameter (linear, extents, t);
    1855               0 :             if (t[0] < 0.0 || t[1] > 1.0)
    1856               0 :                 return FALSE;
    1857                 :         }
    1858                 :     }
    1859                 : 
    1860               0 :     for (i = 1; i < gradient->n_stops; i++)
    1861               0 :         if (! _cairo_color_stop_equal (&gradient->stops[0].color,
    1862               0 :                                        &gradient->stops[i].color))
    1863               0 :             return FALSE;
    1864                 : 
    1865               0 :     _cairo_color_init_rgba (color,
    1866               0 :                             gradient->stops[0].color.red,
    1867               0 :                             gradient->stops[0].color.green,
    1868               0 :                             gradient->stops[0].color.blue,
    1869               0 :                             gradient->stops[0].color.alpha);
    1870                 : 
    1871               0 :     return TRUE;
    1872                 : }
    1873                 : 
    1874                 : /**
    1875                 :  * _cairo_pattern_is_opaque_solid
    1876                 :  *
    1877                 :  * Convenience function to determine whether a pattern is an opaque
    1878                 :  * (alpha==1.0) solid color pattern. This is done by testing whether
    1879                 :  * the pattern's alpha value when converted to a byte is 255, so if a
    1880                 :  * backend actually supported deep alpha channels this function might
    1881                 :  * not do the right thing.
    1882                 :  *
    1883                 :  * Return value: %TRUE if the pattern is an opaque, solid color.
    1884                 :  **/
    1885                 : cairo_bool_t
    1886               0 : _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
    1887                 : {
    1888                 :     cairo_solid_pattern_t *solid;
    1889                 : 
    1890               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
    1891               0 :         return FALSE;
    1892                 : 
    1893               0 :     solid = (cairo_solid_pattern_t *) pattern;
    1894                 : 
    1895               0 :     return CAIRO_COLOR_IS_OPAQUE (&solid->color);
    1896                 : }
    1897                 : 
    1898                 : static cairo_bool_t
    1899               0 : _surface_is_opaque (const cairo_surface_pattern_t *pattern,
    1900                 :                     const cairo_rectangle_int_t *r)
    1901                 : {
    1902               0 :     if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
    1903               0 :         return FALSE;
    1904                 : 
    1905               0 :     if (pattern->base.extend != CAIRO_EXTEND_NONE)
    1906               0 :         return TRUE;
    1907                 : 
    1908               0 :     if (r != NULL) {
    1909                 :         cairo_rectangle_int_t extents;
    1910                 : 
    1911               0 :         if (! _cairo_surface_get_extents (pattern->surface, &extents))
    1912               0 :             return TRUE;
    1913                 : 
    1914               0 :         if (r->x >= extents.x &&
    1915               0 :             r->y >= extents.y &&
    1916               0 :             r->x + r->width <= extents.x + extents.width &&
    1917               0 :             r->y + r->height <= extents.y + extents.height)
    1918                 :         {
    1919               0 :             return TRUE;
    1920                 :         }
    1921                 :     }
    1922                 : 
    1923               0 :     return FALSE;
    1924                 : }
    1925                 : 
    1926                 : static cairo_bool_t
    1927              47 : _surface_is_clear (const cairo_surface_pattern_t *pattern)
    1928                 : {
    1929                 :     cairo_rectangle_int_t extents;
    1930                 : 
    1931              94 :     if (_cairo_surface_get_extents (pattern->surface, &extents) &&
    1932              94 :         (extents.width == 0 || extents.height == 0))
    1933               0 :         return TRUE;
    1934                 : 
    1935              47 :     return pattern->surface->is_clear &&
    1936               0 :         pattern->surface->content & CAIRO_CONTENT_ALPHA;
    1937                 : }
    1938                 : 
    1939                 : static cairo_bool_t
    1940               0 : _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
    1941                 :                      const cairo_rectangle_int_t *extents)
    1942                 : {
    1943                 :     unsigned int i;
    1944                 : 
    1945               0 :     assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
    1946                 :             gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
    1947                 : 
    1948               0 :     if (gradient->n_stops == 0 ||
    1949               0 :         (gradient->base.extend == CAIRO_EXTEND_NONE &&
    1950               0 :          gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
    1951               0 :         return FALSE;
    1952                 : 
    1953               0 :     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
    1954               0 :         if (gradient->base.extend == CAIRO_EXTEND_NONE) {
    1955                 :             double t[2];
    1956               0 :             cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
    1957                 : 
    1958                 :             /* EXTEND_NONE degenerate radial gradients are clear */
    1959               0 :             if (_linear_pattern_is_degenerate (linear))
    1960               0 :                 return FALSE;
    1961                 : 
    1962               0 :             if (extents == NULL)
    1963               0 :                 return FALSE;
    1964                 : 
    1965               0 :             _extents_to_linear_parameter (linear, extents, t);
    1966               0 :             if (t[0] < 0.0 || t[1] > 1.0)
    1967               0 :                 return FALSE;
    1968                 :         }
    1969                 :     }
    1970                 : 
    1971               0 :     for (i = 0; i < gradient->n_stops; i++)
    1972               0 :         if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color))
    1973               0 :             return FALSE;
    1974                 : 
    1975               0 :     return TRUE;
    1976                 : }
    1977                 : 
    1978                 : /**
    1979                 :  * _cairo_pattern_is_opaque
    1980                 :  *
    1981                 :  * Convenience function to determine whether a pattern is an opaque
    1982                 :  * pattern (of any type). The same caveats that apply to
    1983                 :  * _cairo_pattern_is_opaque_solid apply here as well.
    1984                 :  *
    1985                 :  * Return value: %TRUE if the pattern is a opaque.
    1986                 :  **/
    1987                 : cairo_bool_t
    1988               0 : _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
    1989                 :                           const cairo_rectangle_int_t *extents)
    1990                 : {
    1991                 :     const cairo_pattern_union_t *pattern;
    1992                 : 
    1993               0 :     if (abstract_pattern->has_component_alpha)
    1994               0 :         return FALSE;
    1995                 : 
    1996               0 :     pattern = (cairo_pattern_union_t *) abstract_pattern;
    1997               0 :     switch (pattern->base.type) {
    1998                 :     case CAIRO_PATTERN_TYPE_SOLID:
    1999               0 :         return _cairo_pattern_is_opaque_solid (abstract_pattern);
    2000                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    2001               0 :         return _surface_is_opaque (&pattern->surface, extents);
    2002                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    2003                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    2004               0 :         return _gradient_is_opaque (&pattern->gradient.base, extents);
    2005                 :     }
    2006                 : 
    2007               0 :     ASSERT_NOT_REACHED;
    2008               0 :     return FALSE;
    2009                 : }
    2010                 : 
    2011                 : cairo_bool_t
    2012              47 : _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
    2013                 : {
    2014                 :     const cairo_pattern_union_t *pattern;
    2015                 : 
    2016              47 :     if (abstract_pattern->has_component_alpha)
    2017               0 :         return FALSE;
    2018                 : 
    2019              47 :     pattern = (cairo_pattern_union_t *) abstract_pattern;
    2020              47 :     switch (pattern->type) {
    2021                 :     case CAIRO_PATTERN_TYPE_SOLID:
    2022               0 :         return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color);
    2023                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    2024              47 :         return _surface_is_clear (&pattern->surface);
    2025                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    2026                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    2027               0 :         return _gradient_is_clear (&pattern->gradient.base, NULL);
    2028                 :     }
    2029                 : 
    2030               0 :     ASSERT_NOT_REACHED;
    2031               0 :     return FALSE;
    2032                 : }
    2033                 : 
    2034                 : /**
    2035                 :  * _cairo_pattern_analyze_filter:
    2036                 :  * @pattern: surface pattern
    2037                 :  * @pad_out: location to store necessary padding in the source image, or %NULL
    2038                 :  * Returns: the optimized #cairo_filter_t to use with @pattern.
    2039                 :  *
    2040                 :  * Analyze the filter to determine how much extra needs to be sampled
    2041                 :  * from the source image to account for the filter radius and whether
    2042                 :  * we can optimize the filter to a simpler value.
    2043                 :  *
    2044                 :  * XXX: We don't actually have any way of querying the backend for
    2045                 :  *      the filter radius, so we just guess base on what we know that
    2046                 :  *      backends do currently (see bug #10508)
    2047                 :  */
    2048                 : cairo_filter_t
    2049              94 : _cairo_pattern_analyze_filter (const cairo_pattern_t    *pattern,
    2050                 :                                double                   *pad_out)
    2051                 : {
    2052                 :     double pad;
    2053                 :     cairo_filter_t optimized_filter;
    2054                 : 
    2055              94 :     switch (pattern->filter) {
    2056                 :     case CAIRO_FILTER_GOOD:
    2057                 :     case CAIRO_FILTER_BEST:
    2058                 :     case CAIRO_FILTER_BILINEAR:
    2059                 :         /* If source pixels map 1:1 onto destination pixels, we do
    2060                 :          * not need to filter (and do not want to filter, since it
    2061                 :          * will cause blurriness)
    2062                 :          */
    2063              94 :         if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
    2064              74 :             pad = 0.;
    2065              74 :             optimized_filter = CAIRO_FILTER_NEAREST;
    2066                 :         } else {
    2067                 :             /* 0.5 is enough for a bilinear filter. It's possible we
    2068                 :              * should defensively use more for CAIRO_FILTER_BEST, but
    2069                 :              * without a single example, it's hard to know how much
    2070                 :              * more would be defensive...
    2071                 :              */
    2072              20 :             pad = 0.5;
    2073              20 :             optimized_filter = pattern->filter;
    2074                 :         }
    2075              94 :         break;
    2076                 : 
    2077                 :     case CAIRO_FILTER_FAST:
    2078                 :     case CAIRO_FILTER_NEAREST:
    2079                 :     case CAIRO_FILTER_GAUSSIAN:
    2080                 :     default:
    2081               0 :         pad = 0.;
    2082               0 :         optimized_filter = pattern->filter;
    2083               0 :         break;
    2084                 :     }
    2085                 : 
    2086              94 :     if (pad_out)
    2087              94 :         *pad_out = pad;
    2088                 : 
    2089              94 :     return optimized_filter;
    2090                 : }
    2091                 : 
    2092                 : 
    2093                 : static double
    2094               0 : _pixman_nearest_sample (double d)
    2095                 : {
    2096               0 :     return ceil (d - .5);
    2097                 : }
    2098                 : 
    2099                 : static cairo_int_status_t
    2100               0 : _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pattern,
    2101                 :                                             cairo_surface_t            *dst,
    2102                 :                                             int                        x,
    2103                 :                                             int                        y,
    2104                 :                                             unsigned int               width,
    2105                 :                                             unsigned int               height,
    2106                 :                                             unsigned int               flags,
    2107                 :                                             cairo_surface_t            **out,
    2108                 :                                             cairo_surface_attributes_t *attr)
    2109                 : {
    2110                 :     cairo_surface_t *surface;
    2111                 :     cairo_rectangle_int_t extents;
    2112                 :     cairo_rectangle_int_t sampled_area;
    2113                 :     double x1, y1, x2, y2;
    2114                 :     int tx, ty;
    2115                 :     double pad;
    2116                 :     cairo_bool_t is_identity;
    2117                 :     cairo_bool_t is_empty;
    2118                 :     cairo_bool_t is_bounded;
    2119                 :     cairo_int_status_t status;
    2120                 : 
    2121               0 :     surface = cairo_surface_reference (pattern->surface);
    2122                 : 
    2123               0 :     is_identity = FALSE;
    2124               0 :     attr->matrix = pattern->base.matrix;
    2125               0 :     attr->extend = pattern->base.extend;
    2126               0 :     attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
    2127               0 :     attr->has_component_alpha = pattern->base.has_component_alpha;
    2128                 : 
    2129               0 :     attr->x_offset = attr->y_offset = tx = ty = 0;
    2130               0 :     if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
    2131               0 :         cairo_matrix_init_identity (&attr->matrix);
    2132               0 :         attr->x_offset = tx;
    2133               0 :         attr->y_offset = ty;
    2134               0 :         is_identity = TRUE;
    2135               0 :     } else if (attr->filter == CAIRO_FILTER_NEAREST) {
    2136                 :         /*
    2137                 :          * For NEAREST, we can remove the fractional translation component
    2138                 :          * from the transformation - this ensures that the pattern will always
    2139                 :          * hit fast-paths in the backends for simple transformations that
    2140                 :          * become (almost) identity, without loss of quality.
    2141                 :          */
    2142               0 :         attr->matrix.x0 = 0;
    2143               0 :         attr->matrix.y0 = 0;
    2144               0 :         if (_cairo_matrix_is_pixel_exact (&attr->matrix)) {
    2145                 :             /* The rounding here is rather peculiar as it needs to match the
    2146                 :              * rounding performed on the sample coordinate used by pixman.
    2147                 :              */
    2148               0 :             attr->matrix.x0 = _pixman_nearest_sample (pattern->base.matrix.x0);
    2149               0 :             attr->matrix.y0 = _pixman_nearest_sample (pattern->base.matrix.y0);
    2150                 :         } else {
    2151               0 :             attr->matrix.x0 = pattern->base.matrix.x0;
    2152               0 :             attr->matrix.y0 = pattern->base.matrix.y0;
    2153                 :         }
    2154                 : 
    2155               0 :         if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
    2156               0 :             cairo_matrix_init_identity (&attr->matrix);
    2157               0 :             attr->x_offset = tx;
    2158               0 :             attr->y_offset = ty;
    2159               0 :             is_identity = TRUE;
    2160                 :         }
    2161                 :     }
    2162                 : 
    2163                 :     /* XXX: Hack:
    2164                 :      *
    2165                 :      * The way we currently support CAIRO_EXTEND_REFLECT is to create
    2166                 :      * an image twice bigger on each side, and create a pattern of four
    2167                 :      * images such that the new image, when repeated, has the same effect
    2168                 :      * of reflecting the original pattern.
    2169                 :      */
    2170               0 :     if (flags & CAIRO_PATTERN_ACQUIRE_NO_REFLECT &&
    2171               0 :         attr->extend == CAIRO_EXTEND_REFLECT)
    2172                 :     {
    2173                 :         cairo_t *cr;
    2174                 :         cairo_surface_t *src;
    2175                 :         int w, h;
    2176                 : 
    2177               0 :         is_bounded = _cairo_surface_get_extents (surface, &extents);
    2178               0 :         assert (is_bounded);
    2179                 : 
    2180               0 :         status = _cairo_surface_clone_similar (dst, surface,
    2181                 :                                                extents.x, extents.y,
    2182                 :                                                extents.width, extents.height,
    2183                 :                                                &extents.x, &extents.y, &src);
    2184               0 :         if (unlikely (status))
    2185               0 :             goto BAIL;
    2186                 : 
    2187               0 :         w = 2 * extents.width;
    2188               0 :         h = 2 * extents.height;
    2189                 : 
    2190               0 :         if (is_identity) {
    2191               0 :             attr->x_offset = -x;
    2192               0 :             x += tx;
    2193               0 :             while (x <= -w)
    2194               0 :                 x += w;
    2195               0 :             while (x >= w)
    2196               0 :                 x -= w;
    2197               0 :             extents.x += x;
    2198               0 :             tx = x = 0;
    2199                 : 
    2200               0 :             attr->y_offset = -y;
    2201               0 :             y += ty;
    2202               0 :             while (y <= -h)
    2203               0 :                 y += h;
    2204               0 :             while (y >= h)
    2205               0 :                 y -= h;
    2206               0 :             extents.y += y;
    2207               0 :             ty = y = 0;
    2208                 :         }
    2209                 : 
    2210               0 :         cairo_surface_destroy (surface);
    2211               0 :         surface = _cairo_surface_create_similar_solid (dst,
    2212                 :                                                        dst->content, w, h,
    2213                 :                                                        CAIRO_COLOR_TRANSPARENT,
    2214                 :                                                        FALSE);
    2215               0 :         if (surface == NULL)
    2216               0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
    2217               0 :         if (unlikely (surface->status)) {
    2218               0 :             cairo_surface_destroy (src);
    2219               0 :             return surface->status;
    2220                 :         }
    2221                 : 
    2222               0 :         surface->device_transform = pattern->surface->device_transform;
    2223               0 :         surface->device_transform_inverse = pattern->surface->device_transform_inverse;
    2224                 : 
    2225               0 :         cr = cairo_create (surface);
    2226                 : 
    2227               0 :         cairo_set_source_surface (cr, src, -extents.x, -extents.y);
    2228               0 :         cairo_paint (cr);
    2229                 : 
    2230               0 :         cairo_scale (cr, -1, +1);
    2231               0 :         cairo_set_source_surface (cr, src, extents.x-w, -extents.y);
    2232               0 :         cairo_paint (cr);
    2233               0 :         cairo_set_source_surface (cr, src, extents.x, -extents.y);
    2234               0 :         cairo_paint (cr);
    2235                 : 
    2236               0 :         cairo_scale (cr, +1, -1);
    2237               0 :         cairo_set_source_surface (cr, src, extents.x-w, extents.y-h);
    2238               0 :         cairo_paint (cr);
    2239               0 :         cairo_set_source_surface (cr, src, extents.x, extents.y-h);
    2240               0 :         cairo_paint (cr);
    2241               0 :         cairo_set_source_surface (cr, src, extents.x-w, extents.y);
    2242               0 :         cairo_paint (cr);
    2243               0 :         cairo_set_source_surface (cr, src, extents.x, extents.y);
    2244               0 :         cairo_paint (cr);
    2245                 : 
    2246               0 :         cairo_scale (cr, -1, +1);
    2247               0 :         cairo_set_source_surface (cr, src, -extents.x, extents.y-h);
    2248               0 :         cairo_paint (cr);
    2249               0 :         cairo_set_source_surface (cr, src, -extents.x, extents.y);
    2250               0 :         cairo_paint (cr);
    2251                 : 
    2252               0 :         status = cairo_status (cr);
    2253               0 :         cairo_destroy (cr);
    2254                 : 
    2255               0 :         cairo_surface_destroy (src);
    2256                 : 
    2257               0 :         if (unlikely (status))
    2258               0 :             goto BAIL;
    2259                 : 
    2260               0 :         attr->extend = CAIRO_EXTEND_REPEAT;
    2261                 :     }
    2262                 : 
    2263                 :     /* We first transform the rectangle to the coordinate space of the
    2264                 :      * source surface so that we only need to clone that portion of the
    2265                 :      * surface that will be read.
    2266                 :      */
    2267               0 :     x1 = x;
    2268               0 :     y1 = y;
    2269               0 :     x2 = x + (int) width;
    2270               0 :     y2 = y + (int) height;
    2271               0 :     if (! is_identity) {
    2272               0 :         _cairo_matrix_transform_bounding_box (&attr->matrix,
    2273                 :                                               &x1, &y1, &x2, &y2,
    2274                 :                                               NULL);
    2275                 :     }
    2276                 : 
    2277               0 :     sampled_area.x = floor (x1 - pad);
    2278               0 :     sampled_area.y = floor (y1 - pad);
    2279               0 :     sampled_area.width  = ceil (x2 + pad) - sampled_area.x;
    2280               0 :     sampled_area.height = ceil (y2 + pad) - sampled_area.y;
    2281                 : 
    2282               0 :     sampled_area.x += tx;
    2283               0 :     sampled_area.y += ty;
    2284                 : 
    2285               0 :     if ( _cairo_surface_get_extents (surface, &extents)) {
    2286               0 :         if (attr->extend == CAIRO_EXTEND_NONE) {
    2287                 :             /* Never acquire a larger area than the source itself */
    2288               0 :             is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
    2289                 :         } else {
    2290               0 :             int trim = 0;
    2291                 : 
    2292               0 :             if (sampled_area.x >= extents.x &&
    2293               0 :                 sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
    2294                 :             {
    2295                 :                 /* source is horizontally contained within extents, trim */
    2296               0 :                 extents.x = sampled_area.x;
    2297               0 :                 extents.width = sampled_area.width;
    2298               0 :                 trim |= 0x1;
    2299                 :             }
    2300                 : 
    2301               0 :             if (sampled_area.y >= extents.y &&
    2302               0 :                 sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
    2303                 :             {
    2304                 :                 /* source is vertically contained within extents, trim */
    2305               0 :                 extents.y = sampled_area.y;
    2306               0 :                 extents.height = sampled_area.height;
    2307               0 :                 trim |= 0x2;
    2308                 :             }
    2309                 : 
    2310               0 :             if (trim == 0x3) {
    2311                 :                 /* source is wholly contained within extents, drop the REPEAT */
    2312               0 :                 attr->extend = CAIRO_EXTEND_NONE;
    2313                 :             }
    2314                 : 
    2315               0 :             is_empty = extents.width == 0 || extents.height == 0;
    2316                 :         }
    2317                 :     }
    2318                 : 
    2319                 :     /* XXX can we use is_empty? */
    2320                 : 
    2321               0 :     status = _cairo_surface_clone_similar (dst, surface,
    2322                 :                                            extents.x, extents.y,
    2323                 :                                            extents.width, extents.height,
    2324                 :                                            &x, &y, out);
    2325               0 :     if (unlikely (status))
    2326               0 :         goto BAIL;
    2327                 : 
    2328               0 :     if (x != 0 || y != 0) {
    2329               0 :         if (is_identity) {
    2330               0 :             attr->x_offset -= x;
    2331               0 :             attr->y_offset -= y;
    2332                 :         } else {
    2333                 :             cairo_matrix_t m;
    2334                 : 
    2335               0 :             x -= attr->x_offset;
    2336               0 :             y -= attr->y_offset;
    2337               0 :             attr->x_offset = 0;
    2338               0 :             attr->y_offset = 0;
    2339                 : 
    2340               0 :             cairo_matrix_init_translate (&m, -x, -y);
    2341               0 :             cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
    2342                 :         }
    2343                 :     }
    2344                 : 
    2345                 :     /* reduce likelihood of range overflow with large downscaling */
    2346               0 :     if (! is_identity) {
    2347                 :         cairo_matrix_t m;
    2348                 :         cairo_status_t invert_status;
    2349                 : 
    2350               0 :         m = attr->matrix;
    2351               0 :         invert_status = cairo_matrix_invert (&m);
    2352               0 :         assert (invert_status == CAIRO_STATUS_SUCCESS);
    2353                 : 
    2354               0 :         if (m.x0 != 0. || m.y0 != 0.) {
    2355                 :             /* pixman also limits the [xy]_offset to 16 bits so evenly
    2356                 :              * spread the bits between the two.
    2357                 :              */
    2358               0 :             x = floor (m.x0 / 2);
    2359               0 :             y = floor (m.y0 / 2);
    2360               0 :             attr->x_offset -= x;
    2361               0 :             attr->y_offset -= y;
    2362               0 :             cairo_matrix_init_translate (&m, x, y);
    2363               0 :             cairo_matrix_multiply (&attr->matrix, &m, &attr->matrix);
    2364                 :         }
    2365                 :     }
    2366                 : 
    2367                 :   BAIL:
    2368               0 :     cairo_surface_destroy (surface);
    2369               0 :     return status;
    2370                 : }
    2371                 : 
    2372                 : /**
    2373                 :  * _cairo_pattern_acquire_surface:
    2374                 :  * @pattern: a #cairo_pattern_t
    2375                 :  * @dst: destination surface
    2376                 :  * @x: X coordinate in source corresponding to left side of destination area
    2377                 :  * @y: Y coordinate in source corresponding to top side of destination area
    2378                 :  * @width: width of destination area
    2379                 :  * @height: height of destination area
    2380                 :  * @surface_out: location to store a pointer to a surface
    2381                 :  * @attributes: surface attributes that destination backend should apply to
    2382                 :  * the returned surface
    2383                 :  *
    2384                 :  * A convenience function to obtain a surface to use as the source for
    2385                 :  * drawing on @dst.
    2386                 :  *
    2387                 :  * Note that this function is only suitable for use when the destination
    2388                 :  * surface is pixel based and 1 device unit maps to one pixel.
    2389                 :  *
    2390                 :  * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
    2391                 :  **/
    2392                 : cairo_int_status_t
    2393               0 : _cairo_pattern_acquire_surface (const cairo_pattern_t      *pattern,
    2394                 :                                 cairo_surface_t            *dst,
    2395                 :                                 int                        x,
    2396                 :                                 int                        y,
    2397                 :                                 unsigned int               width,
    2398                 :                                 unsigned int               height,
    2399                 :                                 unsigned int               flags,
    2400                 :                                 cairo_surface_t            **surface_out,
    2401                 :                                 cairo_surface_attributes_t *attributes)
    2402                 : {
    2403               0 :     if (unlikely (pattern->status)) {
    2404               0 :         *surface_out = NULL;
    2405               0 :         return pattern->status;
    2406                 :     }
    2407                 : 
    2408               0 :     switch (pattern->type) {
    2409                 :     case CAIRO_PATTERN_TYPE_SOLID:
    2410               0 :         return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern,
    2411                 :                                                          dst, x, y, width, height,
    2412                 :                                                          surface_out,
    2413                 :                                                          attributes);
    2414                 : 
    2415                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    2416                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    2417               0 :         return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern,
    2418                 :                                                             dst, x, y, width, height,
    2419                 :                                                             surface_out,
    2420                 :                                                             attributes);
    2421                 : 
    2422                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    2423               0 :         return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern,
    2424                 :                                                            dst, x, y, width, height,
    2425                 :                                                            flags,
    2426                 :                                                            surface_out,
    2427                 :                                                            attributes);
    2428                 : 
    2429                 :     default:
    2430               0 :         ASSERT_NOT_REACHED;
    2431               0 :         return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    2432                 :     }
    2433                 : }
    2434                 : 
    2435                 : /**
    2436                 :  * _cairo_pattern_release_surface:
    2437                 :  * @pattern: a #cairo_pattern_t
    2438                 :  * @surface: a surface obtained by _cairo_pattern_acquire_surface
    2439                 :  * @attributes: attributes obtained by _cairo_pattern_acquire_surface
    2440                 :  *
    2441                 :  * Releases resources obtained by _cairo_pattern_acquire_surface.
    2442                 :  **/
    2443                 : void
    2444               0 : _cairo_pattern_release_surface (const cairo_pattern_t *pattern,
    2445                 :                                 cairo_surface_t            *surface,
    2446                 :                                 cairo_surface_attributes_t *attributes)
    2447                 : {
    2448               0 :     cairo_surface_destroy (surface);
    2449               0 : }
    2450                 : 
    2451                 : cairo_int_status_t
    2452               0 : _cairo_pattern_acquire_surfaces (const cairo_pattern_t      *src,
    2453                 :                                  const cairo_pattern_t      *mask,
    2454                 :                                  cairo_surface_t            *dst,
    2455                 :                                  int                        src_x,
    2456                 :                                  int                        src_y,
    2457                 :                                  int                        mask_x,
    2458                 :                                  int                        mask_y,
    2459                 :                                  unsigned int               width,
    2460                 :                                  unsigned int               height,
    2461                 :                                  unsigned int               flags,
    2462                 :                                  cairo_surface_t            **src_out,
    2463                 :                                  cairo_surface_t            **mask_out,
    2464                 :                                  cairo_surface_attributes_t *src_attributes,
    2465                 :                                  cairo_surface_attributes_t *mask_attributes)
    2466                 : {
    2467                 :     cairo_int_status_t    status;
    2468                 :     cairo_pattern_union_t src_tmp;
    2469                 : 
    2470               0 :     if (unlikely (src->status))
    2471               0 :         return src->status;
    2472               0 :     if (unlikely (mask != NULL && mask->status))
    2473               0 :         return mask->status;
    2474                 : 
    2475                 :     /* If src and mask are both solid, then the mask alpha can be
    2476                 :      * combined into src and mask can be ignored. */
    2477                 : 
    2478               0 :     if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
    2479               0 :         mask &&
    2480               0 :         ! mask->has_component_alpha &&
    2481               0 :         mask->type == CAIRO_PATTERN_TYPE_SOLID)
    2482                 :     {
    2483                 :         cairo_color_t combined;
    2484               0 :         cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
    2485               0 :         cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
    2486                 : 
    2487               0 :         combined = src_solid->color;
    2488               0 :         _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
    2489                 : 
    2490               0 :         _cairo_pattern_init_solid (&src_tmp.solid, &combined);
    2491                 : 
    2492               0 :         src = &src_tmp.base;
    2493               0 :         mask = NULL;
    2494                 :     }
    2495                 : 
    2496               0 :     status = _cairo_pattern_acquire_surface (src, dst,
    2497                 :                                              src_x, src_y,
    2498                 :                                              width, height,
    2499                 :                                              flags,
    2500                 :                                              src_out, src_attributes);
    2501               0 :     if (unlikely (status))
    2502               0 :         goto BAIL;
    2503                 : 
    2504               0 :     if (mask == NULL) {
    2505               0 :         *mask_out = NULL;
    2506               0 :         goto BAIL;
    2507                 :     }
    2508                 : 
    2509               0 :     status = _cairo_pattern_acquire_surface (mask, dst,
    2510                 :                                              mask_x, mask_y,
    2511                 :                                              width, height,
    2512                 :                                              flags,
    2513                 :                                              mask_out, mask_attributes);
    2514               0 :     if (unlikely (status))
    2515               0 :         _cairo_pattern_release_surface (src, *src_out, src_attributes);
    2516                 : 
    2517                 :   BAIL:
    2518               0 :     if (src == &src_tmp.base)
    2519               0 :         _cairo_pattern_fini (&src_tmp.base);
    2520                 : 
    2521               0 :     return status;
    2522                 : }
    2523                 : 
    2524                 : /**
    2525                 :  * _cairo_pattern_get_extents:
    2526                 :  *
    2527                 :  * Return the "target-space" extents of @pattern in @extents.
    2528                 :  *
    2529                 :  * For unbounded patterns, the @extents will be initialized with
    2530                 :  * "infinite" extents, (minimum and maximum fixed-point values).
    2531                 :  *
    2532                 :  * XXX: Currently, bounded gradient patterns will also return
    2533                 :  * "infinite" extents, though it would be possible to optimize these
    2534                 :  * with a little more work.
    2535                 :  **/
    2536                 : void
    2537              64 : _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
    2538                 :                             cairo_rectangle_int_t         *extents)
    2539                 : {
    2540                 :     double x1, y1, x2, y2;
    2541                 :     cairo_status_t status;
    2542                 : 
    2543              64 :     switch (pattern->type) {
    2544                 :     case CAIRO_PATTERN_TYPE_SOLID:
    2545              17 :         goto UNBOUNDED;
    2546                 : 
    2547                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    2548                 :         {
    2549                 :             cairo_rectangle_int_t surface_extents;
    2550              47 :             const cairo_surface_pattern_t *surface_pattern =
    2551                 :                 (const cairo_surface_pattern_t *) pattern;
    2552              47 :             cairo_surface_t *surface = surface_pattern->surface;
    2553                 :             double pad;
    2554                 : 
    2555              47 :             if (! _cairo_surface_get_extents (surface, &surface_extents))
    2556               0 :                 goto UNBOUNDED;
    2557                 : 
    2558              47 :             if (surface_extents.width == 0 || surface_extents.height == 0)
    2559                 :                 goto EMPTY;
    2560                 : 
    2561              47 :             if (pattern->extend != CAIRO_EXTEND_NONE)
    2562               0 :                 goto UNBOUNDED;
    2563                 : 
    2564                 :             /* The filter can effectively enlarge the extents of the
    2565                 :              * pattern, so extend as necessary.
    2566                 :              */
    2567              47 :             _cairo_pattern_analyze_filter (&surface_pattern->base, &pad);
    2568              47 :             x1 = surface_extents.x - pad;
    2569              47 :             y1 = surface_extents.y - pad;
    2570              47 :             x2 = surface_extents.x + (int) surface_extents.width  + pad;
    2571              47 :             y2 = surface_extents.y + (int) surface_extents.height + pad;
    2572                 :         }
    2573              47 :         break;
    2574                 : 
    2575                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    2576                 :         {
    2577               0 :             const cairo_radial_pattern_t *radial =
    2578                 :                 (const cairo_radial_pattern_t *) pattern;
    2579                 :             double cx1, cy1;
    2580                 :             double cx2, cy2;
    2581                 :             double r, D;
    2582                 : 
    2583               0 :             if (radial->r1 == 0 && radial->r2 == 0)
    2584               0 :                 goto EMPTY;
    2585                 : 
    2586               0 :             cx1 = _cairo_fixed_to_double (radial->c1.x);
    2587               0 :             cy1 = _cairo_fixed_to_double (radial->c1.y);
    2588               0 :             r = _cairo_fixed_to_double (radial->r1);
    2589               0 :             x1 = cx1 - r; x2 = cx1 + r;
    2590               0 :             y1 = cy1 - r; y2 = cy1 + r;
    2591                 : 
    2592               0 :             cx2 = _cairo_fixed_to_double (radial->c2.x);
    2593               0 :             cy2 = _cairo_fixed_to_double (radial->c2.y);
    2594               0 :             r = fabs (_cairo_fixed_to_double (radial->r2));
    2595                 : 
    2596               0 :             if (pattern->extend != CAIRO_EXTEND_NONE)
    2597               0 :                 goto UNBOUNDED;
    2598                 : 
    2599                 :             /* We need to be careful, as if the circles are not
    2600                 :              * self-contained, then the solution is actually unbounded.
    2601                 :              */
    2602               0 :             D = (cx1-cx2)*(cx1-cx2) + (cy1-cy2)*(cy1-cy2);
    2603               0 :             if (D > r*r - 1e-5)
    2604               0 :                 goto UNBOUNDED;
    2605                 : 
    2606               0 :             if (cx2 - r < x1)
    2607               0 :                 x1 = cx2 - r;
    2608               0 :             if (cx2 + r > x2)
    2609               0 :                 x2 = cx2 + r;
    2610                 : 
    2611               0 :             if (cy2 - r < y1)
    2612               0 :                 y1 = cy2 - r;
    2613               0 :             if (cy2 + r > y2)
    2614               0 :                 y2 = cy2 + r;
    2615                 :         }
    2616               0 :         break;
    2617                 : 
    2618                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    2619                 :         {
    2620               0 :             const cairo_linear_pattern_t *linear =
    2621                 :                 (const cairo_linear_pattern_t *) pattern;
    2622                 : 
    2623               0 :             if (pattern->extend != CAIRO_EXTEND_NONE)
    2624               0 :                 goto UNBOUNDED;
    2625                 : 
    2626               0 :             if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y)
    2627               0 :                 goto EMPTY;
    2628                 : 
    2629               0 :             if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
    2630                 :                 goto UNBOUNDED;
    2631                 : 
    2632               0 :             if (linear->p1.x == linear->p2.x) {
    2633               0 :                 x1 = -HUGE_VAL;
    2634               0 :                 x2 = HUGE_VAL;
    2635               0 :                 y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y));
    2636               0 :                 y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y));
    2637               0 :             } else if (linear->p1.y == linear->p2.y) {
    2638               0 :                 x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x));
    2639               0 :                 x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x));
    2640               0 :                 y1 = -HUGE_VAL;
    2641               0 :                 y2 = HUGE_VAL;
    2642                 :             } else {
    2643               0 :                 goto  UNBOUNDED;
    2644                 :             }
    2645                 :         }
    2646               0 :         break;
    2647                 : 
    2648                 :     default:
    2649               0 :         ASSERT_NOT_REACHED;
    2650                 :     }
    2651                 : 
    2652              47 :     if (_cairo_matrix_is_translation (&pattern->matrix)) {
    2653              37 :         x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0;
    2654              37 :         y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0;
    2655                 :     } else {
    2656                 :         cairo_matrix_t imatrix;
    2657                 : 
    2658              10 :         imatrix = pattern->matrix;
    2659              10 :         status = cairo_matrix_invert (&imatrix);
    2660                 :         /* cairo_pattern_set_matrix ensures the matrix is invertible */
    2661              10 :         assert (status == CAIRO_STATUS_SUCCESS);
    2662                 : 
    2663              10 :         _cairo_matrix_transform_bounding_box (&imatrix,
    2664                 :                                               &x1, &y1, &x2, &y2,
    2665                 :                                               NULL);
    2666                 :     }
    2667                 : 
    2668              47 :     x1 = floor (x1);
    2669              47 :     if (x1 < CAIRO_RECT_INT_MIN)
    2670               0 :         x1 = CAIRO_RECT_INT_MIN;
    2671              47 :     y1 = floor (y1);
    2672              47 :     if (y1 < CAIRO_RECT_INT_MIN)
    2673               0 :         y1 = CAIRO_RECT_INT_MIN;
    2674                 : 
    2675              47 :     x2 = ceil (x2);
    2676              47 :     if (x2 > CAIRO_RECT_INT_MAX)
    2677               0 :         x2 = CAIRO_RECT_INT_MAX;
    2678              47 :     y2 = ceil (y2);
    2679              47 :     if (y2 > CAIRO_RECT_INT_MAX)
    2680               0 :         y2 = CAIRO_RECT_INT_MAX;
    2681                 : 
    2682              47 :     extents->x = x1; extents->width  = x2 - x1;
    2683              47 :     extents->y = y1; extents->height = y2 - y1;
    2684              47 :     return;
    2685                 : 
    2686                 :   UNBOUNDED:
    2687                 :     /* unbounded patterns -> 'infinite' extents */
    2688              17 :     _cairo_unbounded_rectangle_init (extents);
    2689              17 :     return;
    2690                 : 
    2691                 :   EMPTY:
    2692               0 :     extents->x = extents->y = 0;
    2693               0 :     extents->width = extents->height = 0;
    2694               0 :     return;
    2695                 : }
    2696                 : 
    2697                 : 
    2698                 : static unsigned long
    2699               0 : _cairo_solid_pattern_hash (unsigned long hash,
    2700                 :                            const cairo_pattern_t *pattern)
    2701                 : {
    2702               0 :     const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
    2703                 : 
    2704               0 :     hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color));
    2705                 : 
    2706               0 :     return hash;
    2707                 : }
    2708                 : 
    2709                 : static unsigned long
    2710               0 : _cairo_gradient_color_stops_hash (unsigned long hash,
    2711                 :                                   const cairo_gradient_pattern_t *gradient)
    2712                 : {
    2713                 :     unsigned int n;
    2714                 : 
    2715               0 :     hash = _cairo_hash_bytes (hash,
    2716               0 :                               &gradient->n_stops,
    2717                 :                               sizeof (gradient->n_stops));
    2718                 : 
    2719               0 :     for (n = 0; n < gradient->n_stops; n++) {
    2720               0 :         hash = _cairo_hash_bytes (hash,
    2721               0 :                                   &gradient->stops[n].offset,
    2722                 :                                   sizeof (double));
    2723               0 :         hash = _cairo_hash_bytes (hash,
    2724               0 :                                   &gradient->stops[n].color,
    2725                 :                                   sizeof (cairo_color_t));
    2726                 :     }
    2727                 : 
    2728               0 :     return hash;
    2729                 : }
    2730                 : 
    2731                 : unsigned long
    2732               0 : _cairo_linear_pattern_hash (unsigned long hash,
    2733                 :                             const cairo_linear_pattern_t *linear)
    2734                 : {
    2735               0 :     hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
    2736               0 :     hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
    2737                 : 
    2738               0 :     return _cairo_gradient_color_stops_hash (hash, &linear->base);
    2739                 : }
    2740                 : 
    2741                 : unsigned long
    2742               0 : _cairo_radial_pattern_hash (unsigned long hash,
    2743                 :                             const cairo_radial_pattern_t *radial)
    2744                 : {
    2745               0 :     hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
    2746               0 :     hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
    2747               0 :     hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
    2748               0 :     hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2));
    2749                 : 
    2750               0 :     return _cairo_gradient_color_stops_hash (hash, &radial->base);
    2751                 : }
    2752                 : 
    2753                 : static unsigned long
    2754               0 : _cairo_surface_pattern_hash (unsigned long hash,
    2755                 :                              const cairo_pattern_t *pattern)
    2756                 : {
    2757               0 :     const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
    2758                 : 
    2759               0 :     hash ^= surface->surface->unique_id;
    2760                 : 
    2761               0 :     return hash;
    2762                 : }
    2763                 : 
    2764                 : unsigned long
    2765               0 : _cairo_pattern_hash (const cairo_pattern_t *pattern)
    2766                 : {
    2767               0 :     unsigned long hash = _CAIRO_HASH_INIT_VALUE;
    2768                 : 
    2769               0 :     if (pattern->status)
    2770               0 :         return 0;
    2771                 : 
    2772               0 :     hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
    2773               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
    2774               0 :         hash = _cairo_hash_bytes (hash,
    2775               0 :                                   &pattern->matrix, sizeof (pattern->matrix));
    2776               0 :         hash = _cairo_hash_bytes (hash,
    2777               0 :                                   &pattern->filter, sizeof (pattern->filter));
    2778               0 :         hash = _cairo_hash_bytes (hash,
    2779               0 :                                   &pattern->extend, sizeof (pattern->extend));
    2780               0 :         hash = _cairo_hash_bytes (hash,
    2781               0 :                                   &pattern->has_component_alpha,
    2782                 :                                   sizeof (pattern->has_component_alpha));
    2783                 :     }
    2784                 : 
    2785               0 :     switch (pattern->type) {
    2786                 :     case CAIRO_PATTERN_TYPE_SOLID:
    2787               0 :         return _cairo_solid_pattern_hash (hash, pattern);
    2788                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    2789               0 :         return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
    2790                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    2791               0 :         return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
    2792                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    2793               0 :         return _cairo_surface_pattern_hash (hash, pattern);
    2794                 :     default:
    2795               0 :         ASSERT_NOT_REACHED;
    2796               0 :         return FALSE;
    2797                 :     }
    2798                 : }
    2799                 : 
    2800                 : static unsigned long
    2801               0 : _cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern)
    2802                 : {
    2803               0 :     cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
    2804                 : 
    2805               0 :     return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t));
    2806                 : }
    2807                 : 
    2808                 : unsigned long
    2809               0 : _cairo_pattern_size (const cairo_pattern_t *pattern)
    2810                 : {
    2811               0 :     if (pattern->status)
    2812               0 :         return 0;
    2813                 : 
    2814                 :     /* XXX */
    2815               0 :     switch (pattern->type) {
    2816                 :     case CAIRO_PATTERN_TYPE_SOLID:
    2817               0 :         return sizeof (cairo_solid_pattern_t);
    2818                 :         break;
    2819                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    2820               0 :         return sizeof (cairo_surface_pattern_t);
    2821                 :         break;
    2822                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    2823               0 :         return sizeof (cairo_linear_pattern_t) +
    2824               0 :             _cairo_gradient_pattern_color_stops_size (pattern);
    2825                 :         break;
    2826                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    2827               0 :         return sizeof (cairo_radial_pattern_t) +
    2828               0 :             _cairo_gradient_pattern_color_stops_size (pattern);
    2829                 :     default:
    2830               0 :         ASSERT_NOT_REACHED;
    2831               0 :         return 0;
    2832                 :     }
    2833                 : }
    2834                 : 
    2835                 : 
    2836                 : static cairo_bool_t
    2837               0 : _cairo_solid_pattern_equal (const cairo_pattern_t *A,
    2838                 :                             const cairo_pattern_t *B)
    2839                 : {
    2840               0 :     const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A;
    2841               0 :     const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B;
    2842                 : 
    2843               0 :     return _cairo_color_equal (&a->color, &b->color);
    2844                 : }
    2845                 : 
    2846                 : static cairo_bool_t
    2847               0 : _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
    2848                 :                                    const cairo_gradient_pattern_t *b)
    2849                 : {
    2850                 :     unsigned int n;
    2851                 : 
    2852               0 :     if (a->n_stops != b->n_stops)
    2853               0 :         return FALSE;
    2854                 : 
    2855               0 :     for (n = 0; n < a->n_stops; n++) {
    2856               0 :         if (a->stops[n].offset != b->stops[n].offset)
    2857               0 :             return FALSE;
    2858               0 :         if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color))
    2859               0 :             return FALSE;
    2860                 :     }
    2861                 : 
    2862               0 :     return TRUE;
    2863                 : }
    2864                 : 
    2865                 : cairo_bool_t
    2866               0 : _cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
    2867                 :                              const cairo_linear_pattern_t *b)
    2868                 : {
    2869               0 :     if (a->p1.x != b->p1.x)
    2870               0 :         return FALSE;
    2871                 : 
    2872               0 :     if (a->p1.y != b->p1.y)
    2873               0 :         return FALSE;
    2874                 : 
    2875               0 :     if (a->p2.x != b->p2.x)
    2876               0 :         return FALSE;
    2877                 : 
    2878               0 :     if (a->p2.y != b->p2.y)
    2879               0 :         return FALSE;
    2880                 : 
    2881               0 :     return _cairo_gradient_color_stops_equal (&a->base, &b->base);
    2882                 : }
    2883                 : 
    2884                 : cairo_bool_t
    2885               0 : _cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
    2886                 :                              const cairo_radial_pattern_t *b)
    2887                 : {
    2888               0 :     if (a->c1.x != b->c1.x)
    2889               0 :         return FALSE;
    2890                 : 
    2891               0 :     if (a->c1.y != b->c1.y)
    2892               0 :         return FALSE;
    2893                 : 
    2894               0 :     if (a->r1 != b->r1)
    2895               0 :         return FALSE;
    2896                 : 
    2897               0 :     if (a->c2.x != b->c2.x)
    2898               0 :         return FALSE;
    2899                 : 
    2900               0 :     if (a->c2.y != b->c2.y)
    2901               0 :         return FALSE;
    2902                 : 
    2903               0 :     if (a->r2 != b->r2)
    2904               0 :         return FALSE;
    2905                 : 
    2906               0 :     return _cairo_gradient_color_stops_equal (&a->base, &b->base);
    2907                 : }
    2908                 : 
    2909                 : static cairo_bool_t
    2910               0 : _cairo_surface_pattern_equal (const cairo_pattern_t *A,
    2911                 :                               const cairo_pattern_t *B)
    2912                 : {
    2913               0 :     const cairo_surface_pattern_t *a = (cairo_surface_pattern_t *) A;
    2914               0 :     const cairo_surface_pattern_t *b = (cairo_surface_pattern_t *) B;
    2915                 : 
    2916               0 :     return a->surface->unique_id == b->surface->unique_id;
    2917                 : }
    2918                 : 
    2919                 : cairo_bool_t
    2920               0 : _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
    2921                 : {
    2922               0 :     if (a->status || b->status)
    2923               0 :         return FALSE;
    2924                 : 
    2925               0 :     if (a == b)
    2926               0 :         return TRUE;
    2927                 : 
    2928               0 :     if (a->type != b->type)
    2929               0 :         return FALSE;
    2930                 : 
    2931               0 :     if (a->has_component_alpha != b->has_component_alpha)
    2932               0 :         return FALSE;
    2933                 : 
    2934               0 :     if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
    2935               0 :         if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
    2936               0 :             return FALSE;
    2937                 : 
    2938               0 :         if (a->filter != b->filter)
    2939               0 :             return FALSE;
    2940                 : 
    2941               0 :         if (a->extend != b->extend)
    2942               0 :             return FALSE;
    2943                 :     }
    2944                 : 
    2945               0 :     switch (a->type) {
    2946                 :     case CAIRO_PATTERN_TYPE_SOLID:
    2947               0 :         return _cairo_solid_pattern_equal (a, b);
    2948                 :     case CAIRO_PATTERN_TYPE_LINEAR:
    2949               0 :         return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
    2950                 :                                             (cairo_linear_pattern_t *) b);
    2951                 :     case CAIRO_PATTERN_TYPE_RADIAL:
    2952               0 :         return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
    2953                 :                                             (cairo_radial_pattern_t *) b);
    2954                 :     case CAIRO_PATTERN_TYPE_SURFACE:
    2955               0 :         return _cairo_surface_pattern_equal (a, b);
    2956                 :     default:
    2957               0 :         ASSERT_NOT_REACHED;
    2958               0 :         return FALSE;
    2959                 :     }
    2960                 : }
    2961                 : 
    2962                 : /**
    2963                 :  * cairo_pattern_get_rgba
    2964                 :  * @pattern: a #cairo_pattern_t
    2965                 :  * @red: return value for red component of color, or %NULL
    2966                 :  * @green: return value for green component of color, or %NULL
    2967                 :  * @blue: return value for blue component of color, or %NULL
    2968                 :  * @alpha: return value for alpha component of color, or %NULL
    2969                 :  *
    2970                 :  * Gets the solid color for a solid color pattern.
    2971                 :  *
    2972                 :  * Return value: %CAIRO_STATUS_SUCCESS, or
    2973                 :  * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid
    2974                 :  * color pattern.
    2975                 :  *
    2976                 :  * Since: 1.4
    2977                 :  **/
    2978                 : cairo_status_t
    2979               0 : cairo_pattern_get_rgba (cairo_pattern_t *pattern,
    2980                 :                         double *red, double *green,
    2981                 :                         double *blue, double *alpha)
    2982                 : {
    2983               0 :     cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern;
    2984                 :     double r0, g0, b0, a0;
    2985                 : 
    2986               0 :     if (pattern->status)
    2987               0 :         return pattern->status;
    2988                 : 
    2989               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
    2990               0 :         return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    2991                 : 
    2992               0 :     _cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0);
    2993                 : 
    2994               0 :     if (red)
    2995               0 :         *red = r0;
    2996               0 :     if (green)
    2997               0 :         *green = g0;
    2998               0 :     if (blue)
    2999               0 :         *blue = b0;
    3000               0 :     if (alpha)
    3001               0 :         *alpha = a0;
    3002                 : 
    3003               0 :     return CAIRO_STATUS_SUCCESS;
    3004                 : }
    3005                 : 
    3006                 : /**
    3007                 :  * cairo_pattern_get_surface
    3008                 :  * @pattern: a #cairo_pattern_t
    3009                 :  * @surface: return value for surface of pattern, or %NULL
    3010                 :  * 
    3011                 :  * Gets the surface of a surface pattern.  The reference returned in
    3012                 :  * @surface is owned by the pattern; the caller should call
    3013                 :  * cairo_surface_reference() if the surface is to be retained.
    3014                 :  *
    3015                 :  * Return value: %CAIRO_STATUS_SUCCESS, or
    3016                 :  * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a surface
    3017                 :  * pattern.
    3018                 :  *
    3019                 :  * Since: 1.4
    3020                 :  **/
    3021                 : cairo_status_t
    3022               0 : cairo_pattern_get_surface (cairo_pattern_t *pattern,
    3023                 :                            cairo_surface_t **surface)
    3024                 : {
    3025               0 :     cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern;
    3026                 : 
    3027               0 :     if (pattern->status)
    3028               0 :         return pattern->status;
    3029                 : 
    3030               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
    3031               0 :         return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
    3032                 : 
    3033               0 :     if (surface)
    3034               0 :         *surface = spat->surface;
    3035                 : 
    3036               0 :     return CAIRO_STATUS_SUCCESS;
    3037                 : }
    3038                 : 
    3039                 : /**
    3040                 :  * cairo_pattern_get_color_stop_rgba
    3041                 :  * @pattern: a #cairo_pattern_t
    3042                 :  * @index: index of the stop to return data for
    3043                 :  * @offset: return value for the offset of the stop, or %NULL
    3044                 :  * @red: return value for red component of color, or %NULL
    3045                 :  * @green: return value for green component of color, or %NULL
    3046                 :  * @blue: return value for blue component of color, or %NULL
    3047                 :  * @alpha: return value for alpha component of color, or %NULL
    3048                 :  *
    3049                 :  * Gets the color and offset information at the given @index for a
    3050                 :  * gradient pattern.  Values of @index are 0 to 1 less than the number
    3051                 :  * returned by cairo_pattern_get_color_stop_count().
    3052                 :  *
    3053                 :  * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX
    3054                 :  * if @index is not valid for the given pattern.  If the pattern is
    3055                 :  * not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is
    3056                 :  * returned.
    3057                 :  *
    3058                 :  * Since: 1.4
    3059                 :  **/
    3060                 : cairo_status_t
    3061               0 : cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern,
    3062                 :                                    int index, double *offset,
    3063                 :                                    double *red, double *green,
    3064                 :                                    double *blue, double *alpha)
    3065                 : {
    3066               0 :     cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
    3067                 : 
    3068               0 :     if (pattern->status)
    3069               0 :         return pattern->status;
    3070                 : 
    3071               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
    3072               0 :         pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
    3073               0 :         return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    3074                 : 
    3075               0 :     if (index < 0 || (unsigned int) index >= gradient->n_stops)
    3076               0 :         return _cairo_error (CAIRO_STATUS_INVALID_INDEX);
    3077                 : 
    3078               0 :     if (offset)
    3079               0 :         *offset = gradient->stops[index].offset;
    3080               0 :     if (red)
    3081               0 :         *red = gradient->stops[index].color.red;
    3082               0 :     if (green)
    3083               0 :         *green = gradient->stops[index].color.green;
    3084               0 :     if (blue)
    3085               0 :         *blue = gradient->stops[index].color.blue;
    3086               0 :     if (alpha)
    3087               0 :         *alpha = gradient->stops[index].color.alpha;
    3088                 : 
    3089               0 :     return CAIRO_STATUS_SUCCESS;
    3090                 : }
    3091                 : 
    3092                 : /**
    3093                 :  * cairo_pattern_get_color_stop_count
    3094                 :  * @pattern: a #cairo_pattern_t
    3095                 :  * @count: return value for the number of color stops, or %NULL
    3096                 :  *
    3097                 :  * Gets the number of color stops specified in the given gradient
    3098                 :  * pattern.
    3099                 :  *
    3100                 :  * Return value: %CAIRO_STATUS_SUCCESS, or
    3101                 :  * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient
    3102                 :  * pattern.
    3103                 :  *
    3104                 :  * Since: 1.4
    3105                 :  */
    3106                 : cairo_status_t
    3107               0 : cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern,
    3108                 :                                     int *count)
    3109                 : {
    3110               0 :     cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
    3111                 : 
    3112               0 :     if (pattern->status)
    3113               0 :         return pattern->status;
    3114                 : 
    3115               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
    3116               0 :         pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
    3117               0 :         return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    3118                 : 
    3119               0 :     if (count)
    3120               0 :         *count = gradient->n_stops;
    3121                 : 
    3122               0 :     return CAIRO_STATUS_SUCCESS;
    3123                 : }
    3124                 : 
    3125                 : /**
    3126                 :  * cairo_pattern_get_linear_points
    3127                 :  * @pattern: a #cairo_pattern_t
    3128                 :  * @x0: return value for the x coordinate of the first point, or %NULL
    3129                 :  * @y0: return value for the y coordinate of the first point, or %NULL
    3130                 :  * @x1: return value for the x coordinate of the second point, or %NULL
    3131                 :  * @y1: return value for the y coordinate of the second point, or %NULL
    3132                 :  *
    3133                 :  * Gets the gradient endpoints for a linear gradient.
    3134                 :  *
    3135                 :  * Return value: %CAIRO_STATUS_SUCCESS, or
    3136                 :  * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a linear
    3137                 :  * gradient pattern.
    3138                 :  *
    3139                 :  * Since: 1.4
    3140                 :  **/
    3141                 : cairo_status_t
    3142               0 : cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
    3143                 :                                  double *x0, double *y0,
    3144                 :                                  double *x1, double *y1)
    3145                 : {
    3146               0 :     cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern;
    3147                 : 
    3148               0 :     if (pattern->status)
    3149               0 :         return pattern->status;
    3150                 : 
    3151               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR)
    3152               0 :         return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    3153                 : 
    3154               0 :     if (x0)
    3155               0 :         *x0 = _cairo_fixed_to_double (linear->p1.x);
    3156               0 :     if (y0)
    3157               0 :         *y0 = _cairo_fixed_to_double (linear->p1.y);
    3158               0 :     if (x1)
    3159               0 :         *x1 = _cairo_fixed_to_double (linear->p2.x);
    3160               0 :     if (y1)
    3161               0 :         *y1 = _cairo_fixed_to_double (linear->p2.y);
    3162                 : 
    3163               0 :     return CAIRO_STATUS_SUCCESS;
    3164                 : }
    3165                 : 
    3166                 : /**
    3167                 :  * cairo_pattern_get_radial_circles
    3168                 :  * @pattern: a #cairo_pattern_t
    3169                 :  * @x0: return value for the x coordinate of the center of the first circle, or %NULL
    3170                 :  * @y0: return value for the y coordinate of the center of the first circle, or %NULL
    3171                 :  * @r0: return value for the radius of the first circle, or %NULL
    3172                 :  * @x1: return value for the x coordinate of the center of the second circle, or %NULL
    3173                 :  * @y1: return value for the y coordinate of the center of the second circle, or %NULL
    3174                 :  * @r1: return value for the radius of the second circle, or %NULL
    3175                 :  *
    3176                 :  * Gets the gradient endpoint circles for a radial gradient, each
    3177                 :  * specified as a center coordinate and a radius.
    3178                 :  *
    3179                 :  * Return value: %CAIRO_STATUS_SUCCESS, or
    3180                 :  * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial
    3181                 :  * gradient pattern.
    3182                 :  *
    3183                 :  * Since: 1.4
    3184                 :  **/
    3185                 : cairo_status_t
    3186               0 : cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
    3187                 :                                   double *x0, double *y0, double *r0,
    3188                 :                                   double *x1, double *y1, double *r1)
    3189                 : {
    3190               0 :     cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern;
    3191                 : 
    3192               0 :     if (pattern->status)
    3193               0 :         return pattern->status;
    3194                 : 
    3195               0 :     if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
    3196               0 :         return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
    3197                 : 
    3198               0 :     if (x0)
    3199               0 :         *x0 = _cairo_fixed_to_double (radial->c1.x);
    3200               0 :     if (y0)
    3201               0 :         *y0 = _cairo_fixed_to_double (radial->c1.y);
    3202               0 :     if (r0)
    3203               0 :         *r0 = _cairo_fixed_to_double (radial->r1);
    3204               0 :     if (x1)
    3205               0 :         *x1 = _cairo_fixed_to_double (radial->c2.x);
    3206               0 :     if (y1)
    3207               0 :         *y1 = _cairo_fixed_to_double (radial->c2.y);
    3208               0 :     if (r1)
    3209               0 :         *r1 = _cairo_fixed_to_double (radial->r2);
    3210                 : 
    3211               0 :     return CAIRO_STATUS_SUCCESS;
    3212                 : }
    3213                 : 
    3214                 : void
    3215               3 : _cairo_pattern_reset_static_data (void)
    3216                 : {
    3217                 : #if HAS_FREED_POOL
    3218                 :     int i;
    3219                 : 
    3220                 :     for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
    3221                 :         _freed_pool_reset (&freed_pattern_pool[i]);
    3222                 : #endif
    3223                 : 
    3224               3 :     _cairo_pattern_reset_solid_surface_cache ();
    3225               3 : }

Generated by: LCOV version 1.7