[cairo-commit] 3 commits - src/cairo-gl-operand.c src/cairo.h src/cairo-image-source.c src/cairo-mime-surface.c src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-raster-source-pattern.c src/cairo-script-surface.c src/cairo-surface-observer.c src/cairo-svg-surface.c src/cairo-xcb-surface-core.c src/cairo-xcb-surface-render.c src/Makefile.sources test/Makefile.sources test/mime-surface.c test/raster-source.c test/reference util/cairo-script util/cairo-trace

Chris Wilson ickle at kemper.freedesktop.org
Fri Nov 25 02:52:58 PST 2011


 dev/null                                          |binary
 src/Makefile.sources                              |    2 
 src/cairo-gl-operand.c                            |   55 --
 src/cairo-image-source.c                          |   95 +++++
 src/cairo-mime-surface.c                          |  405 ----------------------
 src/cairo-pattern-private.h                       |   41 ++
 src/cairo-pattern.c                               |  130 ++++++-
 src/cairo-pdf-surface.c                           |    4 
 src/cairo-ps-surface.c                            |    5 
 src/cairo-raster-source-pattern.c                 |  280 +++++++++++++++
 src/cairo-script-surface.c                        |   32 +
 src/cairo-surface-observer.c                      |    6 
 src/cairo-svg-surface.c                           |    1 
 src/cairo-xcb-surface-core.c                      |    1 
 src/cairo-xcb-surface-render.c                    |    3 
 src/cairo.h                                       |   90 ++--
 test/Makefile.sources                             |    2 
 test/mime-surface.c                               |  174 ---------
 test/raster-source.c                              |  134 +++++++
 test/reference/raster-source.base.argb32.ref.png  |binary
 test/reference/raster-source.base.rgb24.ref.png   |binary
 test/reference/raster-source.ref.png              |binary
 test/reference/raster-source.traps.argb32.ref.png |binary
 test/reference/raster-source.traps.rgb24.ref.png  |binary
 util/cairo-script/cairo-script-operators.c        |  158 ++------
 util/cairo-trace/trace.c                          |   28 -
 26 files changed, 848 insertions(+), 798 deletions(-)

New commits:
commit 4713562eda23c299b6065bd2cca9cb29d08e0763
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Nov 25 10:50:21 2011 +0000

    trace: Remove the warning about the unstable format
    
    We're stuck with the PostScript style for this generation now.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 3c698a6..ebcb293 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -770,7 +770,6 @@ _emit_header (void)
     get_prog_name (name, sizeof (name));
 
     _trace_printf ("%%!CairoScript - %s\n", name);
-    _trace_printf ("%%*** Warning CairoScript is still a new tracing format, and is subject to change.\n");
 }
 
 static cairo_bool_t
commit f5f303f10dd9c698e5d81d17b3fd8336508fd586
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Nov 25 10:48:50 2011 +0000

    script: Prefer polymorphorism for mesh path construction
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index ad1a201..8df03d6 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -1120,10 +1120,11 @@ static csi_status_t
 _curve_to (csi_t *ctx)
 {
     csi_status_t status;
+    csi_object_t *obj;
+    int type;
     double x1, y1;
     double x2, y2;
     double x3, y3;
-    cairo_t *cr;
 
     check (7);
 
@@ -1145,13 +1146,20 @@ _curve_to (csi_t *ctx)
     status = _csi_ostack_get_number (ctx, 5, &x1);
     if (_csi_unlikely (status))
 	return status;
-    status = _csi_ostack_get_context (ctx, 6, &cr);
-    if (_csi_unlikely (status))
-	return status;
 
-    /* XXX handle path object */
+    obj = _csi_peek_ostack (ctx, 6);
+    type = csi_object_get_type (obj);
+    switch (type) {
+    case CSI_OBJECT_TYPE_CONTEXT:
+	cairo_curve_to (obj->datum.cr, x1, y1, x2, y2, x3, y3);
+	break;
+    case CSI_OBJECT_TYPE_PATTERN:
+	cairo_mesh_pattern_curve_to (obj->datum.pattern,
+				     x1, y1, x2, y2, x3, y3);
+	break;
+	/* XXX handle path object */
+    }
 
-    cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
     pop (6);
     return CSI_STATUS_SUCCESS;
 }
@@ -3423,8 +3431,9 @@ static csi_status_t
 _line_to (csi_t *ctx)
 {
     csi_status_t status;
+    csi_object_t *obj;
+    int type;
     double x, y;
-    cairo_t *cr;
 
     check (3);
 
@@ -3434,14 +3443,21 @@ _line_to (csi_t *ctx)
     status = _csi_ostack_get_number (ctx, 1, &x);
     if (_csi_unlikely (status))
 	return status;
-    status = _csi_ostack_get_context (ctx, 2, &cr);
-    if (_csi_unlikely (status))
-	return status;
 
     /* XXX path object */
 
+    obj = _csi_peek_ostack (ctx, 2);
+    type = csi_object_get_type (obj);
+    switch (type) {
+    case CSI_OBJECT_TYPE_CONTEXT:
+	cairo_line_to (obj->datum.cr, x, y);
+	break;
+    case CSI_OBJECT_TYPE_PATTERN:
+	cairo_mesh_pattern_line_to (obj->datum.pattern, x, y);
+	break;
+    }
+
     pop (2);
-    cairo_line_to (cr, x, y);
     return CSI_STATUS_SUCCESS;
 }
 
@@ -3712,43 +3728,6 @@ _mesh_begin_patch (csi_t *ctx)
 }
 
 static csi_status_t
-_mesh_curve_to (csi_t *ctx)
-{
-    csi_status_t status;
-    double x1, y1, x2, y2, x3, y3;
-    cairo_pattern_t *pattern = NULL; /* silence the compiler */
-
-    check (7);
-
-    status = _csi_ostack_get_number (ctx, 0, &y3);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_number (ctx, 1, &x3);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_number (ctx, 2, &y2);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_number (ctx, 3, &x2);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_number (ctx, 4, &y1);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_number (ctx, 5, &x1);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_pattern (ctx, 6, &pattern);
-    if (_csi_unlikely (status))
-	return status;
-
-    cairo_mesh_pattern_curve_to (pattern, x1, y1, x2, y2, x3, y3);
-
-    pop (6);
-    return CSI_STATUS_SUCCESS;
-}
-
-static csi_status_t
 _mesh_end_patch (csi_t *ctx)
 {
     csi_status_t status;
@@ -3765,56 +3744,6 @@ _mesh_end_patch (csi_t *ctx)
 }
 
 static csi_status_t
