From 25c1b0c0e8079355924134a2a84d243b23da69fe Mon Sep 17 00:00:00 2001 From: Søren Sandmann Pedersen Date: Wed, 28 Mar 2012 16:32:42 -0400 Subject: Flesh out the pixman surface some --- src/cairo-pixman-surface.c | 345 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 275 insertions(+), 70 deletions(-) diff --git a/src/cairo-pixman-surface.c b/src/cairo-pixman-surface.c index 5a60b663..3a7b3ec0 100644 --- a/src/cairo-pixman-surface.c +++ b/src/cairo-pixman-surface.c @@ -41,11 +41,18 @@ #include "cairo-pixman.h" #include "cairo-default-context-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-pattern-private.h" -/* Limit on the width / height of an image surface in pixels. This is - * mainly determined by coordinates of things sent to pixman at the - * moment being in 16.16 format. */ -#define MAX_IMAGE_SIZE 32767 +extern const cairo_surface_backend_t cairo_pixman_surface_backend; + +typedef struct _cairo_pixman_surface cairo_pixman_surface_t; + +struct _cairo_pixman_surface +{ + cairo_surface_t base; + pixman_image_t * pimage; +}; /** * SECTION:cairo-pixman @@ -63,16 +70,29 @@ * * Defined if the pixman surface backend is available. * - * @Since: 1.13 + * @Since: 1.14 */ +static cairo_content_t +content_from_pixman_image (pixman_image_t *image) +{ + pixman_format_code_t format = pixman_image_get_format (image); + cairo_content_t result; + + result = 0; + if (PIXMAN_FORMAT_RGB (format)) + result |= CAIRO_CONTENT_COLOR; + if (PIXMAN_FORMAT_A (format)) + result |= CAIRO_CONTENT_ALPHA; + + return result; +} + /** * cairo_pixman_surface_create: - * @format: format of pixels in the surface to create - * @width: width of the surface, in pixels - * @height: height of the surface, in pixels + * @image: a pixman image * - * Creates an image surface of the specified format and + * Creates an pixman surface based on the given image * dimensions. Initially the surface contents are all * 0. (Specifically, within each pixel, each color or alpha channel * belonging to format will be 0. The contents of bits within a pixel, @@ -89,94 +109,278 @@ cairo_surface_t * cairo_pixman_surface_create (pixman_image_t *image) { - return NULL; + cairo_pixman_surface_t *surface; + pixman_format_code_t format; + + if (!(surface = malloc (sizeof *surface))) { + return _cairo_surface_create_in_error ( + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + format = pixman_image_get_format (image); + if (!format || !pixman_format_supported_destination (format)) { + /* FIXME: This error status is intended for incorrect + * cairo_format_ts, not incorrect pixman formats. In + * principle a new error status should be added + */ + return _cairo_surface_create_in_error ( + _cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } + + _cairo_surface_init (&surface->base, &cairo_pixman_surface_backend, + NULL, /* device */ + content_from_pixman_image (image)); + + surface->pimage = pixman_image_ref (image); + + return (cairo_surface_t *)surface; } static cairo_status_t -_cairo_pixman_surface_finish (void *abstract_surface) +cairo_pixman_surface_finish (void *abstract_surface) { + cairo_pixman_surface_t *surface = abstract_surface; + + pixman_image_unref (surface->pimage); + surface->pimage = NULL; + + return CAIRO_STATUS_SUCCESS; } static cairo_surface_t * -_cairo_pixman_surface_create_similar (void *abstract_other, - cairo_content_t content, - int width, - int height) +cairo_pixman_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, + int height) { + cairo_pixman_surface_t *other = abstract_other; + pixman_format_code_t format; + pixman_image_t *copy; + + format = pixman_image_get_format (other->pimage); + + copy = pixman_image_create_bits (format, width, height, NULL, -1); + + return cairo_pixman_surface_create (copy); } static cairo_surface_t * -_cairo_pixman_surface_map_to_image (void *abstract_other, - const cairo_rectangle_int_t *extents) +create_image_surface (cairo_pixman_surface_t *psurface) { + pixman_image_t *pimage = psurface->pimage; + pixman_format_code_t pformat = pixman_image_get_format (pimage); + cairo_bool_t must_copy = FALSE; + cairo_surface_t *image; + cairo_format_t format; + + switch (pformat) + { + case PIXMAN_a8r8g8b8: + format = CAIRO_FORMAT_ARGB32; + break; + + case PIXMAN_x8r8g8b8: + format = CAIRO_FORMAT_RGB24; + break; + + case PIXMAN_a8: + format = CAIRO_FORMAT_A8; + break; + + case PIXMAN_a1: + format = CAIRO_FORMAT_A1; + break; + + case PIXMAN_r5g6b5: + format = CAIRO_FORMAT_RGB16_565; + break; + + case PIXMAN_x2r10g10b10: + format = CAIRO_FORMAT_RGB30; + break; + + default: + format = CAIRO_FORMAT_ARGB32; + must_copy = TRUE; + break; + } + + if (must_copy) + { + int width = pixman_image_get_width (pimage); + int height = pixman_image_get_height (pimage); + pixman_image_t *dest; + + image = cairo_image_surface_create (format, width, height); + + dest = ((cairo_image_surface_t *)image)->pixman_image; + + pixman_image_composite32 (PIXMAN_OP_SRC, + pimage, NULL, dest, + 0, 0, 0, 0, 0, 0, width, height); + } + else + { + image = _cairo_image_surface_create_for_pixman_image (pimage, pformat); + } + + return image; +} + +static cairo_surface_t * +cairo_pixman_surface_map_to_image (void *abstract_other, + const cairo_rectangle_int_t *extents) +{ + cairo_pixman_surface_t *surface = abstract_other; + + /* FIXME: if we need to copy, we should only copy extents */ + return create_image_surface (surface); } static cairo_int_status_t -_cairo_pixman_surface_unmap_image (void *abstract_surface, - cairo_image_surface_t *image) +cairo_pixman_surface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) { + cairo_pixman_surface_t *surface = abstract_surface; + + if (image->pixman_image != surface->pimage) + { + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, surface->pimage, + 0, 0, 0, 0, 0, 0, + pixman_image_get_width (surface->pimage), + pixman_image_get_height (surface->pimage)); + } + + return CAIRO_STATUS_SUCCESS; } static cairo_surface_t * -_cairo_pixman_surface_source (void *abstract_surface, - cairo_rectangle_int_t *extents) +cairo_pixman_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) { + cairo_pixman_surface_t *surface = abstract_surface; + + extents->x = extents->y = 0; + extents->width = pixman_image_get_width (surface->pimage); + extents->height = pixman_image_get_height (surface->pimage); + + return &surface->base; } static cairo_status_t -_cairo_pixman_surface_acquire_source_image (void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) +cairo_pixman_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { - *image_out = abstract_surface; + cairo_pixman_surface_t *psurface; + + *image_out = (cairo_image_surface_t *)create_image_surface (psurface); *image_extra = NULL; + /* FIXME: create_image_surface can fail (or should be able to fail) */ return CAIRO_STATUS_SUCCESS; } static void -_cairo_pixman_surface_release_source_image (void *abstract_surface, +cairo_pixman_surface_release_source_image (void *abstract_surface, cairo_image_surface_t *image, void *image_extra) { + cairo_surface_destroy ((cairo_surface_t *)image); } static cairo_surface_t * -_cairo_pixman_surface_snapshot (void *abstract_surface) +cairo_pixman_surface_snapshot (void *abstract_surface) { + /* huh? */ } static cairo_bool_t -_cairo_pixman_surface_get_extents (void *abstract_surface, - cairo_rectangle_int_t *rectangle) +cairo_pixman_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) { + cairo_pixman_surface_t *psurface = abstract_surface; + + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = pixman_image_get_width (psurface->pimage); + rectangle->height = pixman_image_get_height (psurface->pimage); + + return CAIRO_STATUS_SUCCESS; } static void -_cairo_pixman_surface_get_font_options (void *abstract_surface, +cairo_pixman_surface_get_font_options (void *abstract_surface, cairo_font_options_t *options) { + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); } -static cairo_int_status_t -_cairo_pixman_surface_paint (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) +static pixman_image_t * +pimage_from_solid_pattern (cairo_solid_pattern_t *solid) +{ + pixman_color_t pcolor; + + pcolor.red = _cairo_color_double_to_short (solid->color.red); + pcolor.green = _cairo_color_double_to_short (solid->color.green); + pcolor.blue = _cairo_color_double_to_short (solid->color.blue); + pcolor.alpha = _cairo_color_double_to_short (solid->color.alpha); + + return pixman_image_create_solid_fill (&pcolor); +} + +static pixman_image_t * +pimage_from_surface_pattern (cairo_surface_pattern_t *surface) { + +} + +static pixman_image_t * +pimage_from_pattern (const cairo_pattern_t *pattern) +{ + switch (pattern->type) + { + case CAIRO_PATTERN_TYPE_SOLID: + return pimage_from_solid_pattern ((cairo_solid_pattern_t *)pattern); + break; + + case CAIRO_PATTERN_TYPE_SURFACE: + return pimage_from_surface_pattern ((cairo_surface_pattern_t *)pattern); + break; + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + break; + } } static cairo_int_status_t -_cairo_pixman_surface_mask (void *abstract_surface, +cairo_pixman_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask, const cairo_clip_t *clip) { + pixman_image_t *iamge = pimage_from_pattern (source); + } static cairo_int_status_t -_cairo_pixman_surface_stroke (void *abstract_surface, +cairo_pixman_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ +} + +static cairo_int_status_t +cairo_pixman_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, @@ -190,19 +394,19 @@ _cairo_pixman_surface_stroke (void *abstract_surface, } static cairo_int_status_t -_cairo_pixman_surface_fill (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) +cairo_pixman_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) { } static cairo_int_status_t -_cairo_pixman_surface_glyphs (void *abstract_surface, +cairo_pixman_surface_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *glyphs, @@ -210,38 +414,39 @@ _cairo_pixman_surface_glyphs (void *abstract_surface, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { + } -const cairo_surface_backend_t _cairo_pixman_surface_backend = +const cairo_surface_backend_t cairo_pixman_surface_backend = { CAIRO_SURFACE_TYPE_IMAGE, - _cairo_pixman_surface_finish, - + cairo_pixman_surface_finish, + _cairo_default_context_create, - - _cairo_pixman_surface_create_similar, + + cairo_pixman_surface_create_similar, NULL, /* create similar image */ - _cairo_pixman_surface_map_to_image, - _cairo_pixman_surface_unmap_image, - - _cairo_pixman_surface_source, - _cairo_pixman_surface_acquire_source_image, - _cairo_pixman_surface_release_source_image, - _cairo_pixman_surface_snapshot, - + cairo_pixman_surface_map_to_image, + cairo_pixman_surface_unmap_image, + + cairo_pixman_surface_source, + cairo_pixman_surface_acquire_source_image, + cairo_pixman_surface_release_source_image, + cairo_pixman_surface_snapshot, + NULL, /* copy_page */ NULL, /* show_page */ - - _cairo_pixman_surface_get_extents, - _cairo_pixman_surface_get_font_options, - + + cairo_pixman_surface_get_extents, + cairo_pixman_surface_get_font_options, + NULL, /* flush */ NULL, - - _cairo_pixman_surface_paint, - _cairo_pixman_surface_mask, - _cairo_pixman_surface_stroke, - _cairo_pixman_surface_fill, + + cairo_pixman_surface_paint, + cairo_pixman_surface_mask, + cairo_pixman_surface_stroke, + cairo_pixman_surface_fill, NULL, /* fill-stroke */ - _cairo_pixman_surface_glyphs, + cairo_pixman_surface_glyphs, }; -- cgit v1.2.3