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
4 * Copyright © 2011 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Red Hat, Inc.
34 * Chris Wilson <chris@chris-wilson.co.uk>
38 * SECTION:cairo-mime-surface
39 * @Title: Callback Surfaces
40 * @Short_Description: Allows the user to provide a callback to supply image
42 * @See_Also: #cairo_surface_t
44 * The mime surfaces provide the ability to render from arbitrary sources
45 * not necessarily resident nor immediately usable by Cairo. The user is
46 * given the ability to insert a placeholder surface which can be used
47 * with a pattern and then later supply the actual pixel data upon demand.
48 * This deferred source is given both the sample region for the operation
49 * along with the destination surface such that they may be taken into
50 * account when creating the actual surface to use as the source of pixel
53 * The reason why it is called the mime surface is two-fold. First it came
54 * about as an extension of the mime-data property to handle deferred
55 * image decoding when rendering to pixel buffers (as opposed to the pass-
56 * through support in PDF and friends.) And then to further rationalise
57 * the name, it is a surface that mimics a real source without ever
58 * holding onto to any pixels of its own - a mime surface.
60 * The mime-surface callback interface consists of 4 functions. The principal
61 * pair are the acquire/release callbacks which are called when pixel data
62 * is required for an operation (along with the target surface and the sample
63 * extents). The callee must supply a surface that covers the sample area and
64 * set the actual extents of the returned surface in the output rectangle
65 * parameter. The surface does not necessarily have to be an image surface,
66 * but it is expected that an image surface is likely to be the most
67 * convenient for uploading pixel data. (Use
68 * cairo_surface_create_similar_image() to create an image surface that is
69 * optimised for uploading to the target.) The release callback is
70 * subsequently called when the returned surface is no longer needed (before
71 * the operation completes, within the lifetime of the source).
73 * The other pair of functions are to aide with lifetime management of the
74 * surface with respect to patterns and other users. The destroy callback
75 * allows for the caller to cleanup the associated data when the last
76 * reference to surface is destroyed. The snapshot callback is triggered
77 * when there is an immutable surface pattern referencing the mime-surface
78 * and the mime-surface will be be invalidated. (Since the mime-surface is
79 * read-only and a reference will be held by the pattern, this can only be
80 * triggered through an explicit cairo_surface_finish().) In this
81 * circumstance, we need to clone the source in order to preserve the pixel
82 * data for later use (i.e. we have recorded the pattern). The snapshot
83 * callback provides an interface for the caller to clone the mime-surface
84 * in an efficient manner. The returned surface may be of any type so long
85 * as it holds all pixel data and remains accessible.
89 * CAIRO_HAS_MIME_SURFACE:
91 * Defined if the mime surface backend is available.
92 * The mime surface backend is always built in.
98 #include "cairo-error-private.h"
99 #include "cairo-image-surface-private.h"
100 #include "cairo-surface-backend-private.h"
102 typedef struct _cairo_mime_surface {
103 cairo_surface_t base;
105 cairo_rectangle_int_t extents;
107 cairo_mime_surface_acquire_t acquire;
108 cairo_mime_surface_release_t release;
109 cairo_mime_surface_snapshot_t snapshot;
110 cairo_mime_surface_destroy_t destroy;
112 /* an explicit pre-allocated member in preference to the general user-data */
114 } cairo_mime_surface_t;
116 static cairo_status_t
117 _cairo_mime_surface_finish (void *abstract_surface)
119 cairo_mime_surface_t *surface = abstract_surface;
121 if (surface->destroy)
122 surface->destroy (&surface->base, surface->user_data);
124 return CAIRO_STATUS_SUCCESS;
128 _cairo_mime_surface_get_extents (void *abstract_surface,
129 cairo_rectangle_int_t *rectangle)
131 cairo_mime_surface_t *surface = abstract_surface;
133 *rectangle = surface->extents;
137 static cairo_status_t
138 _cairo_mime_surface_acquire_source_image (void *abstract_surface,
139 //cairo_surface_t *target,
140 cairo_image_surface_t **image_out,
143 cairo_mime_surface_t *mime = abstract_surface;
144 cairo_surface_t *acquired;
145 cairo_surface_t *dummy_target;
146 cairo_rectangle_int_t extents;
148 if (mime->acquire == NULL)
149 return CAIRO_INT_STATUS_UNSUPPORTED;
151 /* Force the callee to populate the extents rectangle */
152 memset (&extents, 0, sizeof (extents));
154 /* Masquerade for a flexible user-interface */
155 dummy_target = _cairo_image_surface_create_with_content (mime->base.content, 0, 0);
156 acquired = mime->acquire (&mime->base, mime->user_data,
157 dummy_target, &mime->extents, &extents);
158 cairo_surface_destroy (dummy_target);
160 if (acquired == NULL)
161 return CAIRO_INT_STATUS_UNSUPPORTED;
163 /* The callee must have supplied us with all the image data */
164 assert (extents.width == mime->extents.width && extents.height == mime->extents.height);
166 if (! _cairo_surface_is_image (acquired)) {
167 cairo_status_t status;
170 status = _cairo_surface_acquire_source_image (acquired, image_out, &extra);
171 if (unlikely (status)) {
172 cairo_surface_destroy (acquired);
176 assert (extra == NULL);
177 *image_extra = acquired;
179 *image_out = (cairo_image_surface_t *) acquired;
182 return CAIRO_STATUS_SUCCESS;
186 _cairo_mime_surface_release_source_image (void *abstract_surface,
187 cairo_image_surface_t *image,
190 cairo_mime_surface_t *mime = abstract_surface;
193 cairo_surface_destroy (&image->base);
198 mime->release (&mime->base, mime->user_data, &image->base);
201 static cairo_surface_t *
202 _cairo_mime_surface_snapshot (void *abstract_surface)
204 cairo_mime_surface_t *mime = abstract_surface;
206 if (mime->snapshot == NULL)
209 return mime->snapshot (&mime->base, mime->user_data);
212 static const cairo_surface_backend_t cairo_mime_surface_backend = {
213 CAIRO_SURFACE_TYPE_MIME,
214 _cairo_mime_surface_finish,
216 NULL, /* Read-only */
218 NULL, /* create similar */
219 NULL, /* create similar image */
220 NULL, /* map to image */
221 NULL, /* unmap image */
223 _cairo_mime_surface_acquire_source_image,
224 _cairo_mime_surface_release_source_image,
225 _cairo_mime_surface_snapshot,
227 NULL, /* copy_page */
228 NULL, /* show_page */
230 _cairo_mime_surface_get_extents,
231 NULL, /* get_font_options */
234 NULL, /* mark_dirty_rectangle */
236 NULL, /* scaled_font_fini */
237 NULL, /* scaled_glyph_fini */
247 cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height)
249 cairo_mime_surface_t *surface;
251 if (width < 0 || height < 0)
252 return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
254 if (! CAIRO_CONTENT_VALID (content))
255 return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
257 surface = calloc (1, sizeof (*surface));
258 if (unlikely (surface == NULL))
259 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
261 _cairo_surface_init (&surface->base,
262 &cairo_mime_surface_backend,
266 surface->extents.x = 0;
267 surface->extents.y = 0;
268 surface->extents.width = width;
269 surface->extents.height = height;
271 surface->user_data = data;
273 return &surface->base;
277 cairo_mime_surface_set_callback_data (cairo_surface_t *surface,
280 cairo_mime_surface_t *mime;
282 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
285 if (surface->backend != &cairo_mime_surface_backend)
288 mime = (cairo_mime_surface_t *)surface;
289 mime->user_data = data;
293 cairo_mime_surface_get_callback_data (cairo_surface_t *surface)
295 cairo_mime_surface_t *mime;
297 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
300 if (surface->backend != &cairo_mime_surface_backend)
303 mime = (cairo_mime_surface_t *)surface;
304 return mime->user_data;
308 cairo_mime_surface_set_acquire (cairo_surface_t *surface,
309 cairo_mime_surface_acquire_t acquire,
310 cairo_mime_surface_release_t release)
312 cairo_mime_surface_t *mime;
314 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
317 if (surface->backend != &cairo_mime_surface_backend)
320 mime = (cairo_mime_surface_t *)surface;
321 mime->acquire = acquire;
322 mime->release = release;
326 cairo_mime_surface_get_acquire (cairo_surface_t *surface,
327 cairo_mime_surface_acquire_t *acquire,
328 cairo_mime_surface_release_t *release)
330 cairo_mime_surface_t *mime;
332 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
335 if (surface->backend != &cairo_mime_surface_backend)
338 mime = (cairo_mime_surface_t *)surface;
340 *acquire = mime->acquire;
342 *release = mime->release;
346 cairo_mime_surface_set_snapshot (cairo_surface_t *surface,
347 cairo_mime_surface_snapshot_t snapshot)
349 cairo_mime_surface_t *mime;
351 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
354 if (surface->backend != &cairo_mime_surface_backend)
357 mime = (cairo_mime_surface_t *)surface;
358 mime->snapshot = snapshot;
361 cairo_mime_surface_snapshot_t
362 cairo_mime_surface_get_snapshot (cairo_surface_t *surface)
364 cairo_mime_surface_t *mime;
366 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
369 if (surface->backend != &cairo_mime_surface_backend)
372 mime = (cairo_mime_surface_t *)surface;
373 return mime->snapshot;
377 cairo_mime_surface_set_destroy (cairo_surface_t *surface,
378 cairo_mime_surface_destroy_t destroy)
380 cairo_mime_surface_t *mime;
382 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
385 if (surface->backend != &cairo_mime_surface_backend)
388 mime = (cairo_mime_surface_t *)surface;
389 mime->destroy = destroy;
392 cairo_mime_surface_destroy_t
393 cairo_mime_surface_get_destroy (cairo_surface_t *surface)
395 cairo_mime_surface_t *mime;
397 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
400 if (surface->backend != &cairo_mime_surface_backend)
403 mime = (cairo_mime_surface_t *)surface;
404 return mime->destroy;