-_mesh_line_to (csi_t *ctx)
-{
-    csi_status_t status;
-    double x, y;
-    cairo_pattern_t *pattern = NULL; /* silence the compiler */
-
-    check (3);
-
-    status = _csi_ostack_get_number (ctx, 0, &y);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_number (ctx, 1, &x);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_pattern (ctx, 2, &pattern);
-    if (_csi_unlikely (status))
-	return status;
-
-    cairo_mesh_pattern_line_to (pattern, x, y);
-
-    pop (2);
-    return CSI_STATUS_SUCCESS;
-}
-
-static csi_status_t
-_mesh_move_to (csi_t *ctx)
-{
-    csi_status_t status;
-    double x, y;
-    cairo_pattern_t *pattern = NULL; /* silence the compiler */
-
-    check (3);
-
-    status = _csi_ostack_get_number (ctx, 0, &y);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_number (ctx, 1, &x);
-    if (_csi_unlikely (status))
-	return status;
-    status = _csi_ostack_get_pattern (ctx, 2, &pattern);
-    if (_csi_unlikely (status))
-	return status;
-
-    cairo_mesh_pattern_move_to (pattern, x, y);
-
-    pop (2);
-    return CSI_STATUS_SUCCESS;
-}
-
-static csi_status_t
 _mesh_set_control_point (csi_t *ctx)
 {
     csi_status_t status;
@@ -3901,8 +3830,9 @@ static csi_status_t
 _move_to (csi_t *ctx)
 {
     csi_status_t status;
+    csi_object_t *obj;
+    int type;
     double x, y;
-    cairo_t *cr;
 
     check (3);
 
@@ -3912,14 +3842,21 @@ _move_to (csi_t *ctx)
     status = _csi_ostack_get_number (ctx, 1, &x);
     if (_csi_unlikely (status))
 	return status;
-    status = _csi_ostack_get_context (ctx, 2, &cr);
-    if (_csi_unlikely (status))
-	return status;
 
-    /* XXX path object */
+    obj = _csi_peek_ostack (ctx, 2);
+    type = csi_object_get_type (obj);
+    switch (type) {
+    case CSI_OBJECT_TYPE_CONTEXT:
+	cairo_move_to (obj->datum.cr, x, y);
+	break;
+    case CSI_OBJECT_TYPE_PATTERN:
+	cairo_mesh_pattern_move_to (obj->datum.pattern, x, y);
+	break;
+
+	/* XXX path object */
+    }
 
     pop (2);
-    cairo_move_to (cr, x, y);
     return CSI_STATUS_SUCCESS;
 }
 
@@ -6442,14 +6379,13 @@ _defs[] = {
     { "mark", _mark },
     { "mask", _mask },
     { "matrix", _matrix },
+
     { "mesh", _mesh },
-    { "mesh-begin-patch", _mesh_begin_patch },
-    { "mesh-curve-to", _mesh_curve_to },
-    { "mesh-end-patch", _mesh_end_patch },
-    { "mesh-line-to", _mesh_line_to },
-    { "mesh-move-to", _mesh_move_to },
-    { "mesh-set-control-point", _mesh_set_control_point },
-    { "mesh-set-corner-color", _mesh_set_corner_color },
+    { "begin-patch", _mesh_begin_patch },
+    { "end-patch", _mesh_end_patch },
+    { "set-control-point", _mesh_set_control_point },
+    { "set-corner-color", _mesh_set_corner_color },
+
     { "mod", _mod },
     { "move-to", _move_to },
     { "mul", _mul },
commit 8844d50308e03e7eb1d6e1530bb4bd98be490cea
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Nov 25 00:59:31 2011 +0000

    Convert cairo_mime_surface_t to cairo_raster_source_pattern_t
    
    As discussed, overloading the cairo_surface_t semantics to include
    sources (i.e. read-only surfaces) was duplicating the definition of
    cairo_pattern_t. So rather than introduce a new surface type with
    pattern semantics, start along the thorny road of extensible pattern
    types.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 867cc35..1182631 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -165,7 +165,6 @@ cairo_sources = \
 	cairo-matrix.c \
 	cairo-mask-compositor.c \
 	cairo-mesh-pattern-rasterizer.c \
-	cairo-mime-surface.c \
 	cairo-misc.c \
 	cairo-mono-scan-converter.c \
 	cairo-mutex.c \
@@ -187,6 +186,7 @@ cairo_sources = \
 	cairo-polygon.c \
 	cairo-polygon-intersect.c \
 	cairo-polygon-reduce.c \
+	cairo-raster-source-pattern.c \
 	cairo-recording-surface.c \
 	cairo-rectangle.c \
 	cairo-rectangular-scan-converter.c \
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
index 31776ff..8ff37c8 100644
--- a/src/cairo-gl-operand.c
+++ b/src/cairo-gl-operand.c
@@ -197,12 +197,11 @@ _cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
 				 cairo_gl_surface_t *dst,
 				 const cairo_rectangle_int_t *extents)
 {
-    const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
     cairo_status_t status;
-    cairo_matrix_t m;
     cairo_gl_surface_t *surface;
     cairo_gl_context_t *ctx;
     cairo_surface_attributes_t *attributes;
+    cairo_surface_t *image;
 
     attributes = &operand->texture.attributes;
 
@@ -212,57 +211,34 @@ _cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
 
     surface = (cairo_gl_surface_t *)
 	_cairo_gl_surface_create_scratch (ctx,
-					  src->surface->content,
+					  CAIRO_CONTENT_COLOR_ALPHA,
 					  extents->width, extents->height);
-    if (src->surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE) {
-	status = _cairo_gl_surface_draw_image (surface,
-				      (cairo_image_surface_t *)src->surface,
-				      0, 0,
-				      extents->width, extents->height,
-				      0, 0);
-
-	attributes->extend = src->base.extend;
-	attributes->filter = src->base.filter;
-    } else {
-	cairo_surface_t *image;
 
-	image = cairo_surface_map_to_image (&surface->base, NULL);
-	status = _cairo_surface_paint (image, CAIRO_OPERATOR_SOURCE,
-				       _src, NULL);
-	cairo_surface_unmap_image (&surface->base, image);
-
-	attributes->extend = CAIRO_EXTEND_NONE;
-	attributes->filter = CAIRO_FILTER_NEAREST;
+    image = cairo_surface_map_to_image (&surface->base, NULL);
+    status = _cairo_surface_offset_paint (image, -extents->x, -extents->y,
+					  CAIRO_OPERATOR_SOURCE, _src, NULL);
+    cairo_surface_unmap_image (&surface->base, image);
+    status = _cairo_gl_context_release (ctx, status);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&surface->base);
+	return status;
     }
 
-    status = _cairo_gl_context_release (ctx, status);
+    attributes->extend = CAIRO_EXTEND_NONE;
+    attributes->filter = CAIRO_FILTER_NEAREST;
+    attributes->has_component_alpha = FALSE;
 
     operand->type = CAIRO_GL_OPERAND_TEXTURE;
     operand->texture.surface = surface;
     operand->texture.tex = surface->tex;
 
-    /* Translate the matrix from
-     * (unnormalized src -> unnormalized src) to
-     * (unnormalized dst -> unnormalized src)
-     */
-    attributes->matrix = src->base.matrix;
-
-    /* Translate the matrix from
-     * (unnormalized dst -> unnormalized src) to
-     * (unnormalized dst -> normalized src)
-     */
     if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
-	cairo_matrix_init_scale (&m,
-				 1.0,
-				 1.0);
+	cairo_matrix_init_identity (&attributes->matrix);
     } else {
-	cairo_matrix_init_scale (&m,
+	cairo_matrix_init_scale (&attributes->matrix,
 				 1.0 / surface->width,
 				 1.0 / surface->height);
     }
-    cairo_matrix_multiply (&attributes->matrix,
-			   &attributes->matrix,
-			   &m);
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -447,6 +423,7 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
 
     default:
     case CAIRO_PATTERN_TYPE_MESH:
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
 	break;
     }
 
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index cdf9a7f..26f245a 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -889,6 +889,96 @@ _pixman_image_for_surface (cairo_image_surface_t *dst,
     return pixman_image;
 }
 
+struct raster_source_cleanup {
+    const cairo_pattern_t *pattern;
+    cairo_surface_t *surface;
+    cairo_image_surface_t *image;
+    void *image_extra;
+};
+
+static void
+_raster_source_cleanup (pixman_image_t *pixman_image,
+			void *closure)
+{
+    struct raster_source_cleanup *data = closure;
+
+    _cairo_surface_release_source_image (data->surface,
+					 data->image,
+					 data->image_extra);
+
+    _cairo_raster_source_pattern_release (data->pattern,
+					  data->surface);
+
+    free (data);
+}
+
+static pixman_image_t *
+_pixman_image_for_raster (cairo_image_surface_t *dst,
+			  const cairo_raster_source_pattern_t *pattern,
+			  cairo_bool_t is_mask,
+			  const cairo_rectangle_int_t *extents,
+			  const cairo_rectangle_int_t *sample,
+			  int *ix, int *iy)
+{
+    pixman_image_t *pixman_image;
+    struct raster_source_cleanup *cleanup;
+    cairo_image_surface_t *image;
+    void *extra;
+    cairo_status_t status;
+    cairo_surface_t *surface;
+
+    *ix = *iy = 0;
+
+    surface = _cairo_raster_source_pattern_acquire (&pattern->base,
+						    &dst->base, NULL);
+    if (unlikely (surface == NULL || surface->status))
+	return NULL;
+
+    status = _cairo_surface_acquire_source_image (surface, &image, &extra);
+    if (unlikely (status)) {
+	_cairo_raster_source_pattern_release (&pattern->base, surface);
+	return NULL;
+    }
+
+    assert (image->width == pattern->extents.width);
+    assert (image->height == pattern->extents.height);
+
+    pixman_image = pixman_image_create_bits (image->pixman_format,
+					     image->width,
+					     image->height,
+					     (uint32_t *) image->data,
+					     image->stride);
+    if (unlikely (pixman_image == NULL)) {
+	_cairo_surface_release_source_image (surface, image, extra);
+	_cairo_raster_source_pattern_release (&pattern->base, surface);
+	return NULL;
+    }
+
+    cleanup = malloc (sizeof (*cleanup));
+    if (unlikely (cleanup == NULL)) {
+	pixman_image_unref (pixman_image);
+	_cairo_surface_release_source_image (surface, image, extra);
+	_cairo_raster_source_pattern_release (&pattern->base, surface);
+	return NULL;
+    }
+
+    cleanup->pattern = &pattern->base;
+    cleanup->surface = surface;
+    cleanup->image = image;
+    cleanup->image_extra = extra;
+    pixman_image_set_destroy_function (pixman_image,
+				       _raster_source_cleanup, cleanup);
+
+    if (! _pixman_image_set_properties (pixman_image,
+					&pattern->base, extents,
+					ix, iy)) {
+	pixman_image_unref (pixman_image);
+	pixman_image= NULL;
+    }
+
+    return pixman_image;
+}
+
 pixman_image_t *
 _pixman_image_for_pattern (cairo_image_surface_t *dst,
 			   const cairo_pattern_t *pattern,
@@ -923,6 +1013,11 @@ _pixman_image_for_pattern (cairo_image_surface_t *dst,
 					  is_mask, extents, sample,
 					  tx, ty);
 
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	return _pixman_image_for_raster (dst,
+					 (const cairo_raster_source_pattern_t *) pattern,
+					 is_mask, extents, sample,
+					 tx, ty);
     }
 }
 
