Note that self-copy now works with the PS backend.

Add _cairo_array_init_snapshot and checks for is_snapshot throughout.
Add a new surface->backend->snapshot function.
Implement _cairo_meta_surface_snapshot and _cairo_meta_surface_acquire/release_source_image. Change _cairo_meta_surface_create to require the width and height in pixels to be used when replaying for purposed of _cairo_meta_surface_aquire_source_image.
Track change in prototype of _cairo_meta_surface_create. Implement _cairo_ps_surface_snapshot by deferring down into _cairo_meta_surface_snapshot.
This commit is contained in:
Carl Worth 2005-12-07 12:19:10 +00:00
parent 96be55124f
commit 964c56e72b
8 changed files with 257 additions and 36 deletions

View file

@ -1,3 +1,38 @@
2005-12-07 Carl Worth <cworth@cworth.org>
* ROADMAP: Note that self-copy now works with the PS backend.
* src/cairo-array.c: (_cairo_array_init),
(_cairo_array_init_snapshot), (_cairo_array_fini),
(_cairo_array_grow_by), (_cairo_array_truncate),
(_cairo_array_append), (_cairo_array_append_multiple),
(_cairo_array_allocate): Add _cairo_array_init_snapshot and checks
for is_snapshot throughout.
* src/cairoint.h:
* src/cairo-surface.c: (_cairo_surface_acquire_source_image),
(_fallback_snapshot), (_cairo_surface_snapshot): Add a new
surface->backend->snapshot function.
* src/cairo-meta-surface-private.h:
* src/cairo-meta-surface.c: (_cairo_meta_surface_create),
(_cairo_meta_surface_create_similar), (_cairo_meta_surface_finish),
(_cairo_meta_surface_acquire_source_image),
(_cairo_meta_surface_release_source_image),
(_cairo_meta_surface_snapshot), (_cairo_meta_surface_get_extents):
Implement _cairo_meta_surface_snapshot and
_cairo_meta_surface_acquire/release_source_image. Change
_cairo_meta_surface_create to require the width and height in
pixels to be used when replaying for purposed of
_cairo_meta_surface_aquire_source_image.
* src/cairo-ps-surface.c:
(_cairo_ps_surface_create_for_stream_internal),
(_cairo_ps_surface_show_page), (_cairo_ps_surface_snapshot),
(_ps_output_old_show_glyphs): Track change in prototype of
_cairo_meta_surface_create. Implement _cairo_ps_surface_snapshot
by deferring down into _cairo_meta_surface_snapshot.
2005-12-07 Carl Worth <cworth@cworth.org>
* test/cairo-test.c: (create_ps_surface): Fix to check

View file

@ -11,17 +11,17 @@ The release won't happen without these being complete.
========================================================
A. PS backend
----------
1. Mark PS backend as supported:
1. Mark PS backend as supported:
✓a. Incorporate into test suite
b. Correct output for the entire test suite
b. Correct output for the entire test suite
✓clip-operator
✓composite-integer-translate-source
✓linear-gradient
✓operator-clear
✓operator-source
self-copy
self-copy
✓text-pattern
✓trap-clip
✓unbounded-operator

View file

