示例#1
0
static cairo_status_t
_cairo_tee_surface_acquire_source_image (void	     *abstract_surface,
					 cairo_image_surface_t **image_out,
					 void		 **image_extra)
{
    cairo_tee_surface_t *surface = abstract_surface;
    cairo_surface_wrapper_t *slaves;
    int num_slaves, n;

    /* we prefer to use a real image surface if available */
    if (_cairo_surface_is_image (surface->master.target)) {
	return _cairo_surface_wrapper_acquire_source_image (&surface->master,
							    image_out, image_extra);
    }

    num_slaves = _cairo_array_num_elements (&surface->slaves);
    slaves = _cairo_array_index (&surface->slaves, 0);
    for (n = 0; n < num_slaves; n++) {
	if (_cairo_surface_is_image (slaves[n].target)) {
	    return _cairo_surface_wrapper_acquire_source_image (&slaves[n],
								image_out,
								image_extra);
	}
    }

    return _cairo_surface_wrapper_acquire_source_image (&surface->master,
							image_out, image_extra);
}
示例#2
0
static cairo_status_t _cairo_xynth_surface_clone_similar (void *abstract_surface, cairo_surface_t *src, int src_x, int src_y, int width, int height, cairo_surface_t **clone_out)
{
	s_render_t *tmp;
	cairo_status_t status;
	cairo_xynth_surface_t *clone;
	cairo_xynth_surface_t *surface;
	ENTER();
	surface = (cairo_xynth_surface_t *) abstract_surface;
	if (src->backend == surface->cairo.backend) {
		*clone_out = cairo_surface_reference(src);
		status = CAIRO_STATUS_SUCCESS;
	} else if (_cairo_surface_is_image(src)) {
		cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
		if (!CAIRO_FORMAT_VALID(image_src->format)) {
			status = CAIRO_INT_STATUS_UNSUPPORTED;
			goto out;
		}
		clone = (cairo_xynth_surface_t *) cairo_xynth_surface_create(image_src->width, image_src->height, image_src->format);
		if (clone->cairo.status) {
			status = CAIRO_STATUS_NO_MEMORY;
			goto out;
		}
		s_render_init_for_data(&tmp, image_src->data, _cairo_xynth_format_from_cairo_format(image_src->format), image_src->width, image_src->height, image_src->depth, image_src->stride);
		s_render_composite(S_RENDER_OPERATOR_SRC, tmp, NULL, clone->render, src_x, src_y, 0, 0, src_x, src_y, width, height);
		s_render_uninit(tmp);
		*clone_out = &clone->cairo;
		status = CAIRO_STATUS_SUCCESS;
	} else {
		status = CAIRO_INT_STATUS_UNSUPPORTED;
	}
out:
	LEAVE();
	return status;
}
cairo_status_t
_cairo_gl_surface_clone_similar (void		     *abstract_surface,
				 cairo_surface_t     *src,
				 int                  src_x,
				 int                  src_y,
				 int                  width,
				 int                  height,
				 int                 *clone_offset_x,
				 int                 *clone_offset_y,
				 cairo_surface_t    **clone_out)
{
    cairo_gl_surface_t *surface = abstract_surface;
    cairo_int_status_t status;

    /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
    if (src->device == surface->base.device &&
        _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
	status = _cairo_gl_surface_deferred_clear ((cairo_gl_surface_t *)src);
	if (unlikely (status))
	    return status;

	*clone_offset_x = 0;
	*clone_offset_y = 0;
	*clone_out = cairo_surface_reference (src);

	return CAIRO_STATUS_SUCCESS;
    } else if (_cairo_surface_is_image (src)) {
	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
	cairo_gl_surface_t *clone;

	clone = (cairo_gl_surface_t *)
		_cairo_gl_surface_create_similar (&surface->base,
						  src->content,
						  width, height);
	if (clone == NULL)
	    return UNSUPPORTED ("create_similar failed");
	if (clone->base.status)
	    return clone->base.status;

	status = _cairo_gl_surface_draw_image (clone, image_src,
					       src_x, src_y,
					       width, height,
					       0, 0);
	if (status) {
	    cairo_surface_destroy (&clone->base);
	    return status;
	}

	*clone_out = &clone->base;
	*clone_offset_x = src_x;
	*clone_offset_y = src_y;

	return CAIRO_STATUS_SUCCESS;
    }

    return UNSUPPORTED ("unknown src surface type in clone_similar");
}
示例#4
0
/**
 * cairo_image_surface_get_height:
 * @surface: a #cairo_image_surface_t
 *
 * Get the height of the image surface in pixels.
 *
 * Return value: the height of the surface in pixels.
 *
 * Since: 1.0
 **/