diff --git a/src/cairo-mime-surface.c b/src/cairo-mime-surface.c
deleted file mode 100644
index e19852f..0000000
--- a/src/cairo-mime-surface.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2011 Intel Corporation
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- *	Chris Wilson <chris at chris-wilson.co.uk>
- */
-
-/**
- * SECTION:cairo-mime-surface
- * @Title: Callback Surfaces
- * @Short_Description: Allows the user to provide a callback to supply image
- * data upon demand
- * @See_Also: #cairo_surface_t
- *
- * The mime surfaces provide the ability to render from arbitrary sources
- * not necessarily resident nor immediately usable by Cairo. The user is
- * given the ability to insert a placeholder surface which can be used
- * with a pattern and then later supply the actual pixel data upon demand.
- * This deferred source is given both the sample region for the operation
- * along with the destination surface such that they may be taken into
- * account when creating the actual surface to use as the source of pixel
- * data.
- *
- * The reason why it is called the mime surface is two-fold. First it came
- * about as an extension of the mime-data property to handle deferred
- * image decoding when rendering to pixel buffers (as opposed to the pass-
- * through support in PDF and friends.) And then to further rationalise
- * the name, it is a surface that mimics a real source without ever
- * holding onto to any pixels of its own - a mime surface.
- *
- * The mime-surface callback interface consists of 4 functions. The principal
- * pair are the acquire/release callbacks which are called when pixel data
- * is required for an operation (along with the target surface and the sample
- * extents). The callee must supply a surface that covers the sample area and
- * set the actual extents of the returned surface in the output rectangle
- * parameter. The surface does not necessarily have to be an image surface,
- * but it is expected that an image surface is likely to be the most
- * convenient for uploading pixel data. (Use
- * cairo_surface_create_similar_image() to create an image surface that is
- * optimised for uploading to the target.) The release callback is
- * subsequently called when the returned surface is no longer needed (before
- * the operation completes, within the lifetime of the source).
- *
- * The other pair of functions are to aide with lifetime management of the
- * surface with respect to patterns and other users. The destroy callback
- * allows for the caller to cleanup the associated data when the last
- * reference to surface is destroyed. The snapshot callback is triggered
- * when there is an immutable surface pattern referencing the mime-surface
- * and the mime-surface will be be invalidated. (Since the mime-surface is
- * read-only and a reference will be held by the pattern, this can only be
- * triggered through an explicit cairo_surface_finish().) In this
- * circumstance, we need to clone the source in order to preserve the pixel
- * data for later use (i.e. we have recorded the pattern). The snapshot
- * callback provides an interface for the caller to clone the mime-surface
- * in an efficient manner.  The returned surface may be of any type so long
- * as it holds all pixel data and remains accessible.
- */
-
-/**
- * CAIRO_HAS_MIME_SURFACE:
- *
- * Defined if the mime surface backend is available.
- * The mime surface backend is always built in.
- *
- * @Since: 1.12
- */
-
-#include "cairoint.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-surface-backend-private.h"
-
-typedef struct _cairo_mime_surface {
-    cairo_surface_t base;
-
-    cairo_rectangle_int_t extents;
-
-    cairo_mime_surface_acquire_t acquire;
-    cairo_mime_surface_release_t release;
-    cairo_mime_surface_snapshot_t snapshot;
-    cairo_mime_surface_destroy_t destroy;
-
-    /* an explicit pre-allocated member in preference to the general user-data */
-    void *user_data;
-} cairo_mime_surface_t;
-
-static cairo_status_t
-_cairo_mime_surface_finish (void *abstract_surface)
-{
-    cairo_mime_surface_t *surface = abstract_surface;
-
-    if (surface->destroy)
-	surface->destroy (&surface->base, surface->user_data);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_bool_t
-_cairo_mime_surface_get_extents (void			  *abstract_surface,
-				 cairo_rectangle_int_t   *rectangle)
-{
-    cairo_mime_surface_t *surface = abstract_surface;
-
-    *rectangle = surface->extents;
-    return TRUE;
-}
-
-static cairo_status_t
-_cairo_mime_surface_acquire_source_image (void                    *abstract_surface,
-					  //cairo_surface_t	  *target,
-					  cairo_image_surface_t  **image_out,
-					  void                   **image_extra)
-{
-    cairo_mime_surface_t *mime = abstract_surface;
-    cairo_surface_t *acquired;
-    cairo_surface_t *dummy_target;
-    cairo_rectangle_int_t extents;
-
-    if (mime->acquire == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* Force the callee to populate the extents rectangle */
-    memset (&extents, 0, sizeof (extents));
-
-    /* Masquerade for a flexible user-interface */
-    dummy_target = _cairo_image_surface_create_with_content (mime->base.content, 0, 0);
-    acquired = mime->acquire (&mime->base, mime->user_data,
-			      dummy_target, &mime->extents, &extents);
-    cairo_surface_destroy (dummy_target);
-
-    if (acquired == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* The callee must have supplied us with all the image data */
-    assert (extents.width == mime->extents.width && extents.height == mime->extents.height);
-
-    if (! _cairo_surface_is_image (acquired)) {
-	cairo_status_t status;
-	void *extra = NULL;
-
-	status = _cairo_surface_acquire_source_image (acquired, image_out, &extra);
-	if (unlikely (status)) {
-	    cairo_surface_destroy (acquired);
-	    return status;
-	}
-
-	assert (extra == NULL);
-	*image_extra = acquired;
-    } else {
-	*image_out = (cairo_image_surface_t *) acquired;
-	*image_extra = NULL;
-    }
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_mime_surface_release_source_image (void                   *abstract_surface,
-					  cairo_image_surface_t  *image,
-					  void                   *image_extra)
-{
-    cairo_mime_surface_t *mime = abstract_surface;
-
-    if (image_extra) {
-	cairo_surface_destroy (&image->base);
-	image = image_extra;
-    }
-
-    if (mime->release)
-	mime->release (&mime->base, mime->user_data, &image->base);
-}
-
-static cairo_surface_t *
-_cairo_mime_surface_snapshot (void *abstract_surface)
-{
-    cairo_mime_surface_t *mime = abstract_surface;
-
-    if (mime->snapshot == NULL)
-	return NULL;
-
-    return mime->snapshot (&mime->base, mime->user_data);
-}
-
-static const cairo_surface_backend_t cairo_mime_surface_backend = {
-    CAIRO_SURFACE_TYPE_MIME,
-    _cairo_mime_surface_finish,
-
-    NULL, /* Read-only */
-
-    NULL, /* create similar */
-    NULL, /* create similar image */
-    NULL, /* map to image */
-    NULL, /* unmap image */
-
-    _cairo_mime_surface_acquire_source_image,
-    _cairo_mime_surface_release_source_image,
-    _cairo_mime_surface_snapshot,
-
-    NULL, /* copy_page */
-    NULL, /* show_page */
-
-    _cairo_mime_surface_get_extents,
-    NULL, /* get_font_options */
-
-    NULL, /* flush */
-    NULL, /* mark_dirty_rectangle */
-
-    NULL, /* scaled_font_fini */
-    NULL, /* scaled_glyph_fini */
-
-    NULL, /* paint */
-    NULL, /* mask */
-    NULL, /* stroke */
-    NULL, /* fill */
-    NULL, /* glyphs */
-};
-
-cairo_surface_t *
-cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height)
-{
-    cairo_mime_surface_t *surface;
-
-    if (width < 0 || height < 0)
-	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
-
-    if (! CAIRO_CONTENT_VALID (content))
-	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
-
-    surface = calloc (1, sizeof (*surface));
-    if (unlikely (surface == NULL))
-	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
-    _cairo_surface_init (&surface->base,
-			 &cairo_mime_surface_backend,
-			 NULL, /* device */
-			 content);
-
-    surface->extents.x = 0;
-    surface->extents.y = 0;
-    surface->extents.width  = width;
-    surface->extents.height = height;
-
-    surface->user_data = data;
-
-    return &surface->base;
-}
-
-void
-cairo_mime_surface_set_callback_data (cairo_surface_t *surface,
-				      void *data)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return;
-
-    mime = (cairo_mime_surface_t *)surface;
-    mime->user_data = data;
-}
-
-void *
-cairo_mime_surface_get_callback_data (cairo_surface_t *surface)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return NULL;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return NULL;
-
-    mime = (cairo_mime_surface_t *)surface;
-    return mime->user_data;
-}
-
-void
-cairo_mime_surface_set_acquire (cairo_surface_t *surface,
-				cairo_mime_surface_acquire_t acquire,
-				cairo_mime_surface_release_t release)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return;
-
-    mime = (cairo_mime_surface_t *)surface;
-    mime->acquire = acquire;
-    mime->release = release;
-}
-
-void
-cairo_mime_surface_get_acquire (cairo_surface_t *surface,
-				cairo_mime_surface_acquire_t *acquire,
-				cairo_mime_surface_release_t *release)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return;
-
-    mime = (cairo_mime_surface_t *)surface;
-    if (acquire)
-	*acquire = mime->acquire;
-    if (release)
-	*release = mime->release;
-}
-
-void
-cairo_mime_surface_set_snapshot (cairo_surface_t *surface,
-				 cairo_mime_surface_snapshot_t snapshot)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return;
-
-    mime = (cairo_mime_surface_t *)surface;
-    mime->snapshot = snapshot;
-}
-
-cairo_mime_surface_snapshot_t
-cairo_mime_surface_get_snapshot (cairo_surface_t *surface)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return NULL;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return NULL;
-
-    mime = (cairo_mime_surface_t *)surface;
-    return mime->snapshot;
-}
-
-void
-cairo_mime_surface_set_destroy (cairo_surface_t *surface,
-				cairo_mime_surface_destroy_t destroy)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return;
-
-    mime = (cairo_mime_surface_t *)surface;
-    mime->destroy = destroy;
-}
-
-cairo_mime_surface_destroy_t
-cairo_mime_surface_get_destroy (cairo_surface_t *surface)
-{
-    cairo_mime_surface_t *mime;
-
-    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
-	return NULL;
-
-    if (surface->backend != &cairo_mime_surface_backend)
-	return NULL;
-
-    mime = (cairo_mime_surface_t *)surface;
-    return mime->destroy;
-}
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index 8be319e..9b2f875 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -167,6 +167,22 @@ typedef struct _cairo_mesh_pattern {
     cairo_bool_t has_color[4];
 } cairo_mesh_pattern_t;
 