@ -58,6 +58,29 @@ _cairo_array_init (cairo_array_t *array, int element_size)
array->num_elements = 0;
array->element_size = element_size;
array->elements = NULL;
array->is_snapshot = FALSE;
}
/**
* _cairo_array_init_snapshot:
* @array: A #cairo_array_t to be initialized as a snapshot
* @other: The #cairo_array_t from which to create the snapshot
*
* Initialize @array as an immutable copy of @other. It is an error to
* call an array-modifying function (other than _cairo_array_fini) on
* @array after calling this function.
**/
void
_cairo_array_init_snapshot (cairo_array_t *array,
const cairo_array_t *other)
{
array->size = other->size;
array->num_elements = other->num_elements;
array->element_size = other->element_size;
array->elements = other->elements;
array->is_snapshot = TRUE;
}
/**
@ -70,6 +93,9 @@ _cairo_array_init (cairo_array_t *array, int element_size)
void
_cairo_array_fini (cairo_array_t *array)
{
if (array->is_snapshot)
return;
free (array->elements);
}
@ -88,6 +114,8 @@ _cairo_array_grow_by (cairo_array_t *array, int additional)
int required_size = array->num_elements + additional;
int new_size;
assert (! array->is_snapshot);
if (required_size <= old_size)
return CAIRO_STATUS_SUCCESS;
@ -123,6 +151,8 @@ _cairo_array_grow_by (cairo_array_t *array, int additional)
void
_cairo_array_truncate (cairo_array_t *array, int num_elements)
{
assert (! array->is_snapshot);
if (num_elements < array->num_elements)
array->num_elements = num_elements;
}
@ -184,6 +214,8 @@ cairo_status_t
_cairo_array_append (cairo_array_t *array,
const void *element)
{
assert (! array->is_snapshot);
return _cairo_array_append_multiple (array, element, 1);
}
@ -206,6 +238,8 @@ _cairo_array_append_multiple (cairo_array_t *array,
cairo_status_t status;
void *dest;
assert (! array->is_snapshot);
status = _cairo_array_allocate (array, num_elements, &dest);
if (status)
return status;
@ -234,6 +268,8 @@ _cairo_array_allocate (cairo_array_t *array,
{
cairo_status_t status;
assert (! array->is_snapshot);
status = _cairo_array_grow_by (array, num_elements);
if (status)
return status;

View file

@ -179,13 +179,21 @@ typedef union _cairo_command {
typedef struct _cairo_meta_surface {
cairo_surface_t base;
/* A meta-surface is logically unbounded, but when used as a
* source we need to render it to an image, so we need a size at
* which to create that image. */
int width_pixels;
int height_pixels;
cairo_array_t commands;
cairo_surface_t *commands_owner;
} cairo_meta_surface_t;
cairo_private cairo_surface_t *
_cairo_meta_surface_create (void);
_cairo_meta_surface_create (int width_pixels, int height_pixels);
cairo_private cairo_int_status_t
cairo_private cairo_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);

View file

