Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-quartz-image-surface.c
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright � 2008 Mozilla 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 Mozilla Foundation.
32  *
33  * Contributor(s):
34  *      Vladimir Vukicevic <vladimir@mozilla.com>
35  */
36
37 #include "cairoint.h"
38
39 #include "cairo-image-surface-inline.h"
40 #include "cairo-quartz-image.h"
41 #include "cairo-quartz-private.h"
42 #include "cairo-surface-backend-private.h"
43
44 #include "cairo-error-private.h"
45 #include "cairo-default-context-private.h"
46
47 #define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
48 #define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH)))
49 #define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE)))
50 #define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
51
52 static void
53 DataProviderReleaseCallback (void *info, const void *data, size_t size)
54 {
55     cairo_surface_t *surface = (cairo_surface_t *) info;
56     cairo_surface_destroy (surface);
57 }
58
59 static cairo_surface_t *
60 _cairo_quartz_image_surface_create_similar (void *asurface,
61                                             cairo_content_t content,
62                                             int width,
63                                             int height)
64 {
65     cairo_surface_t *isurf =
66         _cairo_image_surface_create_with_content (content, width, height);
67     cairo_surface_t *result = cairo_quartz_image_surface_create (isurf);
68     cairo_surface_destroy (isurf);
69
70     return result;
71 }
72
73 static cairo_surface_t *
74 _cairo_quartz_image_surface_create_similar_image (void *asurface,
75                                                   cairo_format_t format,
76                                                   int width,
77                                                   int height)
78 {
79     cairo_surface_t *isurf = cairo_image_surface_create (format, width, height);
80     cairo_surface_t *result = cairo_quartz_image_surface_create (isurf);
81     cairo_surface_destroy (isurf);
82
83     return result;
84 }
85
86 static cairo_status_t
87 _cairo_quartz_image_surface_finish (void *asurface)
88 {
89     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
90
91     /* the imageSurface will be destroyed by the data provider's release callback */
92     CGImageRelease (surface->image);
93
94     return CAIRO_STATUS_SUCCESS;
95 }
96
97 static cairo_status_t
98 _cairo_quartz_image_surface_acquire_source_image (void *asurface,
99                                                   cairo_image_surface_t **image_out,
100                                                   void **image_extra)
101 {
102     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
103
104     *image_out = surface->imageSurface;
105     *image_extra = NULL;
106
107     return CAIRO_STATUS_SUCCESS;
108 }
109
110 static cairo_image_surface_t *
111 _cairo_quartz_image_surface_map_to_image (void *asurface,
112                                           const cairo_rectangle_int_t *extents)
113 {
114     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
115     return _cairo_surface_map_to_image (&surface->imageSurface->base, extents);
116 }
117
118 static cairo_int_status_t
119 _cairo_quartz_image_surface_unmap_image (void *asurface,
120                                          cairo_image_surface_t *image)
121 {
122     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
123     return _cairo_surface_unmap_image (&surface->imageSurface->base, image);
124 }
125
126 static cairo_bool_t
127 _cairo_quartz_image_surface_get_extents (void *asurface,
128                                          cairo_rectangle_int_t *extents)
129 {
130     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
131
132     extents->x = 0;
133     extents->y = 0;
134     extents->width  = surface->width;
135     extents->height = surface->height;
136     return TRUE;
137 }
138
139 /* we assume some drawing happened to the image buffer; make sure it's
140  * represented in the CGImage on flush()
141  */
142
143 static cairo_status_t
144 _cairo_quartz_image_surface_flush (void *asurface,
145                                    unsigned flags)
146 {
147     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
148     CGImageRef oldImage = surface->image;
149     CGImageRef newImage = NULL;
150
151     if (flags)
152         return CAIRO_STATUS_SUCCESS;
153
154     /* XXX only flush if the image has been modified. */
155
156     /* To be released by the ReleaseCallback */
157     cairo_surface_reference ((cairo_surface_t*) surface->imageSurface);
158
159     newImage = CairoQuartzCreateCGImage (surface->imageSurface->format,
160                                          surface->imageSurface->width,
161                                          surface->imageSurface->height,
162                                          surface->imageSurface->stride,
163                                          surface->imageSurface->data,
164                                          TRUE,
165                                          NULL,
166                                          DataProviderReleaseCallback,
167                                          surface->imageSurface);
168
169     surface->image = newImage;
170     CGImageRelease (oldImage);
171
172     return CAIRO_STATUS_SUCCESS;
173 }
174
175 static cairo_int_status_t
176 _cairo_quartz_image_surface_paint (void                 *abstract_surface,
177                                    cairo_operator_t              op,
178                                    const cairo_pattern_t        *source,
179                                    const cairo_clip_t           *clip)
180 {
181     cairo_quartz_image_surface_t *surface = abstract_surface;
182     return _cairo_surface_paint (&surface->imageSurface->base,
183                                  op, source, clip);
184 }
185
186 static cairo_int_status_t
187 _cairo_quartz_image_surface_mask (void                          *abstract_surface,
188                                   cairo_operator_t               op,
189                                   const cairo_pattern_t         *source,
190                                   const cairo_pattern_t         *mask,
191                                   const cairo_clip_t            *clip)
192 {
193     cairo_quartz_image_surface_t *surface = abstract_surface;
194     return _cairo_surface_mask (&surface->imageSurface->base,
195                                 op, source, mask, clip);
196 }
197
198 static cairo_int_status_t
199 _cairo_quartz_image_surface_stroke (void                        *abstract_surface,
200                                     cairo_operator_t             op,
201                                     const cairo_pattern_t       *source,
202                                     const cairo_path_fixed_t    *path,
203                                     const cairo_stroke_style_t  *style,
204                                     const cairo_matrix_t        *ctm,
205                                     const cairo_matrix_t        *ctm_inverse,
206                                     double                       tolerance,
207                                     cairo_antialias_t            antialias,
208                                     const cairo_clip_t          *clip)
209 {
210     cairo_quartz_image_surface_t *surface = abstract_surface;
211     return _cairo_surface_stroke (&surface->imageSurface->base,
212                                   op, source, path,
213                                   style, ctm, ctm_inverse,
214                                   tolerance, antialias, clip);
215 }
216
217 static cairo_int_status_t
218 _cairo_quartz_image_surface_fill (void                          *abstract_surface,
219                            cairo_operator_t              op,
220                            const cairo_pattern_t        *source,
221                            const cairo_path_fixed_t     *path,
222                            cairo_fill_rule_t             fill_rule,
223                            double                        tolerance,
224                            cairo_antialias_t             antialias,
225                            const cairo_clip_t           *clip)
226 {
227     cairo_quartz_image_surface_t *surface = abstract_surface;
228     return _cairo_surface_fill (&surface->imageSurface->base,
229                                 op, source, path,
230                                 fill_rule, tolerance, antialias,
231                                 clip);
232 }
233
234 static cairo_int_status_t
235 _cairo_quartz_image_surface_glyphs (void                        *abstract_surface,
236                                     cairo_operator_t             op,
237                                     const cairo_pattern_t       *source,
238                                     cairo_glyph_t               *glyphs,
239                                     int                          num_glyphs,
240                                     cairo_scaled_font_t         *scaled_font,
241                                     const cairo_clip_t          *clip)
242 {
243     cairo_quartz_image_surface_t *surface = abstract_surface;
244     return _cairo_surface_show_text_glyphs (&surface->imageSurface->base,
245                                             op, source,
246                                             NULL, 0,
247                                             glyphs, num_glyphs,
248                                             NULL, 0, 0,
249                                             scaled_font, clip);
250 }
251
252
253 static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
254     CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
255     _cairo_quartz_image_surface_finish,
256
257     _cairo_default_context_create,
258
259     _cairo_quartz_image_surface_create_similar,
260     _cairo_quartz_image_surface_create_similar_image,
261     _cairo_quartz_image_surface_map_to_image,
262     _cairo_quartz_image_surface_unmap_image,
263
264     _cairo_surface_default_source,
265     _cairo_quartz_image_surface_acquire_source_image,
266     NULL, /* release_source_image */
267     NULL, /* snapshot */
268
269     NULL, /* copy_page */
270     NULL, /* show_page */
271
272     _cairo_quartz_image_surface_get_extents,
273     NULL, /* get_font_options */
274
275     _cairo_quartz_image_surface_flush,
276     NULL, /* mark_dirty_rectangle */
277
278     _cairo_quartz_image_surface_paint,
279     _cairo_quartz_image_surface_mask,
280     _cairo_quartz_image_surface_stroke,
281     _cairo_quartz_image_surface_fill,
282     NULL,  /* fill-stroke */
283     _cairo_quartz_image_surface_glyphs,
284 };
285
286 /**
287  * cairo_quartz_image_surface_create:
288  * @image_surface: a cairo image surface to wrap with a quartz image surface
289  *
290  * Creates a Quartz surface backed by a CGImageRef that references the
291  * given image surface. The resulting surface can be rendered quickly
292  * when used as a source when rendering to a #cairo_quartz_surface.  If
293  * the data in the image surface is ever updated, cairo_surface_flush()
294  * must be called on the #cairo_quartz_image_surface to ensure that the
295  * CGImageRef refers to the updated data.
296  *
297  * Return value: the newly created surface.
298  *
299  * Since: 1.6
300  **/
301 cairo_surface_t *
302 cairo_quartz_image_surface_create (cairo_surface_t *surface)
303 {
304     cairo_quartz_image_surface_t *qisurf;
305
306     CGImageRef image;
307
308     cairo_image_surface_t *image_surface;
309     int width, height, stride;
310     cairo_format_t format;
311     unsigned char *data;
312
313     if (surface->status)
314         return surface;
315
316     if (! _cairo_surface_is_image (surface))
317         return SURFACE_ERROR_TYPE_MISMATCH;
318
319     image_surface = (cairo_image_surface_t*) surface;
320     width = image_surface->width;
321     height = image_surface->height;
322     stride = image_surface->stride;
323     format = image_surface->format;
324     data = image_surface->data;
325
326     if (!_cairo_quartz_verify_surface_size(width, height))
327         return SURFACE_ERROR_INVALID_SIZE;
328
329     if (width == 0 || height == 0)
330         return SURFACE_ERROR_INVALID_SIZE;
331
332     if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24)
333         return SURFACE_ERROR_INVALID_FORMAT;
334
335     qisurf = malloc(sizeof(cairo_quartz_image_surface_t));
336     if (qisurf == NULL)
337         return SURFACE_ERROR_NO_MEMORY;
338
339     memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
340
341     /* In case the create_cgimage fails, this ref will
342      * be released via the callback (which will be called in
343      * case of failure.)
344      */
345     cairo_surface_reference (surface);
346
347     image = CairoQuartzCreateCGImage (format,
348                                       width, height,
349                                       stride,
350                                       data,
351                                       TRUE,
352                                       NULL,
353                                       DataProviderReleaseCallback,
354                                       image_surface);
355
356     if (!image) {
357         free (qisurf);
358         return SURFACE_ERROR_NO_MEMORY;
359     }
360
361     _cairo_surface_init (&qisurf->base,
362                          &cairo_quartz_image_surface_backend,
363                          NULL, /* device */
364                          _cairo_content_from_format (format));
365
366     qisurf->width = width;
367     qisurf->height = height;
368
369     qisurf->image = image;
370     qisurf->imageSurface = image_surface;
371
372     return &qisurf->base;
373 }
374
375
376 cairo_surface_t *
377 cairo_quartz_image_surface_get_image (cairo_surface_t *asurface)
378 {
379     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface;
380
381     if (asurface->type != CAIRO_SURFACE_TYPE_QUARTZ_IMAGE)
382         return NULL;
383
384     return (cairo_surface_t*) surface->imageSurface;
385 }