+typedef struct _cairo_raster_source_pattern {
+    cairo_pattern_t base;
+
+    cairo_content_t content;
+    cairo_rectangle_int_t extents;
+
+    cairo_raster_source_acquire_func_t acquire;
+    cairo_raster_source_release_func_t release;
+    cairo_raster_source_snapshot_func_t snapshot;
+    cairo_raster_source_copy_func_t copy;
+    cairo_raster_source_finish_func_t finish;
+
+    /* an explicit pre-allocated member in preference to the general user-data */
+    void *user_data;
+} cairo_raster_source_pattern_t;
+
 typedef union {
     cairo_pattern_t		    base;
 
@@ -174,9 +190,9 @@ typedef union {
     cairo_surface_pattern_t	    surface;
     cairo_gradient_pattern_union_t  gradient;
     cairo_mesh_pattern_t	    mesh;
+    cairo_raster_source_pattern_t   raster_source;
 } cairo_pattern_union_t;
 
-
 /* cairo-pattern.c */
 
 cairo_private cairo_pattern_t *
@@ -186,6 +202,10 @@ cairo_private cairo_status_t
 _cairo_pattern_create_copy (cairo_pattern_t	  **pattern,
 			    const cairo_pattern_t  *other);
 
+cairo_private void
+_cairo_pattern_init (cairo_pattern_t *pattern,
+		     cairo_pattern_type_t type);
+
 cairo_private cairo_status_t
 _cairo_pattern_init_copy (cairo_pattern_t	*pattern,
 			  const cairo_pattern_t *other);
@@ -328,6 +348,25 @@ _cairo_mesh_pattern_rasterize (const cairo_mesh_pattern_t *mesh,
 			       double                      x_offset,
 			       double                      y_offset);
 
+cairo_private cairo_surface_t *
+_cairo_raster_source_pattern_acquire (const cairo_pattern_t *abstract_pattern,
+				      cairo_surface_t *target,
+				      const cairo_rectangle_int_t *extents);
+
+cairo_private void
+_cairo_raster_source_pattern_release (const cairo_pattern_t *abstract_pattern,
+				      cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_raster_source_pattern_snapshot (cairo_pattern_t *abstract_pattern);
+
+cairo_private cairo_status_t
+_cairo_raster_source_pattern_init_copy (cairo_pattern_t *pattern,
+					const cairo_pattern_t *other);
+
+cairo_private void
+_cairo_raster_source_pattern_finish (cairo_pattern_t *abstract_pattern);
+
 cairo_private void
 _cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern);
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index f91de26..e55e5eb 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -187,7 +187,7 @@ _cairo_pattern_set_error (cairo_pattern_t *pattern,
     return _cairo_error (status);
 }
 
-static void
+void
 _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
 {
 #if HAVE_VALGRIND
@@ -207,6 +207,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
     case CAIRO_PATTERN_TYPE_MESH:
 	VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_mesh_pattern_t));
 	break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	break;
     }
 #endif
 
@@ -219,7 +221,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
 
     _cairo_user_data_array_init (&pattern->user_data);
 
-    if (type == CAIRO_PATTERN_TYPE_SURFACE)
+    if (type == CAIRO_PATTERN_TYPE_SURFACE ||
+	type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
 	pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
     else
 	pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
@@ -291,6 +294,8 @@ cairo_status_t
 _cairo_pattern_init_copy (cairo_pattern_t	*pattern,
 			  const cairo_pattern_t *other)
 {
+    cairo_status_t status;
+
     if (other->status)
 	return _cairo_pattern_set_error (pattern, other->status);
 
@@ -316,7 +321,6 @@ _cairo_pattern_init_copy (cairo_pattern_t	*pattern,
     case CAIRO_PATTERN_TYPE_RADIAL: {
 	cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
 	cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
-	cairo_status_t status;
 
 	if (other->type == CAIRO_PATTERN_TYPE_LINEAR) {
 	    VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)));
@@ -332,7 +336,6 @@ _cairo_pattern_init_copy (cairo_pattern_t	*pattern,
     case CAIRO_PATTERN_TYPE_MESH: {
 	cairo_mesh_pattern_t *dst = (cairo_mesh_pattern_t *) pattern;
 	cairo_mesh_pattern_t *src = (cairo_mesh_pattern_t *) other;
-	cairo_status_t status;
 
 	VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_mesh_pattern_t)));
 
@@ -341,6 +344,12 @@ _cairo_pattern_init_copy (cairo_pattern_t	*pattern,
 	    return status;
 
     } break;
+
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
+	status = _cairo_raster_source_pattern_init_copy (pattern, other);
+	if (unlikely (status))
+	    return status;
+    } break;
     }
 
     /* The reference count and user_data array are unique to the copy. */
@@ -376,6 +385,9 @@ _cairo_pattern_init_static_copy (cairo_pattern_t	*pattern,
     case CAIRO_PATTERN_TYPE_MESH:
 	size = sizeof (cairo_mesh_pattern_t);
 	break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	size = sizeof (cairo_raster_source_pattern_t);
+	break;
     }
 
     memcpy (pattern, other, size);
@@ -407,11 +419,11 @@ _cairo_pattern_init_snapshot (cairo_pattern_t       *pattern,
 
 	cairo_surface_destroy (surface);
 
-	if (surface_pattern->surface->status)
-	    return surface_pattern->surface->status;
-    }
+	status = surface_pattern->surface->status;
+    } else if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	status = _cairo_raster_source_pattern_snapshot (pattern);
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 void
@@ -442,6 +454,9 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
 
 	_cairo_array_fini (&mesh->patches);
     } break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	_cairo_raster_source_pattern_finish (pattern);
+	break;
     }
 
 #if HAVE_VALGRIND
@@ -461,6 +476,8 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
     case CAIRO_PATTERN_TYPE_MESH:
 	VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_mesh_pattern_t));
 	break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	break;
     }
 #endif
 }
@@ -491,6 +508,9 @@ _cairo_pattern_create_copy (cairo_pattern_t	  **pattern_out,
     case CAIRO_PATTERN_TYPE_MESH:
 	pattern = malloc (sizeof (cairo_mesh_pattern_t));
 	break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	pattern = malloc (sizeof (cairo_raster_source_pattern_t));
+	break;
     default:
 	ASSERT_NOT_REACHED;
 	return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
@@ -1093,7 +1113,10 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
     _cairo_pattern_fini (pattern);
 
     /* maintain a small cache of freed patterns */
-    _freed_pool_put (&freed_pattern_pool[type], pattern);
+    if (type < ARRAY_LENGTH (freed_pattern_pool))
+	_freed_pool_put (&freed_pattern_pool[type], pattern);
+    else
+	free (pattern);
 }
 slim_hidden_def (cairo_pattern_destroy);
 
@@ -2929,6 +2952,7 @@ _cairo_pattern_alpha_range (const cairo_pattern_t *pattern,
 	/* fall through */
 
     case CAIRO_PATTERN_TYPE_SURFACE:
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
 	alpha_min = 0;
 	alpha_max = 1;
 	break;
@@ -3133,6 +3157,29 @@ _surface_is_opaque (const cairo_surface_pattern_t *pattern,
 }
 
 static cairo_bool_t
+_raster_source_is_opaque (const cairo_raster_source_pattern_t *pattern,
+			  const cairo_rectangle_int_t *sample)
+{
+    if (pattern->content & CAIRO_CONTENT_ALPHA)
+	return FALSE;
+
+    if (pattern->base.extend != CAIRO_EXTEND_NONE)
+	return TRUE;
+
+    if (sample != NULL) {
+	if (sample->x >= pattern->extents.x &&
+	    sample->y >= pattern->extents.y &&
+	    sample->x + sample->width  <= pattern->extents.x + pattern->extents.width &&
+	    sample->y + sample->height <= pattern->extents.y + pattern->extents.height)
+	{
+	    return TRUE;
+	}
+    }
+
+    return FALSE;
+}
+
+static cairo_bool_t
 _surface_is_clear (const cairo_surface_pattern_t *pattern)
 {
     cairo_rectangle_int_t extents;
@@ -3146,6 +3193,12 @@ _surface_is_clear (const cairo_surface_pattern_t *pattern)
 }
 
 static cairo_bool_t
+_raster_source_is_clear (const cairo_raster_source_pattern_t *pattern)
+{
+    return pattern->extents.width == 0 || pattern->extents.height == 0;
+}
+
+static cairo_bool_t
 _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
 		     const cairo_rectangle_int_t *sample)
 {
@@ -3215,6 +3268,8 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
 	return _cairo_pattern_is_opaque_solid (abstract_pattern);
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return _surface_is_opaque (&pattern->surface, sample);
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	return _raster_source_is_opaque (&pattern->raster_source, sample);
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
 	return _gradient_is_opaque (&pattern->gradient.base, sample);
@@ -3240,6 +3295,8 @@ _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
 	return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color);
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return _surface_is_clear (&pattern->surface);
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	return _raster_source_is_clear (&pattern->raster_source);
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
 	return _gradient_is_clear (&pattern->gradient.base, NULL);
