Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
  2. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright © 2003 University of Southern California
  5.  * Copyright © 2009,2010,2011 Intel Corporation
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it either under the terms of the GNU Lesser General Public
  9.  * License version 2.1 as published by the Free Software Foundation
  10.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  11.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  12.  * notice, a recipient may use your version of this file under either
  13.  * the MPL or the LGPL.
  14.  *
  15.  * You should have received a copy of the LGPL along with this library
  16.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  18.  * You should have received a copy of the MPL along with this library
  19.  * in the file COPYING-MPL-1.1
  20.  *
  21.  * The contents of this file are subject to the Mozilla Public License
  22.  * Version 1.1 (the "License"); you may not use this file except in
  23.  * compliance with the License. You may obtain a copy of the License at
  24.  * http://www.mozilla.org/MPL/
  25.  *
  26.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  27.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  28.  * the specific language governing rights and limitations.
  29.  *
  30.  * The Original Code is the cairo graphics library.
  31.  *
  32.  * The Initial Developer of the Original Code is University of Southern
  33.  * California.
  34.  *
  35.  * Contributor(s):
  36.  *      Carl D. Worth <cworth@cworth.org>
  37.  *      Chris Wilson <chris@chris-wilson.co.uk>
  38.  */
  39.  
  40. /* The purpose of this file/surface is to simply translate a pattern
  41.  * to a pixman_image_t and thence to feed it back to the general
  42.  * compositor interface.
  43.  */
  44.  
  45. #include "cairoint.h"
  46.  
  47. #include "cairo-image-surface-private.h"
  48.  
  49. #include "cairo-compositor-private.h"
  50. #include "cairo-error-private.h"
  51. #include "cairo-pattern-inline.h"
  52. #include "cairo-paginated-private.h"
  53. #include "cairo-recording-surface-private.h"
  54. #include "cairo-surface-observer-private.h"
  55. #include "cairo-surface-snapshot-inline.h"
  56. #include "cairo-surface-subsurface-private.h"
  57.  
  58. #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
  59.  
  60. #if CAIRO_NO_MUTEX
  61. #define PIXMAN_HAS_ATOMIC_OPS 1
  62. #endif
  63.  
  64. #if PIXMAN_HAS_ATOMIC_OPS
  65. static pixman_image_t *__pixman_transparent_image;
  66. static pixman_image_t *__pixman_black_image;
  67. static pixman_image_t *__pixman_white_image;
  68.  
  69. static pixman_image_t *
  70. _pixman_transparent_image (void)
  71. {
  72.     pixman_image_t *image;
  73.  
  74.     TRACE ((stderr, "%s\n", __FUNCTION__));
  75.  
  76.     image = __pixman_transparent_image;
  77.     if (unlikely (image == NULL)) {
  78.         pixman_color_t color;
  79.  
  80.         color.red   = 0x00;
  81.         color.green = 0x00;
  82.         color.blue  = 0x00;
  83.         color.alpha = 0x00;
  84.  
  85.         image = pixman_image_create_solid_fill (&color);
  86.         if (unlikely (image == NULL))
  87.             return NULL;
  88.  
  89.         if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
  90.                                        NULL, image))
  91.         {
  92.             pixman_image_ref (image);
  93.         }
  94.     } else {
  95.         pixman_image_ref (image);
  96.     }
  97.  
  98.     return image;
  99. }
  100.  
  101. static pixman_image_t *
  102. _pixman_black_image (void)
  103. {
  104.     pixman_image_t *image;
  105.  
  106.     TRACE ((stderr, "%s\n", __FUNCTION__));
  107.  
  108.     image = __pixman_black_image;
  109.     if (unlikely (image == NULL)) {
  110.         pixman_color_t color;
  111.  
  112.         color.red   = 0x00;
  113.         color.green = 0x00;
  114.         color.blue  = 0x00;
  115.         color.alpha = 0xffff;
  116.  
  117.         image = pixman_image_create_solid_fill (&color);
  118.         if (unlikely (image == NULL))
  119.             return NULL;
  120.  
  121.         if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
  122.                                        NULL, image))
  123.         {
  124.             pixman_image_ref (image);
  125.         }
  126.     } else {
  127.         pixman_image_ref (image);
  128.     }
  129.  
  130.     return image;
  131. }
  132.  
  133. static pixman_image_t *
  134. _pixman_white_image (void)
  135. {
  136.     pixman_image_t *image;
  137.  
  138.     TRACE ((stderr, "%s\n", __FUNCTION__));
  139.  
  140.     image = __pixman_white_image;
  141.     if (unlikely (image == NULL)) {
  142.         pixman_color_t color;
  143.  
  144.         color.red   = 0xffff;
  145.         color.green = 0xffff;
  146.         color.blue  = 0xffff;
  147.         color.alpha = 0xffff;
  148.  
  149.         image = pixman_image_create_solid_fill (&color);
  150.         if (unlikely (image == NULL))
  151.             return NULL;
  152.  
  153.         if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
  154.                                        NULL, image))
  155.         {
  156.             pixman_image_ref (image);
  157.         }
  158.     } else {
  159.         pixman_image_ref (image);
  160.     }
  161.  
  162.     return image;
  163. }
  164.  
  165. static uint32_t
  166. hars_petruska_f54_1_random (void)
  167. {
  168. #define rol(x,k) ((x << k) | (x >> (32-k)))
  169.     static uint32_t x;
  170.     return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
  171. #undef rol
  172. }
  173.  
  174. static struct {
  175.     cairo_color_t color;
  176.     pixman_image_t *image;
  177. } cache[16];
  178. static int n_cached;
  179.  
  180. #else  /* !PIXMAN_HAS_ATOMIC_OPS */
  181. static pixman_image_t *
  182. _pixman_transparent_image (void)
  183. {
  184.     TRACE ((stderr, "%s\n", __FUNCTION__));
  185.     return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT);
  186. }
  187.  
  188. static pixman_image_t *
  189. _pixman_black_image (void)
  190. {
  191.     TRACE ((stderr, "%s\n", __FUNCTION__));
  192.     return _pixman_image_for_color (CAIRO_COLOR_BLACK);
  193. }
  194.  
  195. static pixman_image_t *
  196. _pixman_white_image (void)
  197. {
  198.     TRACE ((stderr, "%s\n", __FUNCTION__));
  199.     return _pixman_image_for_color (CAIRO_COLOR_WHITE);
  200. }
  201. #endif /* !PIXMAN_HAS_ATOMIC_OPS */
  202.  
  203.  
  204. pixman_image_t *
  205. _pixman_image_for_color (const cairo_color_t *cairo_color)
  206. {
  207.     pixman_color_t color;
  208.     pixman_image_t *image;
  209.  
  210. #if PIXMAN_HAS_ATOMIC_OPS
  211.     int i;
  212.  
  213.     if (CAIRO_COLOR_IS_CLEAR (cairo_color))
  214.         return _pixman_transparent_image ();
  215.  
  216.     if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) {
  217.         if (cairo_color->red_short <= 0x00ff &&
  218.             cairo_color->green_short <= 0x00ff &&
  219.             cairo_color->blue_short <= 0x00ff)
  220.         {
  221.             return _pixman_black_image ();
  222.         }
  223.  
  224.         if (cairo_color->red_short >= 0xff00 &&
  225.             cairo_color->green_short >= 0xff00 &&
  226.             cairo_color->blue_short >= 0xff00)
  227.         {
  228.             return _pixman_white_image ();
  229.         }
  230.     }
  231.  
  232.     CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
  233.     for (i = 0; i < n_cached; i++) {
  234.         if (_cairo_color_equal (&cache[i].color, cairo_color)) {
  235.             image = pixman_image_ref (cache[i].image);
  236.             goto UNLOCK;
  237.         }
  238.     }
  239. #endif
  240.  
  241.     color.red   = cairo_color->red_short;
  242.     color.green = cairo_color->green_short;
  243.     color.blue  = cairo_color->blue_short;
  244.     color.alpha = cairo_color->alpha_short;
  245.  
  246.     image = pixman_image_create_solid_fill (&color);
  247. #if PIXMAN_HAS_ATOMIC_OPS
  248.     if (image == NULL)
  249.         goto UNLOCK;
  250.  
  251.     if (n_cached < ARRAY_LENGTH (cache)) {
  252.         i = n_cached++;
  253.     } else {
  254.         i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
  255.         pixman_image_unref (cache[i].image);
  256.     }
  257.     cache[i].image = pixman_image_ref (image);
  258.     cache[i].color = *cairo_color;
  259.  
  260. UNLOCK:
  261.     CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
  262. #endif
  263.     return image;
  264. }
  265.  
  266.  
  267. void
  268. _cairo_image_reset_static_data (void)
  269. {
  270. #if PIXMAN_HAS_ATOMIC_OPS
  271.     while (n_cached)
  272.         pixman_image_unref (cache[--n_cached].image);
  273.  
  274.     if (__pixman_transparent_image) {
  275.         pixman_image_unref (__pixman_transparent_image);
  276.         __pixman_transparent_image = NULL;
  277.     }
  278.  
  279.     if (__pixman_black_image) {
  280.         pixman_image_unref (__pixman_black_image);
  281.         __pixman_black_image = NULL;
  282.     }
  283.  
  284.     if (__pixman_white_image) {
  285.         pixman_image_unref (__pixman_white_image);
  286.         __pixman_white_image = NULL;
  287.     }
  288. #endif
  289. }
  290.  
  291. static pixman_image_t *
  292. _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
  293.                             const cairo_rectangle_int_t *extents,
  294.                             int *ix, int *iy)
  295. {
  296.     pixman_image_t        *pixman_image;
  297.     pixman_gradient_stop_t pixman_stops_static[2];
  298.     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
  299.     pixman_transform_t      pixman_transform;
  300.     cairo_matrix_t matrix;
  301.     cairo_circle_double_t extremes[2];
  302.     pixman_point_fixed_t p1, p2;
  303.     unsigned int i;
  304.     cairo_int_status_t status;
  305.  
  306.     TRACE ((stderr, "%s\n", __FUNCTION__));
  307.  
  308.     if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
  309.         pixman_stops = _cairo_malloc_ab (pattern->n_stops,
  310.                                          sizeof(pixman_gradient_stop_t));
  311.         if (unlikely (pixman_stops == NULL))
  312.             return NULL;
  313.     }
  314.  
  315.     for (i = 0; i < pattern->n_stops; i++) {
  316.         pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
  317.         pixman_stops[i].color.red   = pattern->stops[i].color.red_short;
  318.         pixman_stops[i].color.green = pattern->stops[i].color.green_short;
  319.         pixman_stops[i].color.blue  = pattern->stops[i].color.blue_short;
  320.         pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
  321.     }
  322.  
  323.     _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
  324.  
  325.     p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
  326.     p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
  327.     p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
  328.     p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
  329.  
  330.     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
  331.         pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
  332.                                                             pixman_stops,
  333.                                                             pattern->n_stops);
  334.     } else {
  335.         pixman_fixed_t r1, r2;
  336.  
  337.         r1   = _cairo_fixed_16_16_from_double (extremes[0].radius);
  338.         r2   = _cairo_fixed_16_16_from_double (extremes[1].radius);
  339.  
  340.         pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
  341.                                                             pixman_stops,
  342.                                                             pattern->n_stops);
  343.     }
  344.  
  345.     if (pixman_stops != pixman_stops_static)
  346.         free (pixman_stops);
  347.  
  348.     if (unlikely (pixman_image == NULL))
  349.         return NULL;
  350.  
  351.     *ix = *iy = 0;
  352.     status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
  353.                                                     extents->x + extents->width/2.,
  354.                                                     extents->y + extents->height/2.,
  355.                                                     &pixman_transform, ix, iy);
  356.     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
  357.         if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
  358.             ! pixman_image_set_transform (pixman_image, &pixman_transform))
  359.         {
  360.             pixman_image_unref (pixman_image);
  361.             return NULL;
  362.         }
  363.     }
  364.  
  365.     {
  366.         pixman_repeat_t pixman_repeat;
  367.  
  368.         switch (pattern->base.extend) {
  369.         default:
  370.         case CAIRO_EXTEND_NONE:
  371.             pixman_repeat = PIXMAN_REPEAT_NONE;
  372.             break;
  373.         case CAIRO_EXTEND_REPEAT:
  374.             pixman_repeat = PIXMAN_REPEAT_NORMAL;
  375.             break;
  376.         case CAIRO_EXTEND_REFLECT:
  377.             pixman_repeat = PIXMAN_REPEAT_REFLECT;
  378.             break;
  379.         case CAIRO_EXTEND_PAD:
  380.             pixman_repeat = PIXMAN_REPEAT_PAD;
  381.             break;
  382.         }
  383.  
  384.         pixman_image_set_repeat (pixman_image, pixman_repeat);
  385.     }
  386.  
  387.     return pixman_image;
  388. }
  389.  
  390. static pixman_image_t *
  391. _pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern,
  392.                         const cairo_rectangle_int_t *extents,
  393.                         int *tx, int *ty)
  394. {
  395.     pixman_image_t *image;
  396.     int width, height;
  397.  
  398.     TRACE ((stderr, "%s\n", __FUNCTION__));
  399.  
  400.     *tx = -extents->x;
  401.     *ty = -extents->y;
  402.     width = extents->width;
  403.     height = extents->height;
  404.  
  405.     image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
  406.     if (unlikely (image == NULL))
  407.         return NULL;
  408.  
  409.     _cairo_mesh_pattern_rasterize (pattern,
  410.                                    pixman_image_get_data (image),
  411.                                    width, height,
  412.                                    pixman_image_get_stride (image),
  413.                                    *tx, *ty);
  414.     return image;
  415. }
  416.  
  417. struct acquire_source_cleanup {
  418.     cairo_surface_t *surface;
  419.     cairo_image_surface_t *image;
  420.     void *image_extra;
  421. };
  422.  
  423. static void
  424. _acquire_source_cleanup (pixman_image_t *pixman_image,
  425.                          void *closure)
  426. {
  427.     struct acquire_source_cleanup *data = closure;
  428.  
  429.     _cairo_surface_release_source_image (data->surface,
  430.                                          data->image,
  431.                                          data->image_extra);
  432.     free (data);
  433. }
  434.  
  435. static void
  436. _defer_free_cleanup (pixman_image_t *pixman_image,
  437.                      void *closure)
  438. {
  439.     cairo_surface_destroy (closure);
  440. }
  441.  
  442. static uint16_t
  443. expand_channel (uint16_t v, uint32_t bits)
  444. {
  445.     int offset = 16 - bits;
  446.     while (offset > 0) {
  447.         v |= v >> bits;
  448.         offset -= bits;
  449.         bits += bits;
  450.     }
  451.     return v;
  452. }
  453.  
  454. static pixman_image_t *
  455. _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
  456. {
  457.     uint32_t pixel;
  458.     pixman_color_t color;
  459.  
  460.     TRACE ((stderr, "%s\n", __FUNCTION__));
  461.  
  462.     switch (image->format) {
  463.     default:
  464.     case CAIRO_FORMAT_INVALID:
  465.         ASSERT_NOT_REACHED;
  466.         return NULL;
  467.  
  468.     case CAIRO_FORMAT_A1:
  469.         pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
  470.         return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
  471.  
  472.     case CAIRO_FORMAT_A8:
  473.         color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
  474.         color.alpha |= color.alpha << 8;
  475.         if (color.alpha == 0)
  476.             return _pixman_transparent_image ();
  477.         if (color.alpha == 0xffff)
  478.             return _pixman_black_image ();
  479.  
  480.         color.red = color.green = color.blue = 0;
  481.         return pixman_image_create_solid_fill (&color);
  482.  
  483.     case CAIRO_FORMAT_RGB16_565:
  484.         pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
  485.         if (pixel == 0)
  486.             return _pixman_black_image ();
  487.         if (pixel == 0xffff)
  488.             return _pixman_white_image ();
  489.  
  490.         color.alpha = 0xffff;
  491.         color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
  492.         color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
  493.         color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
  494.         return pixman_image_create_solid_fill (&color);
  495.  
  496.     case CAIRO_FORMAT_RGB30:
  497.         pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
  498.         pixel &= 0x3fffffff; /* ignore alpha bits */
  499.         if (pixel == 0)
  500.             return _pixman_black_image ();
  501.         if (pixel == 0x3fffffff)
  502.             return _pixman_white_image ();
  503.  
  504.         /* convert 10bpc to 16bpc */
  505.         color.alpha = 0xffff;
  506.         color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
  507.         color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
  508.         color.blue = expand_channel(pixel & 0x3fff, 10);
  509.         return pixman_image_create_solid_fill (&color);
  510.  
  511.     case CAIRO_FORMAT_ARGB32:
  512.     case CAIRO_FORMAT_RGB24:
  513.         pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
  514.         color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
  515.         if (color.alpha == 0)
  516.             return _pixman_transparent_image ();
  517.         if (pixel == 0xffffffff)
  518.             return _pixman_white_image ();
  519.         if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
  520.             return _pixman_black_image ();
  521.  
  522.         color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
  523.         color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
  524.         color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
  525.         return pixman_image_create_solid_fill (&color);
  526.     }
  527. }
  528.  
  529. static cairo_bool_t
  530. _pixman_image_set_properties (pixman_image_t *pixman_image,
  531.                               const cairo_pattern_t *pattern,
  532.                               const cairo_rectangle_int_t *extents,
  533.                               int *ix,int *iy)
  534. {
  535.     pixman_transform_t pixman_transform;
  536.     cairo_int_status_t status;
  537.  
  538.     status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix,
  539.                                                     pattern->filter,
  540.                                                     extents->x + extents->width/2.,
  541.                                                     extents->y + extents->height/2.,
  542.                                                     &pixman_transform, ix, iy);
  543.     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
  544.     {
  545.         /* If the transform is an identity, we don't need to set it
  546.          * and we can use any filtering, so choose the fastest one. */
  547.         pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
  548.     }
  549.     else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
  550.                        ! pixman_image_set_transform (pixman_image,
  551.                                                      &pixman_transform)))
  552.     {
  553.         return FALSE;
  554.     }
  555.     else
  556.     {
  557.         pixman_filter_t pixman_filter;
  558.  
  559.         switch (pattern->filter) {
  560.         case CAIRO_FILTER_FAST:
  561.             pixman_filter = PIXMAN_FILTER_FAST;
  562.             break;
  563.         case CAIRO_FILTER_GOOD:
  564.             pixman_filter = PIXMAN_FILTER_GOOD;
  565.             break;
  566.         case CAIRO_FILTER_BEST:
  567.             pixman_filter = PIXMAN_FILTER_BEST;
  568.             break;
  569.         case CAIRO_FILTER_NEAREST:
  570.             pixman_filter = PIXMAN_FILTER_NEAREST;
  571.             break;
  572.         case CAIRO_FILTER_BILINEAR:
  573.             pixman_filter = PIXMAN_FILTER_BILINEAR;
  574.             break;
  575.         case CAIRO_FILTER_GAUSSIAN:
  576.             /* XXX: The GAUSSIAN value has no implementation in cairo
  577.              * whatsoever, so it was really a mistake to have it in the
  578.              * API. We could fix this by officially deprecating it, or
  579.              * else inventing semantics and providing an actual
  580.              * implementation for it. */
  581.         default:
  582.             pixman_filter = PIXMAN_FILTER_BEST;
  583.         }
  584.  
  585.         pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
  586.     }
  587.  
  588.     {
  589.         pixman_repeat_t pixman_repeat;
  590.  
  591.         switch (pattern->extend) {
  592.         default:
  593.         case CAIRO_EXTEND_NONE:
  594.             pixman_repeat = PIXMAN_REPEAT_NONE;
  595.             break;
  596.         case CAIRO_EXTEND_REPEAT:
  597.             pixman_repeat = PIXMAN_REPEAT_NORMAL;
  598.             break;
  599.         case CAIRO_EXTEND_REFLECT:
  600.             pixman_repeat = PIXMAN_REPEAT_REFLECT;
  601.             break;
  602.         case CAIRO_EXTEND_PAD:
  603.             pixman_repeat = PIXMAN_REPEAT_PAD;
  604.             break;
  605.         }
  606.  
  607.         pixman_image_set_repeat (pixman_image, pixman_repeat);
  608.     }
  609.  
  610.     if (pattern->has_component_alpha)
  611.         pixman_image_set_component_alpha (pixman_image, TRUE);
  612.  
  613.     return TRUE;
  614. }
  615.  
  616. struct proxy {
  617.     cairo_surface_t base;
  618.     cairo_surface_t *image;
  619. };
  620.  
  621. static cairo_status_t
  622. proxy_acquire_source_image (void                         *abstract_surface,
  623.                             cairo_image_surface_t       **image_out,
  624.                             void                        **image_extra)
  625. {
  626.     struct proxy *proxy = abstract_surface;
  627.     return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra);
  628. }
  629.  
  630. static void
  631. proxy_release_source_image (void                        *abstract_surface,
  632.                             cairo_image_surface_t       *image,
  633.                             void                        *image_extra)
  634. {
  635.     struct proxy *proxy = abstract_surface;
  636.     _cairo_surface_release_source_image (proxy->image, image, image_extra);
  637. }
  638.  
  639. static cairo_status_t
  640. proxy_finish (void *abstract_surface)
  641. {
  642.     return CAIRO_STATUS_SUCCESS;
  643. }
  644.  
  645. static const cairo_surface_backend_t proxy_backend  = {
  646.     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
  647.     proxy_finish,
  648.     NULL,
  649.  
  650.     NULL, /* create similar */
  651.     NULL, /* create similar image */
  652.     NULL, /* map to image */
  653.     NULL, /* unmap image */
  654.  
  655.     _cairo_surface_default_source,
  656.     proxy_acquire_source_image,
  657.     proxy_release_source_image,
  658. };
  659.  
  660. static cairo_surface_t *
  661. attach_proxy (cairo_surface_t *source,
  662.               cairo_surface_t *image)
  663. {
  664.     struct proxy *proxy;
  665.  
  666.     proxy = malloc (sizeof (*proxy));
  667.     if (unlikely (proxy == NULL))
  668.         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
  669.  
  670.     _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content);
  671.  
  672.     proxy->image = image;
  673.     _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
  674.  
  675.     return &proxy->base;
  676. }
  677.  
  678. static void
  679. detach_proxy (cairo_surface_t *source,
  680.               cairo_surface_t *proxy)
  681. {
  682.     cairo_surface_finish (proxy);
  683.     cairo_surface_destroy (proxy);
  684. }
  685.  
  686. static cairo_surface_t *
  687. get_proxy (cairo_surface_t *proxy)
  688. {
  689.     return ((struct proxy *)proxy)->image;
  690. }
  691.  
  692. static pixman_image_t *
  693. _pixman_image_for_recording (cairo_image_surface_t *dst,
  694.                              const cairo_surface_pattern_t *pattern,
  695.                              cairo_bool_t is_mask,
  696.                              const cairo_rectangle_int_t *extents,
  697.                              const cairo_rectangle_int_t *sample,
  698.                              int *ix, int *iy)
  699. {
  700.     cairo_surface_t *source, *clone, *proxy;
  701.     cairo_rectangle_int_t limit;
  702.     pixman_image_t *pixman_image;
  703.     cairo_status_t status;
  704.     cairo_extend_t extend;
  705.     cairo_matrix_t *m, matrix;
  706.     int tx = 0, ty = 0;
  707.  
  708.     TRACE ((stderr, "%s\n", __FUNCTION__));
  709.  
  710.     *ix = *iy = 0;
  711.  
  712.     source = _cairo_pattern_get_source (pattern, &limit);
  713.  
  714.     extend = pattern->base.extend;
  715.     if (_cairo_rectangle_contains_rectangle (&limit, sample))
  716.         extend = CAIRO_EXTEND_NONE;
  717.     if (extend == CAIRO_EXTEND_NONE) {
  718.         if (! _cairo_rectangle_intersect (&limit, sample))
  719.             return _pixman_transparent_image ();
  720.  
  721.         if (! _cairo_matrix_is_identity (&pattern->base.matrix)) {
  722.             double x1, y1, x2, y2;
  723.  
  724.             matrix = pattern->base.matrix;
  725.             status = cairo_matrix_invert (&matrix);
  726.             assert (status == CAIRO_STATUS_SUCCESS);
  727.  
  728.             x1 = limit.x;
  729.             y1 = limit.y;
  730.             x2 = limit.x + limit.width;
  731.             y2 = limit.y + limit.height;
  732.  
  733.             _cairo_matrix_transform_bounding_box (&matrix,
  734.                                                   &x1, &y1, &x2, &y2, NULL);
  735.  
  736.             limit.x = floor (x1);
  737.             limit.y = floor (y1);
  738.             limit.width  = ceil (x2) - limit.x;
  739.             limit.height = ceil (y2) - limit.y;
  740.         }
  741.     }
  742.     tx = limit.x;
  743.     ty = limit.y;
  744.  
  745.     /* XXX transformations! */
  746.     proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
  747.     if (proxy != NULL) {
  748.         clone = cairo_surface_reference (get_proxy (proxy));
  749.         goto done;
  750.     }
  751.  
  752.     if (is_mask) {
  753.             clone = cairo_image_surface_create (CAIRO_FORMAT_A8,
  754.                                                 limit.width, limit.height);
  755.     } else {
  756.         if (dst->base.content == source->content)
  757.             clone = cairo_image_surface_create (dst->format,
  758.                                                 limit.width, limit.height);
  759.         else
  760.             clone = _cairo_image_surface_create_with_content (source->content,
  761.                                                               limit.width,
  762.                                                               limit.height);
  763.     }
  764.  
  765.     m = NULL;
  766.     if (extend == CAIRO_EXTEND_NONE) {
  767.         matrix = pattern->base.matrix;
  768.         if (tx | ty)
  769.             cairo_matrix_translate (&matrix, tx, ty);
  770.         m = &matrix;
  771.     } else {
  772.         /* XXX extract scale factor for repeating patterns */
  773.     }
  774.  
  775.     /* Handle recursion by returning future reads from the current image */
  776.     proxy = attach_proxy (source, clone);
  777.     status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
  778.     detach_proxy (source, proxy);
  779.     if (unlikely (status)) {
  780.         cairo_surface_destroy (clone);
  781.         return NULL;
  782.     }
  783.  
  784. done:
  785.     pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image);
  786.     cairo_surface_destroy (clone);
  787.  
  788.     *ix = -limit.x;
  789.     *iy = -limit.y;
  790.     if (extend != CAIRO_EXTEND_NONE) {
  791.         if (! _pixman_image_set_properties (pixman_image,
  792.                                             &pattern->base, extents,
  793.                                             ix, iy)) {
  794.             pixman_image_unref (pixman_image);
  795.             pixman_image= NULL;
  796.         }
  797.     }
  798.  
  799.     return pixman_image;
  800. }
  801.  
  802. static pixman_image_t *
  803. _pixman_image_for_surface (cairo_image_surface_t *dst,
  804.                            const cairo_surface_pattern_t *pattern,
  805.                            cairo_bool_t is_mask,
  806.                            const cairo_rectangle_int_t *extents,
  807.                            const cairo_rectangle_int_t *sample,
  808.                            int *ix, int *iy)
  809. {
  810.     cairo_extend_t extend = pattern->base.extend;
  811.     pixman_image_t *pixman_image;
  812.  
  813.     TRACE ((stderr, "%s\n", __FUNCTION__));
  814.  
  815.     *ix = *iy = 0;
  816.     pixman_image = NULL;
  817.     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
  818.         return _pixman_image_for_recording(dst, pattern,
  819.                                            is_mask, extents, sample,
  820.                                            ix, iy);
  821.  
  822.     if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
  823.         (! is_mask || ! pattern->base.has_component_alpha ||
  824.          (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
  825.     {
  826.         cairo_surface_t *defer_free = NULL;
  827.         cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
  828.         cairo_surface_type_t type;
  829.  
  830.         if (_cairo_surface_is_snapshot (&source->base)) {
  831.             defer_free = _cairo_surface_snapshot_get_target (&source->base);
  832.             source = (cairo_image_surface_t *) defer_free;
  833.         }
  834.  
  835.         type = source->base.backend->type;
  836.         if (type == CAIRO_SURFACE_TYPE_IMAGE) {
  837.             if (extend != CAIRO_EXTEND_NONE &&
  838.                 sample->x >= 0 &&
  839.                 sample->y >= 0 &&
  840.                 sample->x + sample->width  <= source->width &&
  841.                 sample->y + sample->height <= source->height)
  842.             {
  843.                 extend = CAIRO_EXTEND_NONE;
  844.             }
  845.  
  846.             if (sample->width == 1 && sample->height == 1) {
  847.                 if (sample->x < 0 ||
  848.                     sample->y < 0 ||
  849.                     sample->x >= source->width ||
  850.                     sample->y >= source->height)
  851.                 {
  852.                     if (extend == CAIRO_EXTEND_NONE) {
  853.                         cairo_surface_destroy (defer_free);
  854.                         return _pixman_transparent_image ();
  855.                     }
  856.                 }
  857.                 else
  858.                 {
  859.                     pixman_image = _pixel_to_solid (source,
  860.                                                     sample->x, sample->y);
  861.                     if (pixman_image) {
  862.                         cairo_surface_destroy (defer_free);
  863.                         return pixman_image;
  864.                     }
  865.                 }
  866.             }
  867.  
  868. #if PIXMAN_HAS_ATOMIC_OPS
  869.             /* avoid allocating a 'pattern' image if we can reuse the original */
  870.             if (extend == CAIRO_EXTEND_NONE &&
  871.                 _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
  872.                                                      pattern->base.filter,
  873.                                                      ix, iy))
  874.             {
  875.                 cairo_surface_destroy (defer_free);
  876.                 return pixman_image_ref (source->pixman_image);
  877.             }
  878. #endif
  879.  
  880.             pixman_image = pixman_image_create_bits (source->pixman_format,
  881.                                                      source->width,
  882.                                                      source->height,
  883.                                                      (uint32_t *) source->data,
  884.                                                      source->stride);
  885.             if (unlikely (pixman_image == NULL)) {
  886.                 cairo_surface_destroy (defer_free);
  887.                 return NULL;
  888.             }
  889.  
  890.             if (defer_free) {
  891.                 pixman_image_set_destroy_function (pixman_image,
  892.                                                    _defer_free_cleanup,
  893.                                                    defer_free);
  894.             }
  895.         } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
  896.             cairo_surface_subsurface_t *sub;
  897.             cairo_bool_t is_contained = FALSE;
  898.  
  899.             sub = (cairo_surface_subsurface_t *) source;
  900.             source = (cairo_image_surface_t *) sub->target;
  901.  
  902.             if (sample->x >= 0 &&
  903.                 sample->y >= 0 &&
  904.                 sample->x + sample->width  <= sub->extents.width &&
  905.                 sample->y + sample->height <= sub->extents.height)
  906.             {
  907.                 is_contained = TRUE;
  908.             }
  909.  
  910.             if (sample->width == 1 && sample->height == 1) {
  911.                 if (is_contained) {
  912.                     pixman_image = _pixel_to_solid (source,
  913.                                                     sub->extents.x + sample->x,
  914.                                                     sub->extents.y + sample->y);
  915.                     if (pixman_image)
  916.                         return pixman_image;
  917.                 } else {
  918.                     if (extend == CAIRO_EXTEND_NONE)
  919.                         return _pixman_transparent_image ();
  920.                 }
  921.             }
  922.  
  923. #if PIXMAN_HAS_ATOMIC_OPS
  924.             *ix = sub->extents.x;
  925.             *iy = sub->extents.y;
  926.             if (is_contained &&
  927.                 _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
  928.                                                      pattern->base.filter,
  929.                                                      ix, iy))
  930.             {
  931.                 return pixman_image_ref (source->pixman_image);
  932.             }
  933. #endif
  934.  
  935.             /* Avoid sub-byte offsets, force a copy in that case. */
  936.             if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
  937.                 if (is_contained) {
  938.                     void *data = source->data
  939.                         + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
  940.                         + sub->extents.y * source->stride;
  941.                     pixman_image = pixman_image_create_bits (source->pixman_format,
  942.                                                              sub->extents.width,
  943.                                                              sub->extents.height,
  944.                                                              data,
  945.                                                              source->stride);
  946.                     if (unlikely (pixman_image == NULL))
  947.                         return NULL;
  948.                 } else {
  949.                     /* XXX for a simple translation and EXTEND_NONE we can
  950.                      * fix up the pattern matrix instead.
  951.                      */
  952.                 }
  953.             }
  954.         }
  955.     }
  956.  
  957.     if (pixman_image == NULL) {
  958.         struct acquire_source_cleanup *cleanup;
  959.         cairo_image_surface_t *image;
  960.         void *extra;
  961.         cairo_status_t status;
  962.  
  963.         status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
  964.         if (unlikely (status))
  965.             return NULL;
  966.  
  967.         pixman_image = pixman_image_create_bits (image->pixman_format,
  968.                                                  image->width,
  969.                                                  image->height,
  970.                                                  (uint32_t *) image->data,
  971.                                                  image->stride);
  972.         if (unlikely (pixman_image == NULL)) {
  973.             _cairo_surface_release_source_image (pattern->surface, image, extra);
  974.             return NULL;
  975.         }
  976.  
  977.         cleanup = malloc (sizeof (*cleanup));
  978.         if (unlikely (cleanup == NULL)) {
  979.             _cairo_surface_release_source_image (pattern->surface, image, extra);
  980.             pixman_image_unref (pixman_image);
  981.             return NULL;
  982.         }
  983.  
  984.         cleanup->surface = pattern->surface;
  985.         cleanup->image = image;
  986.         cleanup->image_extra = extra;
  987.         pixman_image_set_destroy_function (pixman_image,
  988.                                            _acquire_source_cleanup, cleanup);
  989.     }
  990.  
  991.     if (! _pixman_image_set_properties (pixman_image,
  992.                                         &pattern->base, extents,
  993.                                         ix, iy)) {
  994.         pixman_image_unref (pixman_image);
  995.         pixman_image= NULL;
  996.     }
  997.  
  998.     return pixman_image;
  999. }
  1000.  
  1001. struct raster_source_cleanup {
  1002.     const cairo_pattern_t *pattern;
  1003.     cairo_surface_t *surface;
  1004.     cairo_image_surface_t *image;
  1005.     void *image_extra;
  1006. };
  1007.  
  1008. static void
  1009. _raster_source_cleanup (pixman_image_t *pixman_image,
  1010.                         void *closure)
  1011. {
  1012.     struct raster_source_cleanup *data = closure;
  1013.  
  1014.     _cairo_surface_release_source_image (data->surface,
  1015.                                          data->image,
  1016.                                          data->image_extra);
  1017.  
  1018.     _cairo_raster_source_pattern_release (data->pattern,
  1019.                                           data->surface);
  1020.  
  1021.     free (data);
  1022. }
  1023.  
  1024. static pixman_image_t *
  1025. _pixman_image_for_raster (cairo_image_surface_t *dst,
  1026.                           const cairo_raster_source_pattern_t *pattern,
  1027.                           cairo_bool_t is_mask,
  1028.                           const cairo_rectangle_int_t *extents,
  1029.                           const cairo_rectangle_int_t *sample,
  1030.                           int *ix, int *iy)
  1031. {
  1032.     pixman_image_t *pixman_image;
  1033.     struct raster_source_cleanup *cleanup;
  1034.     cairo_image_surface_t *image;
  1035.     void *extra;
  1036.     cairo_status_t status;
  1037.     cairo_surface_t *surface;
  1038.  
  1039.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1040.  
  1041.     *ix = *iy = 0;
  1042.  
  1043.     surface = _cairo_raster_source_pattern_acquire (&pattern->base,
  1044.                                                     &dst->base, NULL);
  1045.     if (unlikely (surface == NULL || surface->status))
  1046.         return NULL;
  1047.  
  1048.     status = _cairo_surface_acquire_source_image (surface, &image, &extra);
  1049.     if (unlikely (status)) {
  1050.         _cairo_raster_source_pattern_release (&pattern->base, surface);
  1051.         return NULL;
  1052.     }
  1053.  
  1054.     assert (image->width == pattern->extents.width);
  1055.     assert (image->height == pattern->extents.height);
  1056.  
  1057.     pixman_image = pixman_image_create_bits (image->pixman_format,
  1058.                                              image->width,
  1059.                                              image->height,
  1060.                                              (uint32_t *) image->data,
  1061.                                              image->stride);
  1062.     if (unlikely (pixman_image == NULL)) {
  1063.         _cairo_surface_release_source_image (surface, image, extra);
  1064.         _cairo_raster_source_pattern_release (&pattern->base, surface);
  1065.         return NULL;
  1066.     }
  1067.  
  1068.     cleanup = malloc (sizeof (*cleanup));
  1069.     if (unlikely (cleanup == NULL)) {
  1070.         pixman_image_unref (pixman_image);
  1071.         _cairo_surface_release_source_image (surface, image, extra);
  1072.         _cairo_raster_source_pattern_release (&pattern->base, surface);
  1073.         return NULL;
  1074.     }
  1075.  
  1076.     cleanup->pattern = &pattern->base;
  1077.     cleanup->surface = surface;
  1078.     cleanup->image = image;
  1079.     cleanup->image_extra = extra;
  1080.     pixman_image_set_destroy_function (pixman_image,
  1081.                                        _raster_source_cleanup, cleanup);
  1082.  
  1083.     if (! _pixman_image_set_properties (pixman_image,
  1084.                                         &pattern->base, extents,
  1085.                                         ix, iy)) {
  1086.         pixman_image_unref (pixman_image);
  1087.         pixman_image= NULL;
  1088.     }
  1089.  
  1090.     return pixman_image;
  1091. }
  1092.  
  1093. pixman_image_t *
  1094. _pixman_image_for_pattern (cairo_image_surface_t *dst,
  1095.                            const cairo_pattern_t *pattern,
  1096.                            cairo_bool_t is_mask,
  1097.                            const cairo_rectangle_int_t *extents,
  1098.                            const cairo_rectangle_int_t *sample,
  1099.                            int *tx, int *ty)
  1100. {
  1101.     *tx = *ty = 0;
  1102.  
  1103.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1104.  
  1105.     if (pattern == NULL)
  1106.         return _pixman_white_image ();
  1107.  
  1108.     switch (pattern->type) {
  1109.     default:
  1110.         ASSERT_NOT_REACHED;
  1111.     case CAIRO_PATTERN_TYPE_SOLID:
  1112.         return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color);
  1113.  
  1114.     case CAIRO_PATTERN_TYPE_RADIAL:
  1115.     case CAIRO_PATTERN_TYPE_LINEAR:
  1116.         return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
  1117.                                            extents, tx, ty);
  1118.  
  1119.     case CAIRO_PATTERN_TYPE_MESH:
  1120.         return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern,
  1121.                                            extents, tx, ty);
  1122.  
  1123.     case CAIRO_PATTERN_TYPE_SURFACE:
  1124.         return _pixman_image_for_surface (dst,
  1125.                                           (const cairo_surface_pattern_t *) pattern,
  1126.                                           is_mask, extents, sample,
  1127.                                           tx, ty);
  1128.  
  1129.     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
  1130.         return _pixman_image_for_raster (dst,
  1131.                                          (const cairo_raster_source_pattern_t *) pattern,
  1132.                                          is_mask, extents, sample,
  1133.                                          tx, ty);
  1134.     }
  1135. }
  1136.  
  1137. static cairo_status_t
  1138. _cairo_image_source_finish (void *abstract_surface)
  1139. {
  1140.     cairo_image_source_t *source = abstract_surface;
  1141.  
  1142.     pixman_image_unref (source->pixman_image);
  1143.     return CAIRO_STATUS_SUCCESS;
  1144. }
  1145.  
  1146. const cairo_surface_backend_t _cairo_image_source_backend = {
  1147.     CAIRO_SURFACE_TYPE_IMAGE,
  1148.     _cairo_image_source_finish,
  1149.     NULL, /* read-only wrapper */
  1150. };
  1151.  
  1152. cairo_surface_t *
  1153. _cairo_image_source_create_for_pattern (cairo_surface_t *dst,
  1154.                                          const cairo_pattern_t *pattern,
  1155.                                          cairo_bool_t is_mask,
  1156.                                          const cairo_rectangle_int_t *extents,
  1157.                                          const cairo_rectangle_int_t *sample,
  1158.                                          int *src_x, int *src_y)
  1159. {
  1160.     cairo_image_source_t *source;
  1161.  
  1162.     TRACE ((stderr, "%s\n", __FUNCTION__));
  1163.  
  1164.     source = malloc (sizeof (cairo_image_source_t));
  1165.     if (unlikely (source == NULL))
  1166.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  1167.  
  1168.     source->pixman_image =
  1169.         _pixman_image_for_pattern ((cairo_image_surface_t *)dst,
  1170.                                    pattern, is_mask,
  1171.                                    extents, sample,
  1172.                                    src_x, src_y);
  1173.     if (unlikely (source->pixman_image == NULL)) {
  1174.         free (source);
  1175.         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
  1176.     }
  1177.  
  1178.     _cairo_surface_init (&source->base,
  1179.                          &_cairo_image_source_backend,
  1180.                          NULL, /* device */
  1181.                          CAIRO_CONTENT_COLOR_ALPHA);
  1182.  
  1183.     source->is_opaque_solid =
  1184.         pattern == NULL || _cairo_pattern_is_opaque_solid (pattern);
  1185.  
  1186.     return &source->base;
  1187. }
  1188.