763ce9669e644e5fcd2b03e23de0061701739c06
[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-private.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_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
116     return cairo_surface_map_to_image (&surface->imageSurface->base, extents);
117 }
118
119 static cairo_int_status_t
120 _cairo_quartz_image_surface_unmap_image (void *asurface,
121                                          cairo_image_surface_t *image)
122 {
123     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
124
125     cairo_surface_unmap_image (&surface->imageSurface->base, &image->base);
126     return cairo_surface_status (&surface->imageSurface->base);
127 }
128
129 static cairo_bool_t
130 _cairo_quartz_image_surface_get_extents (void *asurface,
131                                          cairo_rectangle_int_t *extents)
132 {
133     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
134
135     extents->x = 0;
136     extents->y = 0;
137     extents->width  = surface->width;
138     extents->height = surface->height;
139     return TRUE;
140 }
141
142 /* we assume some drawing happened to the image buffer; make sure it's
143  * represented in the CGImage on flush()
144  */
145
146 static cairo_status_t
147 _cairo_quartz_image_surface_flush (void *asurface)
148 {
149     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
150     CGImageRef oldImage = surface->image;
151     CGImageRef newImage = NULL;
152
153     /* XXX only flush if the image has been modified. */
154
155     /* To be released by the ReleaseCallback */
156     cairo_surface_reference ((cairo_surface_t*) surface->imageSurface);
157
158     newImage = CairoQuartzCreateCGImage (surface->imageSurface->format,
159                                          surface->imageSurface->width,
160                                          surface->imageSurface->height,
161                                          surface->imageSurface->stride,
162                                          surface->imageSurface->data,
163                                          TRUE,
164                                          NULL,
165                                          DataProviderReleaseCallback,
166                                          surface->imageSurface);
167
168     surface->image = newImage;
169     CGImageRelease (oldImage);
170
171     return CAIRO_STATUS_SUCCESS;
172 }
173
174 static cairo_int_status_t
175 _cairo_quartz_image_surface_paint (void                 *abstract_surface,
176                                    cairo_operator_t              op,
177                                    const cairo_pattern_t        *source,
178                                    const cairo_clip_t           *clip)
179 {
180     cairo_quartz_image_surface_t *surface = abstract_surface;
181     return _cairo_surface_paint (&surface->imageSurface->base,
182                                  op, source, clip);
183 }
184
185 static cairo_int_status_t
186 _cairo_quartz_image_surface_mask (void                          *abstract_surface,
187                                   cairo_operator_t               op,
188                                   const cairo_pattern_t         *source,
189                                   const cairo_pattern_t         *mask,
190                                   const cairo_clip_t            *clip)
191 {
192     cairo_quartz_image_surface_t *surface = abstract_surface;
193     return _cairo_surface_mask (&surface->imageSurface->base,
194                                 op, source, mask, clip);
195 }
196
197 static cairo_int_status_t
198 _cairo_quartz_image_surface_stroke (void                        *abstract_surface,
199                                     cairo_operator_t             op,
200                                     const cairo_pattern_t       *source,
201                                     const cairo_path_fixed_t    *path,
202                                     const cairo_stroke_style_t  *style,
203                                     const cairo_matrix_t        *ctm,
204                                     const cairo_matrix_t        *ctm_inverse,
205                                     double                       tolerance,
206                                     cairo_antialias_t            antialias,
207                                     const cairo_clip_t          *clip)
208 {
209     cairo_quartz_image_surface_t *surface = abstract_surface;
210     return _cairo_surface_stroke (&surface->imageSurface->base,
211                                   op, source, path,
212                                   style, ctm, ctm_inverse,
213                                   tolerance, antialias, clip);
214 }
215
216 static cairo_int_status_t
217 _cairo_quartz_image_surface_fill (void                          *abstract_surface,
218                            cairo_operator_t              op,
219                            const cairo_pattern_t        *source,
220                            const cairo_path_fixed_t     *path,
221                            cairo_fill_rule_t             fill_rule,
222                            double                        tolerance,
223                            cairo_antialias_t             antialias,
224                            const cairo_clip_t           *clip)
225 {
226     cairo_quartz_image_surface_t *surface = abstract_surface;
227     return _cairo_surface_fill (&surface->imageSurface->base,
228                                 op, source, path,
229                                 fill_rule, tolerance, antialias,
230                                 clip);
231 }
232
233 static cairo_int_status_t
234 _cairo_quartz_image_surface_glyphs (void                        *abstract_surface,
235                                     cairo_operator_t             op,
236                                     const cairo_pattern_t       *source,
237                                     cairo_glyph_t               *glyphs,
238                                     int                          num_glyphs,
239                                     cairo_scaled_font_t         *scaled_font,
240                                     const cairo_clip_t          *clip)
241 {
242     cairo_quartz_image_surface_t *surface = abstract_surface;
243     return _cairo_surface_show_text_glyphs (&surface->imageSurface->base,
244                                             op, source,
245                                             NULL, 0,
246                                             glyphs, num_glyphs,
247                                             NULL, 0, 0,
248                                             scaled_font, clip);
249 }
250
251
252 static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
253     CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
254     _cairo_quartz_image_surface_finish,
255
256     _cairo_default_context_create,
257
258     _cairo_quartz_image_surface_create_similar,
259     _cairo_quartz_image_surface_create_similar_image,
260     _cairo_quartz_image_surface_map_to_image,
261     _cairo_quartz_image_surface_unmap_image,
262
263     _cairo_surface_default_source,
264     _cairo_quartz_image_surface_acquire_source_image,
265     NULL, /* release_source_image */
266     NULL, /* snapshot */
267
268     NULL, /* copy_page */
269     NULL, /* show_page */
270
271     _cairo_quartz_image_surface_get_extents,
272     NULL, /* get_font_options */
273
274     _cairo_quartz_image_surface_flush,
275     NULL, /* mark_dirty_rectangle */
276
277     _cairo_quartz_image_surface_paint,
278     _cairo_quartz_image_surface_mask,
279     _cairo_quartz_image_surface_stroke,
280     _cairo_quartz_image_surface_fill,
281     NULL,  /* fill-stroke */
282     _cairo_quartz_image_surface_glyphs,
283 };
284
285 /**
286  * cairo_quartz_image_surface_create:
287  * @image_surface: a cairo image surface to wrap with a quartz image surface
288  *
289  * Creates a Quartz surface backed by a CGImageRef that references the
290  * given image surface. The resulting surface can be rendered quickly
291  * when used as a source when rendering to a #cairo_quartz_surface.  If
292  * the data in the image surface is ever updated, cairo_surface_flush()
293  * must be called on the #cairo_quartz_image_surface to ensure that the
294  * CGImageRef refers to the updated data.
295  *
296  * Return value: the newly created surface.
297  *
298  * Since: 1.6
299  **/
300 cairo_surface_t *
301 cairo_quartz_image_surface_create (cairo_surface_t *surface)
302 {
303     cairo_quartz_image_surface_t *qisurf;
304
305     CGImageRef image;
306
307     cairo_image_surface_t *image_surface;
308     int width, height, stride;
309     cairo_format_t format;
310     unsigned char *data;
311
312     if (surface->status)
313         return surface;
314
315     if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
316         return SURFACE_ERROR_TYPE_MISMATCH;
317
318     image_surface = (cairo_image_surface_t*) surface;
319     width = image_surface->width;
320     height = image_surface->height;
321     stride = image_surface->stride;
322     format = image_surface->format;
323     data = image_surface->data;
324
325     if (!_cairo_quartz_verify_surface_size(width, height))
326         return SURFACE_ERROR_INVALID_SIZE;
327
328     if (width == 0 || height == 0)
329         return SURFACE_ERROR_INVALID_SIZE;
330
331     if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24)
332         return SURFACE_ERROR_INVALID_FORMAT;
333
334     qisurf = malloc(sizeof(cairo_quartz_image_surface_t));
335     if (qisurf == NULL)
336         return SURFACE_ERROR_NO_MEMORY;
337
338     memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
339
340     /* In case the create_cgimage fails, this ref will
341      * be released via the callback (which will be called in
342      * case of failure.)
343      */
344     cairo_surface_reference (surface);
345
346     image = CairoQuartzCreateCGImage (format,
347                                       width, height,
348                                       stride,
349                                       data,
350                                       TRUE,
351                                       NULL,
352                                       DataProviderReleaseCallback,
353                                       image_surface);
354
355     if (!image) {
356         free (qisurf);
357         return SURFACE_ERROR_NO_MEMORY;
358     }
359
360     _cairo_surface_init (&qisurf->base,
361                          &cairo_quartz_image_surface_backend,
362                          NULL, /* device */
363                          _cairo_content_from_format (format));
364
365     qisurf->width = width;
366     qisurf->height = height;
367
368     qisurf->image = image;
369     qisurf->imageSurface = image_surface;
370
371     return &qisurf->base;
372 }
373
374
375 cairo_surface_t *
376 cairo_quartz_image_surface_get_image (cairo_surface_t *asurface)
377 {
378     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface;
379
380     if (cairo_surface_get_type(asurface) != CAIRO_SURFACE_TYPE_QUARTZ_IMAGE)
381         return NULL;
382
383     return (cairo_surface_t*) surface->imageSurface;
384 }