@@ -3409,6 +3466,29 @@ _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
 	}
 	break;
 
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	{
+	    const cairo_raster_source_pattern_t *raster =
+		(const cairo_raster_source_pattern_t *) pattern;
+	    double pad;
+
+	    if (raster->extents.width == 0 || raster->extents.height == 0)
+		goto EMPTY;
+
+	    if (pattern->extend != CAIRO_EXTEND_NONE)
+		goto UNBOUNDED;
+
+	    /* The filter can effectively enlarge the extents of the
+	     * pattern, so extend as necessary.
+	     */
+	    _cairo_pattern_analyze_filter (pattern, &pad);
+	    x1 = raster->extents.x - pad;
+	    y1 = raster->extents.y - pad;
+	    x2 = raster->extents.x + (int) raster->extents.width  + pad;
+	    y2 = raster->extents.y + (int) raster->extents.height + pad;
+	}
+	break;
+
     case CAIRO_PATTERN_TYPE_RADIAL:
 	{
 	    const cairo_radial_pattern_t *radial =
@@ -3666,6 +3746,15 @@ _cairo_surface_pattern_hash (unsigned long hash,
     return hash;
 }
 
+static unsigned long
+_cairo_raster_source_pattern_hash (unsigned long hash,
+				   const cairo_raster_source_pattern_t *raster)
+{
+    hash ^= (uintptr_t)raster->user_data;
+
+    return hash;
+}
+
 unsigned long
 _cairo_pattern_hash (const cairo_pattern_t *pattern)
 {
@@ -3698,6 +3787,8 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
 	return _cairo_mesh_pattern_hash (hash, (cairo_mesh_pattern_t *) pattern);
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return _cairo_surface_pattern_hash (hash, (cairo_surface_pattern_t *) pattern);
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	return _cairo_raster_source_pattern_hash (hash, (cairo_raster_source_pattern_t *) pattern);
     default:
 	ASSERT_NOT_REACHED;
 	return FALSE;
@@ -3804,6 +3895,13 @@ _cairo_surface_pattern_equal (const cairo_surface_pattern_t *a,
     return a->surface->unique_id == b->surface->unique_id;
 }
 
+static cairo_bool_t
+_cairo_raster_source_pattern_equal (const cairo_raster_source_pattern_t *a,
+				    const cairo_raster_source_pattern_t *b)
+{
+    return a->user_data == b->user_data;
+}
+
 cairo_bool_t
 _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
 {
@@ -3846,6 +3944,9 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return _cairo_surface_pattern_equal ((cairo_surface_pattern_t *) a,
 					     (cairo_surface_pattern_t *) b);
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	return _cairo_raster_source_pattern_equal ((cairo_raster_source_pattern_t *) a,
+						   (cairo_raster_source_pattern_t *) b);
     default:
 	ASSERT_NOT_REACHED;
 	return FALSE;
@@ -4381,6 +4482,13 @@ _cairo_debug_print_surface_pattern (FILE *file,
 }
 
 static void
+_cairo_debug_print_raster_source_pattern (FILE *file,
+					  const cairo_raster_source_pattern_t *raster)
+{
+    printf ("  content: %x, size %dx%d\n", raster->content, raster->extents.width, raster->extents.height);
+}
+
+static void
 _cairo_debug_print_linear_pattern (FILE *file,
 				    const cairo_linear_pattern_t *pattern)
 {
@@ -4408,6 +4516,7 @@ _cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern)
     case CAIRO_PATTERN_TYPE_LINEAR: s = "linear"; break;
     case CAIRO_PATTERN_TYPE_RADIAL: s = "radial"; break;
     case CAIRO_PATTERN_TYPE_MESH: s = "mesh"; break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE: s = "raster"; break;
     default: s = "invalid"; ASSERT_NOT_REACHED; break;
     }
 
@@ -4442,6 +4551,9 @@ _cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern)
     default:
     case CAIRO_PATTERN_TYPE_SOLID:
 	break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	_cairo_debug_print_raster_source_pattern (file, (cairo_raster_source_pattern_t *)pattern);
+	break;
     case CAIRO_PATTERN_TYPE_SURFACE:
 	_cairo_debug_print_surface_pattern (file, (cairo_surface_pattern_t *)pattern);
 	break;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 988a215..f45846c 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -3621,6 +3621,7 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern
 
     switch (pdf_pattern->pattern->type) {
     case CAIRO_PATTERN_TYPE_SOLID:
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
 	ASSERT_NOT_REACHED;
 	status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 	break;
@@ -5742,7 +5743,7 @@ _pattern_supported (const cairo_pattern_t *pattern)
     case CAIRO_PATTERN_TYPE_SOLID:
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
-    case CAIRO_PATTERN_TYPE_MESH:	
+    case CAIRO_PATTERN_TYPE_MESH:
 	return TRUE;
 
     case CAIRO_PATTERN_TYPE_SURFACE:
@@ -5750,6 +5751,7 @@ _pattern_supported (const cairo_pattern_t *pattern)
 
     default:
 	ASSERT_NOT_REACHED;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE: /* XXX */
 	return FALSE;
     }
 }
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 36d555d..95b3d12 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1769,6 +1769,8 @@ pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern)
 
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	return FALSE;
 
     default:
 	ASSERT_NOT_REACHED;
@@ -3714,6 +3716,9 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
 	if (unlikely (status))
 	    return status;
 	break;
+
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE: /* XXX */
+	break;
     }
 
     return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-raster-source-pattern.c b/src/cairo-raster-source-pattern.c
