Upload Tizen2.0 source
[framework/graphics/cairo.git] / src / cairo-mime-surface.c
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 © 2011 Intel Corporation
5  *
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.
13  *
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
19  *
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/
24  *
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.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Red Hat, Inc.
32  *
33  * Contributor(s):
34  *      Chris Wilson <chris@chris-wilson.co.uk>
35  */
36
37 /**
38  * SECTION:cairo-mime-surface
39  * @Title: Callback Surfaces
40  * @Short_Description: Allows the user to provide a callback to supply image
41  * data upon demand
42  * @See_Also: #cairo_surface_t
43  *
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
51  * data.
52  *
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.
59  *
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).
72  *
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.
86  */
87
88 /**
89  * CAIRO_HAS_MIME_SURFACE:
90  *
91  * Defined if the mime surface backend is available.
92  * The mime surface backend is always built in.
93  *
94  * @Since: 1.12
95  */
96
97 #include "cairoint.h"
98 #include "cairo-error-private.h"
99 #include "cairo-image-surface-private.h"
100 #include "cairo-surface-backend-private.h"
101
102 typedef struct _cairo_mime_surface {
103     cairo_surface_t base;
104
105     cairo_rectangle_int_t extents;
106
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;
111
112     /* an explicit pre-allocated member in preference to the general user-data */
113     void *user_data;
114 } cairo_mime_surface_t;
115
116 static cairo_status_t
117 _cairo_mime_surface_finish (void *abstract_surface)
118 {
119     cairo_mime_surface_t *surface = abstract_surface;
120
121     if (surface->destroy)
122         surface->destroy (&surface->base, surface->user_data);
123
124     return CAIRO_STATUS_SUCCESS;
125 }
126
127 static cairo_bool_t
128 _cairo_mime_surface_get_extents (void                     *abstract_surface,
129                                  cairo_rectangle_int_t   *rectangle)
130 {
131     cairo_mime_surface_t *surface = abstract_surface;
132
133     *rectangle = surface->extents;
134     return TRUE;
135 }
136
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,
141                                           void                   **image_extra)
142 {
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;
147
148     if (mime->acquire == NULL)
149         return CAIRO_INT_STATUS_UNSUPPORTED;
150
151     /* Force the callee to populate the extents rectangle */
152     memset (&extents, 0, sizeof (extents));
153
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);
159
160     if (acquired == NULL)
161         return CAIRO_INT_STATUS_UNSUPPORTED;
162
163     /* The callee must have supplied us with all the image data */
164     assert (extents.width == mime->extents.width && extents.height == mime->extents.height);
165
166     if (! _cairo_surface_is_image (acquired)) {
167         cairo_status_t status;
168         void *extra = NULL;
169
170         status = _cairo_surface_acquire_source_image (acquired, image_out, &extra);
171         if (unlikely (status)) {
172             cairo_surface_destroy (acquired);
173             return status;
174         }
175
176         assert (extra == NULL);
177         *image_extra = acquired;
178     } else {
179         *image_out = (cairo_image_surface_t *) acquired;
180         *image_extra = NULL;
181     }
182     return CAIRO_STATUS_SUCCESS;
183 }
184
185 static void
186 _cairo_mime_surface_release_source_image (void                   *abstract_surface,
187                                           cairo_image_surface_t  *image,
188                                           void                   *image_extra)
189 {
190     cairo_mime_surface_t *mime = abstract_surface;
191
192     if (image_extra) {
193         cairo_surface_destroy (&image->base);
194         image = image_extra;
195     }
196
197     if (mime->release)
198         mime->release (&mime->base, mime->user_data, &image->base);
199 }
200
201 static cairo_surface_t *
202 _cairo_mime_surface_snapshot (void *abstract_surface)
203 {
204     cairo_mime_surface_t *mime = abstract_surface;
205
206     if (mime->snapshot == NULL)
207         return NULL;
208
209     return mime->snapshot (&mime->base, mime->user_data);
210 }
211
212 static const cairo_surface_backend_t cairo_mime_surface_backend = {
213     CAIRO_SURFACE_TYPE_MIME,
214     _cairo_mime_surface_finish,
215
216     NULL, /* Read-only */
217
218     NULL, /* create similar */
219     NULL, /* create similar image */
220     NULL, /* map to image */
221     NULL, /* unmap image */
222
223     _cairo_mime_surface_acquire_source_image,
224     _cairo_mime_surface_release_source_image,
225     _cairo_mime_surface_snapshot,
226
227     NULL, /* copy_page */
228     NULL, /* show_page */
229
230     _cairo_mime_surface_get_extents,
231     NULL, /* get_font_options */
232
233     NULL, /* flush */
234     NULL, /* mark_dirty_rectangle */
235
236     NULL, /* scaled_font_fini */
237     NULL, /* scaled_glyph_fini */
238
239     NULL, /* paint */
240     NULL, /* mask */
241     NULL, /* stroke */
242     NULL, /* fill */
243     NULL, /* glyphs */
244 };
245
246 cairo_surface_t *
247 cairo_mime_surface_create (void *data, cairo_content_t content, int width, int height)
248 {
249     cairo_mime_surface_t *surface;
250
251     if (width < 0 || height < 0)
252         return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
253
254     if (! CAIRO_CONTENT_VALID (content))
255         return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
256
257     surface = calloc (1, sizeof (*surface));
258     if (unlikely (surface == NULL))
259         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
260
261     _cairo_surface_init (&surface->base,
262                          &cairo_mime_surface_backend,
263                          NULL, /* device */
264                          content);
265
266     surface->extents.x = 0;
267     surface->extents.y = 0;
268     surface->extents.width  = width;
269     surface->extents.height = height;
270
271     surface->user_data = data;
272
273     return &surface->base;
274 }
275
276 void
277 cairo_mime_surface_set_callback_data (cairo_surface_t *surface,
278                                       void *data)
279 {
280     cairo_mime_surface_t *mime;
281
282     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
283         return;
284
285     if (surface->backend != &cairo_mime_surface_backend)
286         return;
287
288     mime = (cairo_mime_surface_t *)surface;
289     mime->user_data = data;
290 }
291
292 void *
293 cairo_mime_surface_get_callback_data (cairo_surface_t *surface)
294 {
295     cairo_mime_surface_t *mime;
296
297     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
298         return NULL;
299
300     if (surface->backend != &cairo_mime_surface_backend)
301         return NULL;
302
303     mime = (cairo_mime_surface_t *)surface;
304     return mime->user_data;
305 }
306
307 void
308 cairo_mime_surface_set_acquire (cairo_surface_t *surface,
309                                 cairo_mime_surface_acquire_t acquire,
310                                 cairo_mime_surface_release_t release)
311 {
312     cairo_mime_surface_t *mime;
313
314     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
315         return;
316
317     if (surface->backend != &cairo_mime_surface_backend)
318         return;
319
320     mime = (cairo_mime_surface_t *)surface;
321     mime->acquire = acquire;
322     mime->release = release;
323 }
324
325 void
326 cairo_mime_surface_get_acquire (cairo_surface_t *surface,
327                                 cairo_mime_surface_acquire_t *acquire,
328                                 cairo_mime_surface_release_t *release)
329 {
330     cairo_mime_surface_t *mime;
331
332     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
333         return;
334
335     if (surface->backend != &cairo_mime_surface_backend)
336         return;
337
338     mime = (cairo_mime_surface_t *)surface;
339     if (acquire)
340         *acquire = mime->acquire;
341     if (release)
342         *release = mime->release;
343 }
344
345 void
346 cairo_mime_surface_set_snapshot (cairo_surface_t *surface,
347                                  cairo_mime_surface_snapshot_t snapshot)
348 {
349     cairo_mime_surface_t *mime;
350
351     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
352         return;
353
354     if (surface->backend != &cairo_mime_surface_backend)
355         return;
356
357     mime = (cairo_mime_surface_t *)surface;
358     mime->snapshot = snapshot;
359 }
360
361 cairo_mime_surface_snapshot_t
362 cairo_mime_surface_get_snapshot (cairo_surface_t *surface)
363 {
364     cairo_mime_surface_t *mime;
365
366     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
367         return NULL;
368
369     if (surface->backend != &cairo_mime_surface_backend)
370         return NULL;
371
372     mime = (cairo_mime_surface_t *)surface;
373     return mime->snapshot;
374 }
375
376 void
377 cairo_mime_surface_set_destroy (cairo_surface_t *surface,
378                                 cairo_mime_surface_destroy_t destroy)
379 {
380     cairo_mime_surface_t *mime;
381
382     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
383         return;
384
385     if (surface->backend != &cairo_mime_surface_backend)
386         return;
387
388     mime = (cairo_mime_surface_t *)surface;
389     mime->destroy = destroy;
390 }
391
392 cairo_mime_surface_destroy_t
393 cairo_mime_surface_get_destroy (cairo_surface_t *surface)
394 {
395     cairo_mime_surface_t *mime;
396
397     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
398         return NULL;
399
400     if (surface->backend != &cairo_mime_surface_backend)
401         return NULL;
402
403     mime = (cairo_mime_surface_t *)surface;
404     return mime->destroy;
405 }