[cairo-commit] cairo/src cairo-array.c, 1.8, 1.9 cairo-meta-surface-private.h, 1.7, 1.8 cairo-meta-surface.c, 1.17, 1.18 cairo-ps-surface.c, 1.61, 1.62 cairo-surface.c, 1.112, 1.113 cairoint.h, 1.229, 1.230

Carl Worth commit at pdx.freedesktop.org
Wed Dec 7 12:19:12 PST 2005


Committed by: cworth

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv16041/src

Modified Files:
	cairo-array.c cairo-meta-surface-private.h 
	cairo-meta-surface.c cairo-ps-surface.c cairo-surface.c 
	cairoint.h 
Log Message:

2005-12-07  Carl Worth  <cworth at 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.


Index: cairo-array.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-array.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- cairo-array.c	7 Nov 2005 21:23:32 -0000	1.8
+++ cairo-array.c	7 Dec 2005 20:19:10 -0000	1.9
@@ -58,6 +58,29 @@
     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 @@
 void
 _cairo_array_fini (cairo_array_t *array)
 {
+    if (array->is_snapshot)
+	return;
+
     free (array->elements);
 }
 
@@ -88,6 +114,8 @@
     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 @@
 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_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_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_status_t status;
 
+    assert (! array->is_snapshot);
+
     status = _cairo_array_grow_by (array, num_elements);
     if (status)
 	return status;

Index: cairo-meta-surface-private.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-meta-surface-private.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- cairo-meta-surface-private.h	9 Nov 2005 01:16:21 -0000	1.7
+++ cairo-meta-surface-private.h	7 Dec 2005 20:19:10 -0000	1.8
@@ -179,13 +179,21 @@
 
 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);
 

Index: cairo-meta-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-meta-surface.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- cairo-meta-surface.c	9 Nov 2005 01:16:21 -0000	1.17
+++ cairo-meta-surface.c	7 Dec 2005 20:19:10 -0000	1.18
@@ -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_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 @@
 				    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_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++) {
@@ -150,6 +160,39 @@
 }
 
 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 @@
     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 @@
     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 @@
 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 @@
     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 @@
     _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)
 {

Index: cairo-ps-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ps-surface.c,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -d -r1.61 -r1.62
--- cairo-ps-surface.c	9 Nov 2005 01:43:14 -0000	1.61
+++ cairo-ps-surface.c	7 Dec 2005 20:19:10 -0000	1.62
@@ -106,7 +106,8 @@
     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 @@
     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 @@
 				       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 @@
     _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 @@
     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);
 

Index: cairo-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-surface.c,v
retrieving revision 1.112
retrieving revision 1.113
diff -u -d -r1.112 -r1.113
--- cairo-surface.c	9 Nov 2005 01:16:21 -0000	1.112
+++ cairo-surface.c	7 Dec 2005 20:19:10 -0000	1.113
@@ -581,7 +581,8 @@
 {
     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 @@
     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_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 @@
     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;

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.229
retrieving revision 1.230
diff -u -d -r1.229 -r1.230
--- cairoint.h	9 Nov 2005 01:43:14 -0000	1.229
+++ cairoint.h	7 Dec 2005 20:19:10 -0000	1.230
@@ -318,11 +318,17 @@
     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 @@
 				 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_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,



More information about the cairo-commit mailing list