new file mode 100644
index 0000000..40031f7
--- /dev/null
+++ b/src/cairo-raster-source-pattern.c
@@ -0,0 +1,280 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+#include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
+
+cairo_surface_t *
+_cairo_raster_source_pattern_acquire (const cairo_pattern_t *abstract_pattern,
+				      cairo_surface_t *target,
+				      const cairo_rectangle_int_t *extents)
+{
+    cairo_raster_source_pattern_t *pattern =
+	(cairo_raster_source_pattern_t *) abstract_pattern;
+
+    if (pattern->acquire == NULL)
+	return NULL;
+
+    if (extents == NULL)
+	extents = &pattern->extents;
+
+    return pattern->acquire (&pattern->base, pattern->user_data,
+			     target, extents);
+}
+
+void
+_cairo_raster_source_pattern_release (const cairo_pattern_t *abstract_pattern,
+				      cairo_surface_t *surface)
+{
+    cairo_raster_source_pattern_t *pattern =
+	(cairo_raster_source_pattern_t *) abstract_pattern;
+
+    if (pattern->release == NULL)
+	return;
+
+    return pattern->release (&pattern->base, pattern->user_data,
+			     surface);
+}
+
+cairo_status_t
+_cairo_raster_source_pattern_init_copy (cairo_pattern_t *abstract_pattern,
+					const cairo_pattern_t *other)
+{
+    cairo_raster_source_pattern_t *pattern =
+	(cairo_raster_source_pattern_t *) abstract_pattern;
+    cairo_status_t status;
+
+    VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_raster_source_pattern_t)));
+    memcpy(pattern, other, sizeof (cairo_raster_source_pattern_t));
+
+    status = CAIRO_STATUS_SUCCESS;
+    if (pattern->copy)
+	status = pattern->copy (&pattern->base, pattern->user_data, other);
+
+    return status;
+}
+
+cairo_status_t
+_cairo_raster_source_pattern_snapshot (cairo_pattern_t *abstract_pattern)
+{
+    cairo_raster_source_pattern_t *pattern =
+	(cairo_raster_source_pattern_t *) abstract_pattern;
+
+    if (pattern->snapshot == NULL)
+	return CAIRO_STATUS_SUCCESS;
+
+    return pattern->snapshot (&pattern->base, pattern->user_data);
+}
+
+void
+_cairo_raster_source_pattern_finish (cairo_pattern_t *abstract_pattern)
+{
+    cairo_raster_source_pattern_t *pattern =
+	(cairo_raster_source_pattern_t *) abstract_pattern;
+
+    if (pattern->finish == NULL)
+	return;
+
+    pattern->finish (&pattern->base, pattern->user_data);
+}
+
+cairo_pattern_t *
+cairo_pattern_create_raster_source (void *user_data,
+				    cairo_content_t content,
+				    int width, int height)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    CAIRO_MUTEX_INITIALIZE ();
+
+    if (width < 0 || height < 0)
+	return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+    if (! CAIRO_CONTENT_VALID (content))
+	return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
+
+    pattern = calloc (1, sizeof (*pattern));
+    if (unlikely (pattern == NULL))
+	return _cairo_pattern_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    _cairo_pattern_init (&pattern->base,
+			 CAIRO_PATTERN_TYPE_RASTER_SOURCE);
+    CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
+
+    pattern->content = content;
+
+    pattern->extents.x = 0;
+    pattern->extents.y = 0;
+    pattern->extents.width  = width;
+    pattern->extents.height = height;
+
+    pattern->user_data = user_data;
+
+    return &pattern->base;
+}
+
+void
+cairo_raster_source_pattern_set_callback_data (cairo_pattern_t *abstract_pattern,
+					       void *data)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    pattern->user_data = data;
+}
+
+void *
+cairo_raster_source_pattern_get_callback_data (cairo_pattern_t *abstract_pattern)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return NULL;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    return pattern->user_data;
+}
+
+void
+cairo_raster_source_pattern_set_acquire (cairo_pattern_t *abstract_pattern,
+					 cairo_raster_source_acquire_func_t acquire,
+					 cairo_raster_source_release_func_t release)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    pattern->acquire = acquire;
+    pattern->release = release;
+}
+
+void
+cairo_raster_source_pattern_get_acquire (cairo_pattern_t *abstract_pattern,
+					 cairo_raster_source_acquire_func_t *acquire,
+					 cairo_raster_source_release_func_t *release)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    if (acquire)
+	*acquire = pattern->acquire;
+    if (release)
+	*release = pattern->release;
+}
+
+void
+cairo_raster_source_pattern_set_snapshot (cairo_pattern_t *abstract_pattern,
+					  cairo_raster_source_snapshot_func_t snapshot)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    pattern->snapshot = snapshot;
+}
+
+cairo_raster_source_snapshot_func_t
+cairo_raster_source_pattern_get_snapshot (cairo_pattern_t *abstract_pattern)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return NULL;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    return pattern->snapshot;
+}
+
+void
+cairo_raster_source_pattern_set_copy (cairo_pattern_t *abstract_pattern,
+				      cairo_raster_source_copy_func_t copy)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    pattern->copy = copy;
+}
+
+cairo_raster_source_copy_func_t
+cairo_raster_source_pattern_get_copy (cairo_pattern_t *abstract_pattern)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return NULL;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    return pattern->copy;
+}
+
+void
+cairo_raster_source_pattern_set_finish (cairo_pattern_t *abstract_pattern,
+					cairo_raster_source_finish_func_t finish)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    pattern->finish = finish;
+}
+
+cairo_raster_source_finish_func_t
+cairo_raster_source_pattern_get_finish (cairo_pattern_t *abstract_pattern)
+{
+    cairo_raster_source_pattern_t *pattern;
+
+    if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return NULL;
+
+    pattern = (cairo_raster_source_pattern_t *) abstract_pattern;
+    return pattern->finish;
+}
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 811b015..29a6ae4 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -53,8 +53,9 @@
 #include "cairo-error-private.h"
 #include "cairo-list-private.h"
 #include "cairo-image-surface-private.h"
-#include "cairo-recording-surface-private.h"
 #include "cairo-output-stream-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-recording-surface-private.h"
 #include "cairo-scaled-font-private.h"
 #include "cairo-surface-clipper-private.h"
 #include "cairo-surface-snapshot-private.h"
@@ -1469,7 +1470,6 @@ _emit_image_surface (cairo_script_surface_t *surface,
 
 	_cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n");
     }
-    attach_snapshot (ctx, &image->base);
 
     return CAIRO_INT_STATUS_SUCCESS;
 }
@@ -1574,6 +1574,30 @@ _emit_surface_pattern (cairo_script_surface_t *surface,
 }
 
 static cairo_int_status_t
