[cairo-commit] 3 commits - src/cairo-base85-stream.c src/cairo-ps-surface.c test/cairo-test.c

Carl Worth cworth at kemper.freedesktop.org
Tue Apr 4 12:53:34 PDT 2006


 src/cairo-base85-stream.c |   30 ++------
 src/cairo-ps-surface.c    |  163 +++++++++++++++++++++++++++++++++++++++++-----
 test/cairo-test.c         |    1 
 3 files changed, 156 insertions(+), 38 deletions(-)

New commits:
diff-tree 45bbdf94cbac736c9f854012581e8f914a6e27df (from d1134cd7e25a78c70819df879336f895134bafe1)
Author: Carl Worth <cworth at raht.cworth.org>
Date:   Tue Apr 4 12:50:44 2006 -0700

    Break PostScript image data into chunks that each fit into a string.
    
    This solves the problem with the previous commit that made strings
    longer than the "standard" 65k implementation limit for strings.
    It's achieved by removing the line-wrapping from the base85 stream and
    instead adding a new string-array stream between the base85 stream and
    the output stream (the string-array stream does the line wrapping and
    enforces the 65k characters per string limit).

diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c
index 4ea94ea..bd1a7ac 100644
--- a/src/cairo-base85-stream.c
+++ b/src/cairo-base85-stream.c
@@ -40,7 +40,6 @@ typedef struct _cairo_base85_stream {
     cairo_output_stream_t *output;
     unsigned char four_tuple[4];
     int pending;
-    int column;
 } cairo_base85_stream_t;
 
 static void
@@ -63,15 +62,6 @@ _expand_four_tuple_to_five (unsigned cha
     }
 }
 