int
cairo_image_surface_get_height (cairo_surface_t *surface)
{
    cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;

    if (! _cairo_surface_is_image (surface)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }

    return image_surface->height;
}
示例#5
0
/**
 * cairo_image_surface_get_format:
 * @surface: a #cairo_image_surface_t
 *
 * Get the format of the surface.
 *
 * Return value: the format of the surface
 *
 * Since: 1.2
 **/
cairo_format_t
cairo_image_surface_get_format (cairo_surface_t *surface)
{
    cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;

    if (! _cairo_surface_is_image (surface)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return CAIRO_FORMAT_INVALID;
    }

    return image_surface->format;
}
示例#6
0
/**
 * cairo_image_surface_get_data:
 * @surface: a #cairo_image_surface_t
 *
 * Get a pointer to the data of the image surface, for direct
 * inspection or modification.
 *
 * A call to cairo_surface_flush() is required before accessing the
 * pixel data to ensure that all pending drawing operations are
 * finished. A call to cairo_surface_mark_dirty() is required after
 * the data is modified.
 *
 * Return value: a pointer to the image data of this surface or %NULL
 * if @surface is not an image surface, or if cairo_surface_finish()
 * has been called.
 *
 * Since: 1.2
 **/
unsigned char *
cairo_image_surface_get_data (cairo_surface_t *surface)
{
    cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;

    if (! _cairo_surface_is_image (surface)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return NULL;
    }

    return image_surface->data;
}
/**
 * cairo_image_surface_get_width:
 * @surface: a #cairo_image_surface_t
 * 
 * Get the width of the image surface in pixels.
 * 
 * Return value: the width of the surface in pixels.
 **/