+_emit_raster_pattern (cairo_script_surface_t *surface,
+		      const cairo_pattern_t *pattern)
+{
+    cairo_surface_t *source;
+    cairo_int_status_t status;
+
+    source = _cairo_raster_source_pattern_acquire (pattern, &surface->base, NULL);
+    if (unlikely (source == NULL)) {
+	ASSERT_NOT_REACHED;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+    if (unlikely (source->status))
+	return source->status;
+
+    status = _emit_image_surface_pattern (surface, source);
+    _cairo_raster_source_pattern_release (pattern, source);
+    if (unlikely (status))
+	return status;
+
+    _cairo_output_stream_puts (to_context(surface)->stream, "pattern");
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
 _emit_pattern (cairo_script_surface_t *surface,
 	       const cairo_pattern_t *pattern)
 {
@@ -1603,6 +1627,10 @@ _emit_pattern (cairo_script_surface_t *surface,
 	status = _emit_surface_pattern (surface, pattern);
 	is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT;
 	break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	status = _emit_raster_pattern (surface, pattern);
+	is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT;
+	break;
 
     default:
 	ASSERT_NOT_REACHED;
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index ebb38b9..c70c0cc 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -184,6 +184,9 @@ classify_pattern (const cairo_pattern_t *pattern,
     case CAIRO_PATTERN_TYPE_MESH:
 	classify = 6;
 	break;
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	classify = 7;
+	break;
     }
     return classify;
 }
@@ -1687,7 +1690,8 @@ static const char *pattern_names[] = {
     "solid",
     "linear",
     "radial",
-    "mesh"
+    "mesh",
+    "raster"
 };
 static void
 print_pattern (cairo_output_stream_t *stream,
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 6f607d3..eab50c8 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -2035,6 +2035,7 @@ _cairo_svg_surface_emit_pattern (cairo_svg_surface_t   *surface,
 						       output, is_stroke, parent_matrix);
 
     case CAIRO_PATTERN_TYPE_MESH:
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
 	ASSERT_NOT_REACHED;
     }
     return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
index 447529d..c608c9a 100644
--- a/src/cairo-xcb-surface-core.c
+++ b/src/cairo-xcb-surface-core.c
@@ -485,6 +485,7 @@ _cairo_xcb_pixmap_for_pattern (cairo_xcb_surface_t *target,
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
     case CAIRO_PATTERN_TYPE_MESH:
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
 	return _render_to_pixmap (target, pattern, extents);
 
     default:
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 5bc8b09..662eb74 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1242,9 +1242,10 @@ _cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target,
 	return _cairo_xcb_surface_picture (target,
 					   (cairo_surface_pattern_t *) pattern,
 					   extents);
-    case CAIRO_PATTERN_TYPE_MESH:
     default:
 	ASSERT_NOT_REACHED;
+    case CAIRO_PATTERN_TYPE_MESH:
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
 	return _render_to_picture (target, pattern, extents);
     }
 }
diff --git a/src/cairo.h b/src/cairo.h
index 25c32c2..bc5abcf 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2260,8 +2260,7 @@ cairo_surface_status (cairo_surface_t *surface);
  * @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10
  * @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with
  *   cairo_surface_create_for_rectangle(), since 1.10
- * @CAIRO_SURFACE_TYPE_MIME: The surface is a callback (mime) surface, since 1.12
- * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl
+ * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12
  *
  * #cairo_surface_type_t is used to describe the type of a given
  * surface. The surface types are also known as "backends" or "surface
@@ -2312,7 +2311,6 @@ typedef enum _cairo_surface_type {
     CAIRO_SURFACE_TYPE_XML,
     CAIRO_SURFACE_TYPE_SKIA,
     CAIRO_SURFACE_TYPE_SUBSURFACE,
-    CAIRO_SURFACE_TYPE_MIME,
     CAIRO_SURFACE_TYPE_COGL
 } cairo_surface_type_t;
 
@@ -2472,55 +2470,73 @@ cairo_public cairo_bool_t
 cairo_recording_surface_get_extents (cairo_surface_t *surface,
 				     cairo_rectangle_t *extents);
 
-/* Mime-surface (callback) functions */
+/* raster-source pattern (callback) functions */
 
-typedef cairo_surface_t *(*cairo_mime_surface_acquire_t) (cairo_surface_t *mime_surface,
-							  void *callback_data,
-							  cairo_surface_t *target,
-							  const cairo_rectangle_int_t *sample_extents,
-							  cairo_rectangle_int_t *surface_extents);
+typedef cairo_surface_t *
+(*cairo_raster_source_acquire_func_t) (cairo_pattern_t *pattern,
+				       void *callback_data,
+				       cairo_surface_t *target,
+				       const cairo_rectangle_int_t *extents);
 
-typedef void (*cairo_mime_surface_release_t) (cairo_surface_t *mime_surface,
-					      void *callback_data,
-					      cairo_surface_t *image_surface);
+typedef void
+(*cairo_raster_source_release_func_t) (cairo_pattern_t *pattern,
+				       void *callback_data,
+				       cairo_surface_t *surface);
 
-typedef cairo_surface_t *(*cairo_mime_surface_snapshot_t) (cairo_surface_t *mime_surface,
-							   void *callback_data);
-typedef void (*cairo_mime_surface_destroy_t) (cairo_surface_t *mime_surface,
-					      void *callback_data);
+typedef cairo_status_t
+(*cairo_raster_source_snapshot_func_t) (cairo_pattern_t *pattern,
+					void *callback_data);
 
-cairo_public cairo_surface_t *
-cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height);
+typedef cairo_status_t
+(*cairo_raster_source_copy_func_t) (cairo_pattern_t *pattern,
+				    void *callback_data,
+				    const cairo_pattern_t *other);
+
+typedef void
+(*cairo_raster_source_finish_func_t) (cairo_pattern_t *pattern,
+				      void *callback_data);
+
+cairo_public cairo_pattern_t *
+cairo_pattern_create_raster_source (void *user_data,
+				    cairo_content_t content,
+				    int width, int height);
 
 cairo_public void
-cairo_mime_surface_set_callback_data (cairo_surface_t *surface,
-				      void *data);
+cairo_raster_source_pattern_set_callback_data (cairo_pattern_t *pattern,
+					       void *data);
 
 cairo_public void *
-cairo_mime_surface_get_callback_data (cairo_surface_t *surface);
+cairo_raster_source_pattern_get_callback_data (cairo_pattern_t *pattern);
 
 cairo_public void
-cairo_mime_surface_set_acquire (cairo_surface_t *surface,
-				cairo_mime_surface_acquire_t acquire,
-				cairo_mime_surface_release_t release);
+cairo_raster_source_pattern_set_acquire (cairo_pattern_t *pattern,
+					 cairo_raster_source_acquire_func_t acquire,
+					 cairo_raster_source_release_func_t release);
 
 cairo_public void
-cairo_mime_surface_get_acquire (cairo_surface_t *surface,
-				cairo_mime_surface_acquire_t *acquire,
-				cairo_mime_surface_release_t *release);
+cairo_raster_source_pattern_get_acquire (cairo_pattern_t *pattern,
+					 cairo_raster_source_acquire_func_t *acquire,
+					 cairo_raster_source_release_func_t *release);
+cairo_public void
+cairo_raster_source_pattern_set_snapshot (cairo_pattern_t *pattern,
+					  cairo_raster_source_snapshot_func_t snapshot);
+
+cairo_public cairo_raster_source_snapshot_func_t
+cairo_raster_source_pattern_get_snapshot (cairo_pattern_t *pattern);
+
 cairo_public void
-cairo_mime_surface_set_snapshot (cairo_surface_t *surface,
-				 cairo_mime_surface_snapshot_t snapshot);
+cairo_raster_source_pattern_set_copy (cairo_pattern_t *pattern,
+				      cairo_raster_source_copy_func_t copy);
 
-cairo_public cairo_mime_surface_snapshot_t
-cairo_mime_surface_get_snapshot (cairo_surface_t *surface);
+cairo_public cairo_raster_source_copy_func_t
+cairo_raster_source_pattern_get_copy (cairo_pattern_t *pattern);
 
 cairo_public void
-cairo_mime_surface_set_destroy (cairo_surface_t *surface,
-				cairo_mime_surface_destroy_t destroy);
+cairo_raster_source_pattern_set_finish (cairo_pattern_t *pattern,
+					cairo_raster_source_finish_func_t finish);
 
-cairo_public cairo_mime_surface_destroy_t
-cairo_mime_surface_get_destroy (cairo_surface_t *surface);
+cairo_public cairo_raster_source_finish_func_t
+cairo_raster_source_pattern_get_finish (cairo_pattern_t *pattern);
 
 /* Pattern creation functions */
 
@@ -2575,6 +2591,7 @@ cairo_pattern_set_user_data (cairo_pattern_t		 *pattern,
  * @CAIRO_PATTERN_TYPE_LINEAR: The pattern is a linear gradient.
  * @CAIRO_PATTERN_TYPE_RADIAL: The pattern is a radial gradient.
  * @CAIRO_PATTERN_TYPE_MESH: The pattern is a mesh.
+ * @CAIRO_PATTERN_TYPE_RASTER_SOURCE: The pattern is a user pattern providing raster data, since 1.12.
  *
  * #cairo_pattern_type_t is used to describe the type of a given pattern.
  *
@@ -2603,7 +2620,8 @@ typedef enum _cairo_pattern_type {
     CAIRO_PATTERN_TYPE_SURFACE,
     CAIRO_PATTERN_TYPE_LINEAR,
     CAIRO_PATTERN_TYPE_RADIAL,
-    CAIRO_PATTERN_TYPE_MESH
+    CAIRO_PATTERN_TYPE_MESH,
+    CAIRO_PATTERN_TYPE_RASTER_SOURCE
 } cairo_pattern_type_t;
 
 cairo_public cairo_pattern_type_t
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 8acc266..2d35666 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -203,7 +203,6 @@ test_sources = \
 	mesh-pattern-overlap.c		        	\
 	mesh-pattern-transformed.c		        \
 	mime-data.c					\
-	mime-surface.c					\
 	mime-surface-api.c				\
 	miter-precision.c				\
 	move-to-show-surface.c				\
@@ -247,6 +246,7 @@ test_sources = \
 	random-intersections-nonzero.c			\
 	random-intersections-curves-eo.c		\
 	random-intersections-curves-nz.c		\
+	raster-source.c					\
 	record.c					\
 	record-extend.c					\
 	record-mesh.c					\
diff --git a/test/mime-surface.c b/test/mime-surface.c
deleted file mode 100644
index d59112f..0000000
--- a/test/mime-surface.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright © 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Author: Chris Wilson <chris at chris-wilson.co.uk>
- */
-
-#include "cairo-test.h"
-
-#include <stdio.h>
-#include <errno.h>
-
-/* Basic test to exercise the new mime-surface callback. */
-
-#define WIDTH 200
-#define HEIGHT 80
-
-/* Lazy way of determining PNG dimensions... */
-static void
-png_dimensions (const char *filename,
-		cairo_content_t *content, int *width, int *height)
-{
-    cairo_surface_t *surface;
-
-    surface = cairo_image_surface_create_from_png (filename);
-    *content = cairo_surface_get_content (surface);
-    *width = cairo_image_surface_get_width (surface);
-    *height = cairo_image_surface_get_height (surface);
-    cairo_surface_destroy (surface);
-}
-
-static cairo_surface_t *
-png_acquire (cairo_surface_t *mime_surface, void *closure,
-	     cairo_surface_t *target, const cairo_rectangle_int_t *roi,
-	     cairo_rectangle_int_t *extents)
-{
-    cairo_surface_t *image;
-
-    image = cairo_image_surface_create_from_png (closure);
-    extents->x = extents->y = 0;
-    extents->width = cairo_image_surface_get_width (image);
-    extents->height = cairo_image_surface_get_height (image);
-    return image;
-}
-
-static cairo_surface_t *
-red_acquire (cairo_surface_t *mime_surface, void *closure,
-	     cairo_surface_t *target, const cairo_rectangle_int_t *roi,
-	     cairo_rectangle_int_t *extents)
-{
-    cairo_surface_t *image;
-    cairo_t *cr;
-
-    image = cairo_surface_create_similar_image (target,
-						CAIRO_FORMAT_RGB24,
-						roi->width, roi->height);
-    cr = cairo_create (image);
-    cairo_set_source_rgb (cr, 1, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
-
-    *extents = *roi;
-    return image;
-}
-
-static void
-release (cairo_surface_t *mime_surface, void *closure, cairo_surface_t *image)
-{
-    cairo_surface_destroy (image);
-}
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
-    const char *png_filename = "png.png";
-    cairo_surface_t *png, *red;
-    cairo_content_t content;
-    int png_width, png_height;
-    int i, j;
-
-    png_dimensions (png_filename, &content, &png_width, &png_height);
-
-    png = cairo_mime_surface_create ((void*)png_filename, content, png_width, png_height);
-    cairo_mime_surface_set_acquire (png, png_acquire, release);
-
-    red = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, WIDTH, HEIGHT);
-    cairo_mime_surface_set_acquire (red, red_acquire, release);
-
-    cairo_set_source_rgb (cr, 0, 0, 1);
-    cairo_paint (cr);
-
-    cairo_translate (cr, 0, (HEIGHT-png_height)/2);
-    for (i = 0; i < 4; i++) {
-	for (j = 0; j < 4; j++) {
-	    cairo_surface_t *source;
-	    if ((i ^ j) & 1)
-		source = red;
-	    else
-		source = png;
-	    cairo_set_source_surface (cr, source, 0, 0);
-	    cairo_rectangle (cr, i * WIDTH/4, j * png_height/4, WIDTH/4, png_height/4);
-	    cairo_fill (cr);
-	}
-    }
-
-    cairo_surface_destroy (red);
-    cairo_surface_destroy (png);
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-static cairo_test_status_t
-check_status (const cairo_test_context_t *ctx,
-	      cairo_status_t status,
-	      cairo_status_t expected)
-{
-    if (status == expected)
-	return CAIRO_TEST_SUCCESS;
-
-    cairo_test_log (ctx,
-		    "Error: Expected status value %d (%s), received %d (%s)\n",
-		    expected,
-		    cairo_status_to_string (expected),
-		    status,
-		    cairo_status_to_string (status));
-    return CAIRO_TEST_FAILURE;
-}
-
-static cairo_test_status_t
-preamble (cairo_test_context_t *ctx)
-{
-    cairo_surface_t *mime;
-    cairo_status_t status;
-    cairo_t *cr;
-
-    /* drawing to a mime-surface is verboten */
-
-    mime = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, 0, 0);
-    cr = cairo_create (mime);
-    cairo_surface_destroy (mime);
-    status = cairo_status (cr);
-    cairo_destroy (cr);
-    status = check_status (ctx, status, CAIRO_STATUS_WRITE_ERROR);
-    if (status)
-	return status;
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (mime_surface,
-	    "Check that the mime-surface embedding works",
-	    "api", /* keywords */
-	    NULL, /* requirements */
-	    WIDTH, HEIGHT,
-	    preamble, draw)
diff --git a/test/raster-source.c b/test/raster-source.c
new file mode 100644
index 0000000..5a7646e
--- /dev/null
+++ b/test/raster-source.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+/* Basic test to exercise the new mime-surface callback. */
+
+#define WIDTH 200
+#define HEIGHT 80
+
+/* Lazy way of determining PNG dimensions... */
+static void
+png_dimensions (const char *filename,
+		cairo_content_t *content, int *width, int *height)
+{
+    cairo_surface_t *surface;
+
+    surface = cairo_image_surface_create_from_png (filename);
+    *content = cairo_surface_get_content (surface);
+    *width = cairo_image_surface_get_width (surface);
+    *height = cairo_image_surface_get_height (surface);
+    cairo_surface_destroy (surface);
+}
+
+static cairo_surface_t *
+png_acquire (cairo_pattern_t *pattern, void *closure,
+	     cairo_surface_t *target,
+	     const cairo_rectangle_int_t *extents)
+{
+    return cairo_image_surface_create_from_png (closure);
+}
+
+static cairo_surface_t *
+red_acquire (cairo_pattern_t *pattern, void *closure,
+	     cairo_surface_t *target,
+	     const cairo_rectangle_int_t *extents)
+{
+    cairo_surface_t *image;
+    cairo_t *cr;
+
+    image = cairo_surface_create_similar_image (target,
+						CAIRO_FORMAT_RGB24,
+						extents->width,
+						extents->height);
+    cairo_surface_set_device_offset (image, extents->x, extents->y);
+
+    cr = cairo_create (image);
+    cairo_set_source_rgb (cr, 1, 0, 0);
+    cairo_paint (cr);
+    cairo_destroy (cr);
+
+    return image;
+}
+
+static void
+release (cairo_pattern_t *pattern, void *closure, cairo_surface_t *image)
+{
+    cairo_surface_destroy (image);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    const char *png_filename = "png.png";
+    cairo_pattern_t *png, *red;
+    cairo_content_t content;
+    int png_width, png_height;
+    int i, j;
+
+    png_dimensions (png_filename, &content, &png_width, &png_height);
+
+    png = cairo_pattern_create_raster_source ((void*)png_filename,
+					      content, png_width, png_height);
+    cairo_raster_source_pattern_set_acquire (png, png_acquire, release);
+
+    red = cairo_pattern_create_raster_source (NULL,
+					      CAIRO_CONTENT_COLOR, WIDTH, HEIGHT);
+    cairo_raster_source_pattern_set_acquire (red, red_acquire, release);
+
+    cairo_set_source_rgb (cr, 0, 0, 1);
+    cairo_paint (cr);
+
+    cairo_translate (cr, 0, (HEIGHT-png_height)/2);
+    for (i = 0; i < 4; i++) {
+	for (j = 0; j < 4; j++) {
+	    cairo_pattern_t *source;
+	    if ((i ^ j) & 1)
+		source = red;
+	    else
+		source = png;
+	    cairo_set_source (cr, source);
+	    cairo_rectangle (cr, i * WIDTH/4, j * png_height/4, WIDTH/4, png_height/4);
+	    cairo_fill (cr);
+	}
+    }
+
+    cairo_pattern_destroy (red);
+    cairo_pattern_destroy (png);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (raster_source,
+	    "Check that the mime-surface embedding works",
+	    "api", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, draw)
diff --git a/test/reference/mime-surface.base.argb32.ref.png b/test/reference/mime-surface.base.argb32.ref.png
deleted file mode 100644
index ac5e560..0000000
Binary files a/test/reference/mime-surface.base.argb32.ref.png and /dev/null differ
diff --git a/test/reference/mime-surface.base.rgb24.ref.png b/test/reference/mime-surface.base.rgb24.ref.png
deleted file mode 100644
index ac5e560..0000000
Binary files a/test/reference/mime-surface.base.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/mime-surface.ref.png b/test/reference/mime-surface.ref.png
deleted file mode 100644
index ac5e560..0000000
Binary files a/test/reference/mime-surface.ref.png and /dev/null differ
diff --git a/test/reference/mime-surface.traps.argb32.ref.png b/test/reference/mime-surface.traps.argb32.ref.png
deleted file mode 100644
index ac5e560..0000000
Binary files a/test/reference/mime-surface.traps.argb32.ref.png and /dev/null differ
diff --git a/test/reference/mime-surface.traps.rgb24.ref.png b/test/reference/mime-surface.traps.rgb24.ref.png
deleted file mode 100644
index ac5e560..0000000
Binary files a/test/reference/mime-surface.traps.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/raster-source.base.argb32.ref.png b/test/reference/raster-source.base.argb32.ref.png
new file mode 100644
index 0000000..ac5e560
Binary files /dev/null and b/test/reference/raster-source.base.argb32.ref.png differ
diff --git a/test/reference/raster-source.base.rgb24.ref.png b/test/reference/raster-source.base.rgb24.ref.png
new file mode 100644
index 0000000..ac5e560
Binary files /dev/null and b/test/reference/raster-source.base.rgb24.ref.png differ
diff --git a/test/reference/raster-source.ref.png b/test/reference/raster-source.ref.png
new file mode 100644
index 0000000..ac5e560
Binary files /dev/null and b/test/reference/raster-source.ref.png differ
diff --git a/test/reference/raster-source.traps.argb32.ref.png b/test/reference/raster-source.traps.argb32.ref.png
new file mode 100644
index 0000000..ac5e560
Binary files /dev/null and b/test/reference/raster-source.traps.argb32.ref.png differ
diff --git a/test/reference/raster-source.traps.rgb24.ref.png b/test/reference/raster-source.traps.rgb24.ref.png
new file mode 100644
index 0000000..ac5e560
Binary files /dev/null and b/test/reference/raster-source.traps.rgb24.ref.png differ
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 7475958..3c698a6 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -3511,24 +3511,24 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format,
     return ret;
 }
 
-cairo_surface_t *
-cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height)
+cairo_pattern_t *
+cairo_pattern_create_raster_source (void *data, cairo_content_t content, int width, int height)
 {
-    cairo_surface_t *ret;
+    cairo_pattern_t *ret;
 
     _enter_trace ();
 
-    ret = DLCALL (cairo_mime_surface_create, data, content, width, height);
+    ret = DLCALL (cairo_pattern_create_raster_source, data, content, width, height);
 
     _emit_line_info ();
     if (_write_lock ()) {
-	Object *obj = _create_surface (ret);
+	long pattern_id = _create_pattern_id (ret);
 	cairo_format_t format;
 	cairo_surface_t *image;
 	cairo_t *cr;
 
-	/* Impossible to accurately record the interaction with a mime-surface
-	 * so just suck all the data into an image upfront */
+	/* Impossible to accurately record the interaction with this custom
+	 * pattern so just suck all the data into an image upfront */
 	switch (content) {
 	case CAIRO_CONTENT_ALPHA: format = CAIRO_FORMAT_A8; break;
 	case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break;
@@ -3536,23 +3536,20 @@ cairo_mime_surface_create (void *data, cairo_content_t content, int width, int h
 	case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break;
 	}
 
-	_trace_printf ("%% mime-surface\n");
+	_trace_printf ("%% raster-source\n");
 
 	image = DLCALL (cairo_image_surface_create, format, width, height);
 	cr = DLCALL (cairo_create, image);
-	DLCALL (cairo_set_source_surface, cr, ret, 0, 0);
+	DLCALL (cairo_set_source, cr, ret);
 	DLCALL (cairo_paint, cr);
 	DLCALL (cairo_destroy, cr);
 
 	_emit_image (image, NULL);
 	DLCALL (cairo_surface_destroy, image);
-	_trace_printf (" dup /s%ld exch def\n",
-		       obj->token);
+	_trace_printf (" pattern dup /s%ld exch def\n",
+		       pattern_id);
 
-	obj->width = width;
-	obj->height = height;
-	obj->defined = TRUE;
-	_push_object (obj);
+	_push_operand (PATTERN, ret);
 	_write_unlock ();
     }
 


More information about the cairo-commit mailing list