-static void
-_cairo_base85_wrap_perhaps (cairo_base85_stream_t *stream)
-{
-    if (stream->column >= 72) {
-	_cairo_output_stream_write (stream->output, "\n", 1);
-	stream->column = 0;
-    }
-}
-
 static cairo_status_t
 _cairo_base85_stream_write_data (void			*closure,
 				 const unsigned char	*data,
@@ -87,14 +77,10 @@ _cairo_base85_stream_write_data (void			
 	length--;
 	if (stream->pending == 4) {
 	    _expand_four_tuple_to_five (stream->four_tuple, five_tuple, &is_zero);
-	    if (is_zero) {
+	    if (is_zero)
 		_cairo_output_stream_write (stream->output, "z", 1);
-		stream->column += 1;
-	    } else {
+	    else
 		_cairo_output_stream_write (stream->output, five_tuple, 5);
-		stream->column += 5;
-	    }
-	    _cairo_base85_wrap_perhaps (stream);
 	    stream->pending = 0;
 	}
     }
@@ -105,6 +91,7 @@ _cairo_base85_stream_write_data (void			
 static cairo_status_t
 _cairo_base85_stream_close (void *closure)
 {
+    cairo_status_t status;
     cairo_base85_stream_t *stream = closure;
     unsigned char five_tuple[5];
 
@@ -112,14 +99,16 @@ _cairo_base85_stream_close (void *closur
 	memset (stream->four_tuple + stream->pending, 0, 4 - stream->pending);
 	_expand_four_tuple_to_five (stream->four_tuple, five_tuple, NULL);
 	_cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1);
-	stream->column += stream->pending + 1;
-	_cairo_base85_wrap_perhaps (stream);
     }
 
     /* Mark end of base85 data */
-    _cairo_output_stream_printf (stream->output, "~>\n");
+    _cairo_output_stream_printf (stream->output, "~>");
 
-    return _cairo_output_stream_get_status (stream->output);
+    status = _cairo_output_stream_get_status (stream->output);
+
+    free (stream);
+
+    return status;
 }
 
 cairo_output_stream_t *
@@ -133,7 +122,6 @@ _cairo_base85_stream_create (cairo_outpu
 
     stream->output = output;
     stream->pending = 0;
-    stream->column = 0;
 
     return _cairo_output_stream_create (_cairo_base85_stream_write_data,
 					_cairo_base85_stream_close,
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 11e346d..99a1021 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -655,6 +655,104 @@ pattern_operation_needs_fallback (cairo_
     return pattern_is_translucent (pattern);
 }
 
+/* The "standard" implementation limit for PostScript string sizes is
+ * 65535 characters (see PostScript Language Reference, Appendix
+ * B). We go one short of that because we sometimes need two
+ * characters in a string to represent a single ASCII85 byte, (for the
+ * escape sequences "\\", "\(", and "\)") and we must not split these
+ * across two strings. So we'd be in trouble if we went right to the
+ * limit and one of these escape sequences just happened to land at
+ * the end.
+ */
+#define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
+#define STRING_ARRAY_MAX_COLUMN	     72
+
+typedef struct _string_array_stream {
+    cairo_output_stream_t *output;
+    int column;
+    int string_size;
+} string_array_stream_t;
+
+static cairo_status_t
+_string_array_stream_write (void		*closure,
+			    const unsigned char	*data,
+			    unsigned int	 length)
+{
+    string_array_stream_t *stream = closure;
+    unsigned char c;
+    const unsigned char backslash = '\\';
+
+    if (length == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    while (length--) {
+	if (stream->string_size == 0) {
+	    _cairo_output_stream_printf (stream->output, "(");
+	    stream->column++;
+	}
+
+	c = *data++;
+	switch (c) {
+	case '\\':
+	case '(':
+	case ')':
+	    _cairo_output_stream_write (stream->output, &backslash, 1);
+	    stream->column++;
+	    stream->string_size++;
+	    break;
+	}
+	_cairo_output_stream_write (stream->output, &c, 1);
+	stream->column++;
+	stream->string_size++;
+
+	if (stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE) {
+	    _cairo_output_stream_printf (stream->output, ")\n");
+	    stream->string_size = 0;
+	    stream->column = 0;
+	}
+	if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
+	    _cairo_output_stream_printf (stream->output, "\n ");
+	    stream->string_size += 2;
+	    stream->column = 1;
+	}
+    }
+
+    return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_status_t
+_string_array_stream_close (void *closure)
+{
+    cairo_status_t status;
+    string_array_stream_t *stream = closure;
+
+    _cairo_output_stream_printf (stream->output, ")\n");
+
+    status = _cairo_output_stream_get_status (stream->output);
+
+    free (stream);
+
+    return status;
+}
+
+static cairo_output_stream_t *
+_string_array_stream_create (cairo_output_stream_t *output)
+{
+    string_array_stream_t *stream;
+
+    stream = malloc (sizeof (string_array_stream_t));
+    if (stream == NULL)
+	return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+    stream->output = output;
+    stream->column = 0;
+    stream->string_size = 0;
+
+    return _cairo_output_stream_create (_string_array_stream_write,
+					_string_array_stream_close,
+					stream);
+}
+
 /* PS Output - this section handles output of the parts of the meta
  * surface we can render natively in PS. */
 
@@ -683,7 +781,7 @@ emit_image (cairo_ps_surface_t    *surfa
     cairo_pattern_union_t pattern;
     cairo_matrix_t d2i;
     int x, y, i;
-    cairo_output_stream_t *base85_stream;
+    cairo_output_stream_t *base85_stream, *string_array_stream;
 
     /* PostScript can not represent the alpha channel, so we blend the
        current image over a white RGB surface to eliminate it. */
@@ -741,6 +839,8 @@ emit_image (cairo_ps_surface_t    *surfa
 	}
     }
 
+    /* XXX: Should fix cairo-lzw to provide a stream-based interface
+     * instead. */
     compressed_size = rgb_size;
     compressed = _cairo_lzw_compress (rgb, &compressed_size);
     if (compressed == NULL) {
@@ -751,22 +851,20 @@ emit_image (cairo_ps_surface_t    *surfa
     /* First emit the image data as a base85-encoded string which will
      * be used as the data source for the image operator later. */
     _cairo_output_stream_printf (surface->stream,
-				 "/%sData\n", name);
-    _cairo_output_stream_printf (surface->stream,
-				 "<~\n");
-    base85_stream = _cairo_base85_stream_create (surface->stream);
+				 "/%sData [\n", name);
 
-    _cairo_output_stream_write (base85_stream, compressed, compressed_size);
-    _cairo_output_stream_close (base85_stream);
+    string_array_stream = _string_array_stream_create (surface->stream);
+    base85_stream = _cairo_base85_stream_create (string_array_stream);
 
-    status = _cairo_output_stream_get_status (base85_stream);
-    if (status)
-	goto bail3;
+    _cairo_output_stream_write (base85_stream, compressed, compressed_size);
 
     _cairo_output_stream_destroy (base85_stream);
+    _cairo_output_stream_destroy (string_array_stream);
 
     _cairo_output_stream_printf (surface->stream,
-				 " def\n");
+				 "] def\n");
+    _cairo_output_stream_printf (surface->stream,
+				 "/%sDataIndex 0 def\n", name);
 
     /* matrix transforms from user space to image space.  We need to
      * transform from device space to image space to compensate for
@@ -783,7 +881,11 @@ emit_image (cairo_ps_surface_t    *surfa
 				 "	/Height %d\n"
 				 "	/BitsPerComponent 8\n"
 				 "	/Decode [ 0 1 0 1 0 1 ]\n"
-				 "	/DataSource %sData /LZWDecode filter \n"
+				 "	/DataSource {\n"
+				 "	    %sData %sDataIndex get\n"
+				 "	    /%sDataIndex %sDataIndex 1 add def\n"
+				 "	    %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
+				 "	} /ASCII85Decode filter /LZWDecode filter\n"
 				 "	/ImageMatrix [ %f %f %f %f %f %f ]\n"
 				 "    >>\n"
 				 "    image\n"
@@ -791,14 +893,13 @@ emit_image (cairo_ps_surface_t    *surfa
 				 name,
 				 opaque_image->width,
 				 opaque_image->height,
-				 name,
+				 name, name, name, name, name, name, name,
 				 d2i.xx, d2i.yx,
 				 d2i.xy, d2i.yy,
 				 d2i.x0, d2i.y0);
     _cairo_output_stream_printf (surface->stream,
 				 "%sImage\n", name);
 
- bail3:
     free (compressed);
  bail2:
     free (rgb);
diff-tree d1134cd7e25a78c70819df879336f895134bafe1 (from 0114393a132471cbf87bc3abc2f298b4ca38c69c)
Author: Carl Worth <cworth at raht.cworth.org>
Date:   Tue Apr 4 11:21:17 2006 -0700

    Emit images into PostScript output as strings rather than inline.
    
    This is a baby step toward having shared source patterns in the
    PostScript output. This patch is based on original work by Keith
    Packard in the following commit:
    
    	06b83b89fc4271060c63b284d7909162b92152f1
    
    One problem with this approach is that it attempts to put an entire
    image into a PostScript string object. However, PostScript strings are
    typically limited to 65k bytes. So, as is, this commit causes a few
    failures for tests in the suite with large output images.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 7689205..11e346d 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -663,6 +663,18 @@ emit_image (cairo_ps_surface_t    *surfa
 	    cairo_image_surface_t *image,
 	    cairo_matrix_t	  *matrix)
 {
+    /* Using a single name for all images is fine since we immediately
+     * use the image and never again reference it. Later calls will
+     * re-use the same name which will just store new image data under
+     * the same entries in the PostScript dictionaries.
+     *
+     * Eventually, we'll want to emit a shared image once into the
+     * PostScript output and re-use it. In order to do that, we'll
+     * need to support multiple images "in flight" at the same time,
+     * which means we'll need to have unique names here one way or
+     * another.
+     */
+    const char name[] = "Fallback";
     cairo_status_t status;
     unsigned char *rgb, *compressed;
     unsigned long rgb_size, compressed_size;
@@ -736,6 +748,26 @@ emit_image (cairo_ps_surface_t    *surfa
 	goto bail2;
     }
 
+    /* First emit the image data as a base85-encoded string which will
+     * be used as the data source for the image operator later. */
+    _cairo_output_stream_printf (surface->stream,
+				 "/%sData\n", name);
+    _cairo_output_stream_printf (surface->stream,
+				 "<~\n");
+    base85_stream = _cairo_base85_stream_create (surface->stream);
+
+    _cairo_output_stream_write (base85_stream, compressed, compressed_size);
+    _cairo_output_stream_close (base85_stream);
+
+    status = _cairo_output_stream_get_status (base85_stream);
+    if (status)
+	goto bail3;
+
+    _cairo_output_stream_destroy (base85_stream);
+
+    _cairo_output_stream_printf (surface->stream,
+				 " def\n");
+
     /* matrix transforms from user space to image space.  We need to
      * transform from device space to image space to compensate for
      * postscripts coordinate system. */
@@ -743,32 +775,28 @@ emit_image (cairo_ps_surface_t    *surfa
     cairo_matrix_multiply (&d2i, &d2i, matrix);
 
     _cairo_output_stream_printf (surface->stream,
-				 "/DeviceRGB setcolorspace\n"
-				 "<<\n"
+				 "/%sImage {\n"
+				 "    /DeviceRGB setcolorspace\n"
+				 "    <<\n"
 				 "	/ImageType 1\n"
 				 "	/Width %d\n"
 				 "	/Height %d\n"
 				 "	/BitsPerComponent 8\n"
 				 "	/Decode [ 0 1 0 1 0 1 ]\n"
-				 "	/DataSource currentfile /ASCII85Decode filter /LZWDecode filter \n"
+				 "	/DataSource %sData /LZWDecode filter \n"
 				 "	/ImageMatrix [ %f %f %f %f %f %f ]\n"
-				 ">>\n"
-				 "image\n",
+				 "    >>\n"
+				 "    image\n"
+				 "} def\n",
+				 name,
 				 opaque_image->width,
 				 opaque_image->height,
+				 name,
 				 d2i.xx, d2i.yx,
 				 d2i.xy, d2i.yy,
 				 d2i.x0, d2i.y0);
-
-    /* Compressed image data (Base85 encoded) */
-    base85_stream = _cairo_base85_stream_create (surface->stream);
-
-    _cairo_output_stream_write (base85_stream, compressed, compressed_size);
-    _cairo_output_stream_close (base85_stream);
-
-    status = _cairo_output_stream_get_status (base85_stream);
-
-    _cairo_output_stream_destroy (base85_stream);
+    _cairo_output_stream_printf (surface->stream,
+				 "%sImage\n", name);
 
  bail3:
     free (compressed);
diff-tree 0114393a132471cbf87bc3abc2f298b4ca38c69c (from dd67cf6616c2e819e7e8e4452c1e14e68b4a66bd)
Author: Carl Worth <cworth at raht.cworth.org>
Date:   Tue Apr 4 11:17:25 2006 -0700

    Explicitly remove the output png image before creating it during testing.
    
    What was happening here is that some backends (such as the PS surface
    backend) directly generate an output file, and then run a conversion
    process to generate the png file. Some bugs were such that a broken
    file would successfully be generated, the conversion would fail (the
    failure was unnoticed), and the test suite would happily verify the
    old image from a previously successful run.
    
    This fix eliminates this source of false positives.

diff --git a/test/cairo-test.c b/test/cairo-test.c
index d782a92..928ab63 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -1440,6 +1440,7 @@ cairo_test_for_target (cairo_test_t *tes
     /* Skip image check for tests with no image (width,height == 0,0) */
     if (test->width != 0 && test->height != 0) {
 	int pixels_changed;
+	xunlink (png_name);
 	(target->write_to_png) (surface, png_name);
 	if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
 	    pixels_changed = image_diff_flattened (png_name, ref_name, diff_name);


More information about the cairo-commit mailing list