[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