@ -41,7 +41,7 @@
static const cairo_surface_backend_t cairo_meta_surface_backend;
cairo_surface_t *
_cairo_meta_surface_create (void)
_cairo_meta_surface_create (int width_pixels, int height_pixels)
{
cairo_meta_surface_t *meta;
@ -52,7 +52,12 @@ _cairo_meta_surface_create (void)
}
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend);
meta->width_pixels = width_pixels;
meta->height_pixels = height_pixels;
_cairo_array_init (&meta->commands, sizeof (cairo_command_t *));
meta->commands_owner = NULL;
return &meta->base;
}
@ -63,7 +68,7 @@ _cairo_meta_surface_create_similar (void *abstract_surface,
int width,
int height)
{
return _cairo_meta_surface_create ();
return _cairo_meta_surface_create (width, height);
}
static cairo_status_t
@ -74,6 +79,11 @@ _cairo_meta_surface_finish (void *abstract_surface)
cairo_command_t **elements;
int i, num_elements;
if (meta->commands_owner) {
cairo_surface_destroy (meta->commands_owner);
return CAIRO_STATUS_SUCCESS;
}
num_elements = meta->commands.num_elements;
elements = (cairo_command_t **) meta->commands.elements;
for (i = 0; i < num_elements; i++) {
@ -149,6 +159,39 @@ _cairo_meta_surface_finish (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_meta_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_status_t status;
cairo_meta_surface_t *surface = abstract_surface;
cairo_surface_t *image;
image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
surface->width_pixels,
surface->height_pixels);
status = _cairo_meta_surface_replay (&surface->base, image);
if (status) {
cairo_surface_destroy (image);
return status;
}
*image_out = (cairo_image_surface_t *) image;
*image_extra = NULL;
return status;
}
static void
_cairo_meta_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
cairo_surface_destroy (&image->base);
}
static cairo_status_t
_init_pattern_with_snapshot (cairo_pattern_t *pattern,
const cairo_pattern_t *other)
@ -397,6 +440,43 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
return status;
}
/**
* _cairo_meta_surface_snapshot
* @surface: a #cairo_surface_t which must be a meta surface
*
* Make an immutable copy of @surface. It is an error to call a
* surface-modifying function on the result of this function.
*
* The caller owns the return value and should call
* cairo_surface_destroy when finished with it. This function will not
* return NULL, but will return a nil surface instead.
*
* Return value: The snapshot surface.
**/
static cairo_surface_t *
_cairo_meta_surface_snapshot (void *abstract_other)
{
cairo_meta_surface_t *other = abstract_other;
cairo_meta_surface_t *meta;
meta = malloc (sizeof (cairo_meta_surface_t));
if (meta == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil;
}
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend);
meta->base.is_snapshot = TRUE;
meta->width_pixels = other->width_pixels;
meta->height_pixels = other->height_pixels;
_cairo_array_init_snapshot (&meta->commands, &other->commands);
meta->commands_owner = cairo_surface_reference (&other->base);
return &meta->base;
}
static cairo_int_status_t
_cairo_meta_surface_composite (cairo_operator_t operator,
cairo_pattern_t *src_pattern,
@ -594,6 +674,26 @@ _cairo_meta_surface_intersect_clip_path (void *dst,
return CAIRO_STATUS_SUCCESS;
}
/* A meta-surface is logically unbounded, but when it is used as a
* source, the drawing code can optimize based on the extents of the
* surface.
*
* XXX: The optimization being attempted here would only actually work
* if the meta-surface kept track of its extents as commands were
* added to it.
*/
static cairo_int_status_t
_cairo_meta_surface_get_extents (void *abstract_surface,
cairo_rectangle_t *rectangle)
{
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = CAIRO_MAXSHORT;
rectangle->height = CAIRO_MAXSHORT;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_surface_is_meta:
* @surface: a #cairo_surface_t
@ -611,8 +711,8 @@ _cairo_surface_is_meta (const cairo_surface_t *surface)
static const cairo_surface_backend_t cairo_meta_surface_backend = {
_cairo_meta_surface_create_similar,
_cairo_meta_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
_cairo_meta_surface_acquire_source_image,
_cairo_meta_surface_release_source_image,
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
@ -623,7 +723,7 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_meta_surface_intersect_clip_path,
NULL, /* get_extents */
_cairo_meta_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
@ -639,10 +739,12 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
_cairo_meta_surface_mask,
_cairo_meta_surface_stroke,
_cairo_meta_surface_fill,
_cairo_meta_surface_show_glyphs
_cairo_meta_surface_show_glyphs,
_cairo_meta_surface_snapshot
};
cairo_int_status_t
cairo_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target)
{

View file

@ -106,7 +106,8 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->base.device_x_scale = surface->x_dpi / 72.0;
surface->base.device_y_scale = surface->y_dpi / 72.0;
surface->current_page = _cairo_meta_surface_create ();
surface->current_page = _cairo_meta_surface_create (width * surface->x_dpi / 72,
height * surface->y_dpi / 72);
if (surface->current_page->status) {
free (surface);
_cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -343,7 +344,8 @@ _cairo_ps_surface_show_page (void *abstract_surface)
if (status)
return status;
surface->current_page = _cairo_meta_surface_create ();
surface->current_page = _cairo_meta_surface_create (surface->width * surface->x_dpi / 72,
surface->height * surface->y_dpi / 72);
if (surface->current_page->status)
return CAIRO_STATUS_NO_MEMORY;
@ -549,6 +551,16 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
scaled_font);
}
static cairo_surface_t *
_cairo_ps_surface_snapshot (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
assert (_cairo_surface_is_meta (surface->current_page));
return _cairo_surface_snapshot (surface->current_page);
}
static const cairo_surface_backend_t cairo_ps_surface_backend = {
NULL, /* create_similar */
_cairo_ps_surface_finish,
@ -578,7 +590,9 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_mask,
_cairo_ps_surface_stroke,
_cairo_ps_surface_fill,
_cairo_ps_surface_show_glyphs
_cairo_ps_surface_show_glyphs,
_cairo_ps_surface_snapshot
};
static cairo_int_status_t
@ -1400,6 +1414,9 @@ _ps_output_old_show_glyphs (cairo_scaled_font_t *scaled_font,
if (! _cairo_scaled_font_is_ft (scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->fallback)
return CAIRO_STATUS_SUCCESS;
if (pattern_operation_needs_fallback (operator, pattern))
return _ps_output_add_fallback_area (surface, dest_x, dest_y, width, height);

View file

@ -581,7 +581,8 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface,
{
assert (!surface->finished);
return surface->backend->acquire_source_image (surface, image_out, image_extra);
return surface->backend->acquire_source_image (surface,
image_out, image_extra);
}
/**
@ -722,21 +723,11 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
return status;
}
/**
* _cairo_surface_snapshot
* @surface: a #cairo_surface_t
* @snapshot_out: return value surface---not necessarily of the same type as @surface
*
* Make an immutable copy of @surface. It is an error to call a
* surface-modifying function on the result of this function.
*
* The caller owns the return value and should call
* cairo_surface_destroy when finished with it. This function will not
* return NULL, but will return a nil surface instead.
**/
cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface)
/* XXX: Shouldn't really need to do this here. */
#include "cairo-meta-surface-private.h"
static cairo_surface_t *
_fallback_snapshot (cairo_surface_t *surface)
{
cairo_surface_t *snapshot;
cairo_status_t status;
@ -744,12 +735,6 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
cairo_image_surface_t *image;
void *image_extra;
if (surface->finished)
return (cairo_surface_t *) &_cairo_surface_nil;
/* XXX: Will need to do something very different here to snapshot
* a meta-surface. */
status = _cairo_surface_acquire_source_image (surface,
&image, &image_extra);
if (status != CAIRO_STATUS_SUCCESS)
@ -783,6 +768,32 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
return snapshot;
}
/**
* _cairo_surface_snapshot
* @surface: a #cairo_surface_t
*
* Make an immutable copy of @surface. It is an error to call a
* surface-modifying function on the result of this function.
*
* The caller owns the return value and should call
* cairo_surface_destroy when finished with it. This function will not
* return NULL, but will return a nil surface instead.
*
* Return value: The snapshot surface. Note that the return surface
* may not necessarily be of the same type as @surface.
**/
cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface)
{
if (surface->finished)
return (cairo_surface_t *) &_cairo_surface_nil;
if (surface->backend->snapshot)
return surface->backend->snapshot (surface);
return _fallback_snapshot (surface);
}
typedef struct {
cairo_surface_t *dst;
cairo_rectangle_t extents;

View file

@ -318,11 +318,17 @@ struct _cairo_array {
int num_elements;
int element_size;
char *elements;
cairo_bool_t is_snapshot;
};
cairo_private void
_cairo_array_init (cairo_array_t *array, int element_size);
void
_cairo_array_init_snapshot (cairo_array_t *array,
const cairo_array_t *other);
cairo_private void
_cairo_array_fini (cairo_array_t *array);
@ -790,6 +796,9 @@ struct _cairo_surface_backend {
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
cairo_surface_t *
(*snapshot) (void *surface);
};
typedef struct _cairo_format_masks {
@ -1843,6 +1852,9 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
cairo_private cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface);
cairo_private cairo_bool_t
_cairo_surface_is_meta (const cairo_surface_t *surface);
/* cairo_pen.c */
cairo_private cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,