int
cairo_image_surface_get_width (cairo_surface_t *surface)
{
    cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;

    if (!_cairo_surface_is_image (surface)) {
	_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }

    return image_surface->width;
}
示例#8
0
static cairo_status_t
_cairo_skia_surface_clone_similar (void *asurface,
				   cairo_surface_t *src,
				   cairo_content_t content,
				   int src_x,
				   int src_y,
				   int width,
				   int height,
				   int *clone_offset_x,
				   int *clone_offset_y,
				   cairo_surface_t **clone_out)
{
    if (src->type == CAIRO_SURFACE_TYPE_SKIA || _cairo_surface_is_image (src)) {
	*clone_offset_x = 0;
	*clone_offset_y = 0;
	*clone_out = cairo_surface_reference (src);
	return CAIRO_STATUS_SUCCESS;
    }

    return (cairo_status_t) CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
_cairo_xcb_surface_clone_similar (void			*abstract_surface,
				  cairo_surface_t	*src,
				  cairo_surface_t     **clone_out)
{
    cairo_xcb_surface_t *surface = abstract_surface;
    cairo_xcb_surface_t *clone;

    if (src->backend == surface->base.backend ) {
	cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;

	if (_cairo_xcb_surface_same_screen(surface, xcb_src)) {
	    *clone_out = cairo_surface_reference (src);

	    return CAIRO_STATUS_SUCCESS;
	}
    } else if (_cairo_surface_is_image (src)) {
	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
	cairo_content_t content = _cairo_content_from_format (image_src->format);

	if (surface->base.status)
	    return surface->base.status;

	clone = (cairo_xcb_surface_t *)
	    _cairo_xcb_surface_create_similar (surface, content,
					       image_src->width, image_src->height);
	if (clone->base.status)
	    return CAIRO_STATUS_NO_MEMORY;

	_draw_image_surface (clone, image_src, 0, 0);

	*clone_out = &clone->base;

	return CAIRO_STATUS_SUCCESS;
    }

    return CAIRO_INT_STATUS_UNSUPPORTED;
}
static SkShader*
source_to_sk_shader (cairo_skia_context_t *cr,
		     const cairo_pattern_t *pattern)
{
    SkShader *shader = NULL;

    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
	return new SkColorShader (color_to_sk (solid->color));
    } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
	cairo_surface_t *surface = surface_from_pattern (pattern);

	cr->source = cairo_surface_reference (surface);

	if (surface->type == CAIRO_SURFACE_TYPE_SKIA) {
	    cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface;

	    shader = SkShader::CreateBitmapShader (*esurf->bitmap,
						   extend_to_sk (pattern->extend),
						   extend_to_sk (pattern->extend));
	} else {
	    SkBitmap bitmap;

	    if (! _cairo_surface_is_image (surface)) {
		cairo_status_t status;

		status = _cairo_surface_acquire_source_image (surface,
							      &cr->source_image,
							      &cr->source_extra);
		if (status)
		    return NULL;

		surface = &cr->source_image->base;
	    }

	    if (unlikely (! surface_to_sk_bitmap (surface, bitmap)))
		return NULL;

	    shader = SkShader::CreateBitmapShader (bitmap,
						   extend_to_sk (pattern->extend),
						   extend_to_sk (pattern->extend));
	}
    } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR
	       /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */)
    {
	cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
	SkColor colors_stack[10];
	SkScalar pos_stack[10];
	SkColor *colors = colors_stack;
	SkScalar *pos = pos_stack;

	if (gradient->n_stops > 10) {
	    colors = new SkColor[gradient->n_stops];
	    pos = new SkScalar[gradient->n_stops];
	}

	for (unsigned int i = 0; i < gradient->n_stops; i++) {
	    pos[i] = CAIRO_FIXED_TO_SK_SCALAR (gradient->stops[i].offset);
	    colors[i] = color_stop_to_sk (gradient->stops[i].color);
	}

	if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
	    cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
	    SkPoint points[2];

	    points[0].set (SkFloatToScalar (linear->pd1.x),
			   SkFloatToScalar (linear->pd1.y));
	    points[1].set (SkFloatToScalar (linear->pd2.x),
			   SkFloatToScalar (linear->pd2.y));
	    shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops,
						     extend_to_sk (pattern->extend));
	} else {
	    // XXX todo -- implement real radial shaders in Skia
	}

	if (gradient->n_stops > 10) {
	    delete [] colors;
	    delete [] pos;
	}
    }

    if (shader && ! _cairo_matrix_is_identity (&pattern->matrix))
	shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix));

    return shader;
}
cairo_int_status_t
_cairo_gl_surface_composite (cairo_operator_t		  op,
			     const cairo_pattern_t	 *src,
			     const cairo_pattern_t	 *mask,
			     void			 *abstract_dst,
			     int			  src_x,
			     int			  src_y,
			     int			  mask_x,
			     int			  mask_y,
			     int			  dst_x,
			     int			  dst_y,
			     unsigned int		  width,
			     unsigned int		  height,
			     cairo_region_t		 *clip_region)
{
    cairo_gl_surface_t *dst = abstract_dst;
    cairo_gl_context_t *ctx;
    cairo_status_t status;
    cairo_gl_composite_t setup;
    cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
    int dx, dy;

    status = _cairo_gl_surface_deferred_clear (dst);
    if (unlikely (status))
	    return status;

    if (op == CAIRO_OPERATOR_SOURCE &&
        mask == NULL &&
        src->type == CAIRO_PATTERN_TYPE_SURFACE &&
        _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
        _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
        cairo_image_surface_t *image = (cairo_image_surface_t *)
            ((cairo_surface_pattern_t *) src)->surface;
        dx += src_x;
        dy += src_y;
        if (dx >= 0 &&
            dy >= 0 &&
            dx + width <= (unsigned int) image->width &&
            dy + height <= (unsigned int) image->height) {
            status = _cairo_gl_surface_draw_image (dst, image,
                                                   dx, dy,
                                                   width, height,
                                                   dst_x, dst_y);
            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
                return status;
        }
    }

    status = _cairo_gl_composite_init (&setup, op, dst,
                                       mask && mask->has_component_alpha,
                                       &rect);
    if (unlikely (status))
        goto CLEANUP;

    status = _cairo_gl_composite_set_source (&setup, src,
                                             src_x, src_y,
                                             dst_x, dst_y,
                                             width, height);
    if (unlikely (status))
        goto CLEANUP;

    status = _cairo_gl_composite_set_mask (&setup, mask,
                                           mask_x, mask_y,
                                           dst_x, dst_y,
                                           width, height);
    if (unlikely (status))
        goto CLEANUP;

    status = _cairo_gl_composite_begin (&setup, &ctx);
    if (unlikely (status))
	goto CLEANUP;

    if (clip_region != NULL) {
        int i, num_rectangles;

        num_rectangles = cairo_region_num_rectangles (clip_region);

	for (i = 0; i < num_rectangles; i++) {
	    cairo_rectangle_int_t rect;

	    cairo_region_get_rectangle (clip_region, i, &rect);
            _cairo_gl_composite_emit_rect (ctx,
                                           rect.x,              rect.y,
                                           rect.x + rect.width, rect.y + rect.height,
                                           0);
	}
    } else {
        _cairo_gl_composite_emit_rect (ctx,
                                       dst_x,         dst_y,
                                       dst_x + width, dst_y + height,
                                       0);
    }

    status = _cairo_gl_context_release (ctx, status);

  CLEANUP:
    _cairo_gl_composite_fini (&setup);

    return status;
}
static cairo_int_status_t
_cairo_beos_surface_composite (cairo_operator_t		op,
			       cairo_pattern_t	       *src,
			       cairo_pattern_t	       *mask,
			       void		       *dst,
			       int		 	src_x,
			       int			src_y,
			       int			mask_x,
			       int			mask_y,
			       int			dst_x,
			       int			dst_y,
			       unsigned int		width,
			       unsigned int		height)
{
    cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
							dst);
    AutoLockView locker(surface->view);
    if (!locker)
	return CAIRO_INT_STATUS_SUCCESS;

    drawing_mode mode;
    if (!_cairo_op_to_be_op(op, &mode))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    // XXX Masks are not yet supported
    if (mask)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    // XXX should eventually support the others
    if (src->type != CAIRO_PATTERN_TYPE_SURFACE ||
	src->extend != CAIRO_EXTEND_NONE)
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    // Can we maybe support other matrices as well? (scale? if the filter is right)
    int itx, ity;
    if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    BRect srcRect(src_x + itx,
		  src_y + ity,
		  src_x + itx + width - 1,
		  src_y + ity + height - 1);
    BRect dstRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1);

    cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)->
					surface;

    // Get a bitmap
    BBitmap* bmp = NULL;
    bool free_bmp = false;
    if (_cairo_surface_is_image(src_surface)) {
	cairo_image_surface_t* img_surface =
	    reinterpret_cast<cairo_image_surface_t*>(src_surface);

	bmp = _cairo_image_surface_to_bitmap(img_surface);
	free_bmp = true;
    } else if (src_surface->backend == surface->base.backend) {
	cairo_beos_surface_t *beos_surface =
	    reinterpret_cast<cairo_beos_surface_t*>(src_surface);
	if (beos_surface->bitmap) {
	    AutoLockView locker(beos_surface->view);
	    if (locker)
		beos_surface->view->Sync();
	    bmp = beos_surface->bitmap;
	} else {
	    _cairo_beos_view_to_bitmap(surface->view, &bmp);
	    free_bmp = true;
	}
    }

    if (!bmp)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    // So, BeOS seems to screw up painting an opaque bitmap onto a
    // translucent one (it makes them partly transparent). Just return
    // unsupported.
    if (bmp->ColorSpace() == B_RGB32 && surface->bitmap &&
	surface->bitmap->ColorSpace() == B_RGBA32 &&
	(mode == B_OP_COPY || mode == B_OP_ALPHA))
    {
	if (free_bmp)
	    delete bmp;
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    fprintf(stderr, "Composite\n");

    // Draw it on screen.
    surface->view->PushState();

	// If our image rect is only a subrect of the desired size, and we
	// aren't using B_OP_ALPHA, then we need to fill the rect first.
	if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) {
	    rgb_color black = { 0, 0, 0, 0 };

	    surface->view->SetDrawingMode(mode);
	    surface->view->SetHighColor(black);
	    surface->view->FillRect(dstRect);
	}

	if (mode == B_OP_ALPHA && bmp->ColorSpace() == B_RGB32) {
	    mode = B_OP_COPY;
	}
	surface->view->SetDrawingMode(mode);

	if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
	    surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
	else
	    surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);

	surface->view->DrawBitmap(bmp, srcRect, dstRect);

    surface->view->PopState();

    if (free_bmp)
	delete bmp;

    return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_beos_composite (cairo_operator_t		op,
		       cairo_pattern_t	       *src,
		       cairo_pattern_t	       *mask,
		       void		       *dst,
		       int		 	src_x,
		       int			src_y,
		       int			mask_x,
		       int			mask_y,
		       int			dst_x,
		       int			dst_y,
		       unsigned int		width,
		       unsigned int		height)
{
    cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
							dst);
    AutoLockView locker(surface->view);
    if (!locker)
	return CAIRO_INT_STATUS_SUCCESS;

    drawing_mode mode;
    if (!_cairo_op_to_be_op(op, &mode))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    // XXX Masks are not yet supported
    if (mask)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    // XXX should eventually support the others
    if (src->type != CAIRO_PATTERN_SURFACE ||
	src->extend != CAIRO_EXTEND_NONE)
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    // Can we maybe support other matrices as well? (scale? if the filter is right)
    int itx, ity;
    if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    BRect srcRect(src_x + itx,
		  src_y + ity,
		  src_x + itx + width - 1,
		  src_y + ity + height - 1);
    BRect dstRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1);

    cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)->
					surface;
    if (_cairo_surface_is_image(src_surface)) {
    	fprintf(stderr, "Composite\n");

	// Draw it on screen.
	cairo_image_surface_t* img_surface =
	    reinterpret_cast<cairo_image_surface_t*>(src_surface);

	BBitmap* bmp = _cairo_image_surface_to_bitmap(img_surface);
	surface->view->PushState();

	    // If our image rect is only a subrect of the desired size, and we
	    // aren't using B_OP_ALPHA, then we need to fill the rect first.
	    if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) {
		rgb_color black = { 0, 0, 0, 0 };

		surface->view->SetDrawingMode(mode);
		surface->view->SetHighColor(black);
		surface->view->FillRect(dstRect);
	    }

	    if (mode == B_OP_ALPHA && img_surface->format != CAIRO_FORMAT_ARGB32) {
		mode = B_OP_COPY;

	    }
	    surface->view->SetDrawingMode(mode);

	    if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
		surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
	    else
		surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);

	    surface->view->DrawBitmap(bmp, srcRect, dstRect);

	surface->view->PopState();
	delete bmp;

	return CAIRO_INT_STATUS_SUCCESS;
    }

    return CAIRO_INT_STATUS_UNSUPPORTED;
}
/**
 * cairo_quartz_image_surface_create:
 * @image_surface: a cairo image surface to wrap with a quartz image surface
 *
 * Creates a Quartz surface backed by a CGImageRef that references the
 * given image surface. The resulting surface can be rendered quickly
 * when used as a source when rendering to a #cairo_quartz_surface.  If
 * the data in the image surface is ever updated, cairo_surface_flush()
 * must be called on the #cairo_quartz_image_surface to ensure that the
 * CGImageRef refers to the updated data.
 *
 * Return value: the newly created surface.
 *
 * Since: 1.6
 **/
