Back to index

lightning-sunbird  0.9+nobinonly
cairo-quartz-surface.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2004 Calum Robinson
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is Calum Robinson
00031  *
00032  * Contributor(s):
00033  *    Calum Robinson <calumr@mac.com>
00034  */
00035 
00036 #include "cairoint.h"
00037 #include "cairo-private.h"
00038 #include "cairo-quartz.h"
00039 
00040 typedef struct cairo_quartz_surface {
00041     cairo_surface_t base;
00042 
00043     CGContextRef context;
00044 
00045     int width;
00046     int height;
00047 
00048     cairo_image_surface_t *image;
00049 
00050     CGImageRef cgImage;
00051 } cairo_quartz_surface_t;
00052 
00053 static void
00054 ImageDataReleaseFunc(void *info, const void *data, size_t size)
00055 {
00056     if (data != NULL) {
00057         free((void *) data);
00058     }
00059 }
00060 
00061 static cairo_status_t
00062 _cairo_quartz_surface_finish(void *abstract_surface)
00063 {
00064     cairo_quartz_surface_t *surface = abstract_surface;
00065 
00066     if (surface->image)
00067         cairo_surface_destroy(&surface->image->base);
00068 
00069     if (surface->cgImage)
00070         CGImageRelease(surface->cgImage);
00071 
00072     return CAIRO_STATUS_SUCCESS;
00073 }
00074 
00075 static cairo_status_t
00076 _cairo_quartz_surface_acquire_source_image(void *abstract_surface,
00077                                       cairo_image_surface_t **image_out,
00078                                       void **image_extra)
00079 {
00080     cairo_quartz_surface_t *surface = abstract_surface;
00081     CGColorSpaceRef colorSpace;
00082     void *imageData;
00083     UInt32 imageDataSize, rowBytes;
00084     CGDataProviderRef dataProvider;
00085 
00086     // We keep a cached (cairo_image_surface_t *) in the cairo_quartz_surface_t
00087     // struct. If the window is ever drawn to without going through Cairo, then
00088     // we would need to refetch the pixel data from the window into the cached
00089     // image surface. 
00090     if (surface->image) {
00091         cairo_surface_reference(&surface->image->base);
00092 
00093        *image_out = surface->image;
00094        return CAIRO_STATUS_SUCCESS;
00095     }
00096 
00097     colorSpace = CGColorSpaceCreateDeviceRGB();
00098 
00099 
00100     rowBytes = surface->width * 4;
00101     imageDataSize = rowBytes * surface->height;
00102     imageData = malloc(imageDataSize);
00103 
00104     dataProvider =
00105         CGDataProviderCreateWithData(NULL, imageData, imageDataSize,
00106                                      ImageDataReleaseFunc);
00107 
00108     surface->cgImage = CGImageCreate(surface->width,
00109                                      surface->height,
00110                                      8,
00111                                      32,
00112                                      rowBytes,
00113                                      colorSpace,
00114                                      kCGImageAlphaPremultipliedFirst |
00115                                       kCGBitmapByteOrder32Host,
00116                                      dataProvider,
00117                                      NULL,
00118                                      false, kCGRenderingIntentDefault);
00119 
00120     CGColorSpaceRelease(colorSpace);
00121     CGDataProviderRelease(dataProvider);
00122 
00123     surface->image = (cairo_image_surface_t *)
00124         cairo_image_surface_create_for_data(imageData,
00125                                             CAIRO_FORMAT_ARGB32,
00126                                             surface->width,
00127                                             surface->height, rowBytes);
00128     if (surface->image->base.status) {
00129        if (surface->cgImage)
00130            CGImageRelease(surface->cgImage);
00131        return CAIRO_STATUS_NO_MEMORY;
00132     }
00133 
00134     *image_out = surface->image;
00135     *image_extra = NULL;
00136 
00137     return CAIRO_STATUS_SUCCESS;
00138 }
00139 
00140 static cairo_status_t
00141 _cairo_quartz_surface_acquire_dest_image(void *abstract_surface,
00142                                          cairo_rectangle_t * interest_rect,
00143                                          cairo_image_surface_t **
00144                                          image_out,
00145                                          cairo_rectangle_t * image_rect,
00146                                          void **image_extra)
00147 {
00148     cairo_quartz_surface_t *surface = abstract_surface;
00149 
00150     image_rect->x = 0;
00151     image_rect->y = 0;
00152     image_rect->width = surface->image->width;
00153     image_rect->height = surface->image->height;
00154 
00155     *image_out = surface->image;
00156     if (image_extra)
00157        *image_extra = NULL;
00158 
00159     return CAIRO_STATUS_SUCCESS;
00160 }
00161 
00162 
00163 static void
00164 _cairo_quartz_surface_release_dest_image(void *abstract_surface,
00165                                          cairo_rectangle_t *
00166                                          intersect_rect,
00167                                          cairo_image_surface_t * image,
00168                                          cairo_rectangle_t * image_rect,
00169                                          void *image_extra)
00170 {
00171     cairo_quartz_surface_t *surface = abstract_surface;
00172 
00173     if (surface->image == image) {
00174         CGRect rect;
00175 
00176         rect = CGRectMake(0, 0, surface->width, surface->height);
00177 
00178         CGContextDrawImage(surface->context, rect, surface->cgImage);
00179 
00180        memset(surface->image->data, 0, surface->width * surface->height * 4);
00181     }
00182 }
00183 
00184 static cairo_int_status_t
00185 _cairo_quartz_surface_set_clip_region(void *abstract_surface,
00186                                       pixman_region16_t * region)
00187 {
00188     cairo_quartz_surface_t *surface = abstract_surface;
00189     unsigned int serial;
00190 
00191     serial = _cairo_surface_allocate_clip_serial (&surface->image->base);
00192     return _cairo_surface_set_clip_region(&surface->image->base,
00193                                      region, serial);
00194 }
00195 
00196 static cairo_int_status_t
00197 _cairo_quartz_surface_get_extents (void *abstract_surface,
00198                                cairo_rectangle_t * rectangle)
00199 {
00200     cairo_quartz_surface_t *surface = abstract_surface;
00201 
00202     rectangle->x = 0;
00203     rectangle->y = 0;
00204     rectangle->width = surface->width;
00205     rectangle->height = surface->height;
00206 
00207     return CAIRO_STATUS_SUCCESS;
00208 }
00209 
00210 static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
00211     NULL, /* create_similar */
00212     _cairo_quartz_surface_finish,
00213     _cairo_quartz_surface_acquire_source_image,
00214     NULL, /* release_source_image */
00215     _cairo_quartz_surface_acquire_dest_image,
00216     _cairo_quartz_surface_release_dest_image,
00217     NULL, /* clone_similar */
00218     NULL, /* composite */
00219     NULL, /* fill_rectangles */
00220     NULL, /* composite_trapezoids */
00221     NULL, /* copy_page */
00222     NULL, /* show_page */
00223     _cairo_quartz_surface_set_clip_region,
00224     NULL, /* intersect_clip_path */
00225     _cairo_quartz_surface_get_extents,
00226     NULL  /* show_glyphs */
00227 };
00228 
00229 
00230 cairo_surface_t *cairo_quartz_surface_create(CGContextRef context,
00231                                              int width, int height)
00232 {
00233     cairo_quartz_surface_t *surface;
00234 
00235     surface = malloc(sizeof(cairo_quartz_surface_t));
00236     if (surface == NULL) {
00237        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00238         return (cairo_surface_t*) &_cairo_surface_nil;
00239     }
00240 
00241     _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
00242 
00243     surface->context = context;
00244     surface->width = width;
00245     surface->height = height;
00246     surface->image = NULL;
00247     surface->cgImage = NULL;
00248 
00249     // Set up the image surface which Cairo draws into and we blit to & from.
00250     void *foo;
00251     _cairo_quartz_surface_acquire_source_image(surface, &surface->image, &foo);
00252 
00253     return (cairo_surface_t *) surface;
00254 }