cairo_surface_t *
cairo_quartz_image_surface_create (cairo_surface_t *surface)
{
    cairo_quartz_image_surface_t *qisurf;

    CGImageRef image;

    cairo_image_surface_t *image_surface;
    int width, height, stride;
    cairo_format_t format;
    unsigned char *data;

    if (surface->status)
	return surface;

    if (! _cairo_surface_is_image (surface))
	return SURFACE_ERROR_TYPE_MISMATCH;

    image_surface = (cairo_image_surface_t*) surface;
    width = image_surface->width;
    height = image_surface->height;
    stride = image_surface->stride;
    format = image_surface->format;
    data = image_surface->data;

    if (!_cairo_quartz_verify_surface_size(width, height))
	return SURFACE_ERROR_INVALID_SIZE;

    if (width == 0 || height == 0)
	return SURFACE_ERROR_INVALID_SIZE;

    if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24)
	return SURFACE_ERROR_INVALID_FORMAT;

    qisurf = malloc(sizeof(cairo_quartz_image_surface_t));
    if (qisurf == NULL)
	return SURFACE_ERROR_NO_MEMORY;

    memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));

    /* In case the create_cgimage fails, this ref will
     * be released via the callback (which will be called in
     * case of failure.)
     */
    cairo_surface_reference (surface);

    image = CairoQuartzCreateCGImage (format,
				      width, height,
				      stride,
				      data,
				      TRUE,
				      NULL,
				      DataProviderReleaseCallback,
				      image_surface);

    if (!image) {
	free (qisurf);
	return SURFACE_ERROR_NO_MEMORY;
    }

    _cairo_surface_init (&qisurf->base,
			 &cairo_quartz_image_surface_backend,
			 NULL, /* device */
			 _cairo_content_from_format (format));

    qisurf->width = width;
    qisurf->height = height;

    qisurf->image = image;
    qisurf->imageSurface = image_surface;

    return &qisurf->base;
}