[cairo] [PATCH] PS/PDF improve efficiency of text output

Adrian Johnson ajohnson at redneon.com
Sat Sep 23 09:55:48 PDT 2006


The PDF and PS backends are very inefficient at printing text. These
patches remove some of the redundancy and help to reduce the size of the
PS and PDF files generated by cairo.

The first patch makes the PS show glyphs function look for strings of
glyphs from the same subset and use either the xshow, yshow, or xyshow
PS operator to print the glyphs depending on whether the glyphs are
horizontal, vertical, or neither.

The PDF show glyphs function emits the text matrix for every glyph
displayed as this is the only way to specify an absolute position.
There is a 'x y Td' PDF operator that multiplies the text matrix by a
translation matrix created from the x and y operands. The second patch
will, for the simple case where the text matrix is a diagonal matrix,
use the Td operator for positioning glyphs.

The third patch adds a new stream filter type that compresses the stream
using the zlib deflate method.

The fourth patch uses the deflate stream in the PDF backend when
emitting the content stream. This could be further extended to compress
all PDF streams including replacing the compress_dup() function with the
deflate stream.

Testing the PDF backend with a paragraph of text showed that currently
the content stream averages 45 bytes per glyph. These patches reduce
that to an average of 1.6 bytes per glyph.

I mentioned previously that I am getting a large number of make test
failures despite trying different library versions. How do I resolve
this apparent conflict between "don't commit until make test passes" and
the inability to get make test to pass for the latest git master on my
machine?

-------------- next part --------------
>From 6bcc67f1df6d4301e616fa6d4711c73fd4c5795e Mon Sep 17 00:00:00 2001
From: Adrian Johnson <ajohnson at redneon.com>
Date: Sun, 24 Sep 2006 00:46:43 +0930
Subject: [PATCH] PS: Use xshow/yshow/xyshow for strings of glyphs

Optimize show glyphs by looking for strings of glyphs from the same subset
and use the xyshow operator to display. As a further optimization the xshow
and yshow operators are used for displaying horizontal and vertical text.
---
 src/cairo-ps-surface.c |   97 +++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 86 insertions(+), 11 deletions(-)

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 7403b0e..d9c5d9c 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -2089,6 +2089,15 @@ _cairo_ps_surface_fill (void		*abstract_
     return status;
 }
 
+/* This size keeps the length of the hex encoded string of glyphs
+ * within 80 columns. */
+#define MAX_GLYPHS_PER_SHOW  36
+
+typedef struct _cairo_ps_glyph_id {
+    unsigned int subset_id;
+    unsigned int glyph_id;
+} cairo_ps_glyph_id_t;
+
 static cairo_int_status_t
 _cairo_ps_surface_show_glyphs (void		     *abstract_surface,
 			       cairo_operator_t	      op,
@@ -2100,9 +2109,12 @@ _cairo_ps_surface_show_glyphs (void		   
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     unsigned int current_subset_id = -1;
-    unsigned int font_id, subset_id, subset_glyph_index;
+    unsigned int font_id;
+    cairo_ps_glyph_id_t *glyph_ids;
     cairo_status_t status;
-    int i;
+    int i, j, last, end;
+    cairo_bool_t vertical, horizontal;
+    cairo_output_stream_t *word_wrap;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _analyze_operation (surface, op, source);
@@ -2114,35 +2126,98 @@ _cairo_ps_surface_show_glyphs (void		   
 
     if (num_glyphs)
 	emit_pattern (surface, source, 0, 0);
+    else
+        return CAIRO_STATUS_SUCCESS;
+
+    glyph_ids = malloc (num_glyphs*sizeof(cairo_ps_glyph_id_t));
+    if (glyph_ids == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
 
     for (i = 0; i < num_glyphs; i++) {
 	status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
 						       scaled_font, glyphs[i].index,
-						       &font_id, &subset_id, &subset_glyph_index);
+						       &font_id,
+                                                       &(glyph_ids[i].subset_id),
+                                                       &(glyph_ids[i].glyph_id));
 	if (status)
-	    return status;
+	    goto fail;
+    }
 
-	if (subset_id != current_subset_id) {
+    i = 0;
+    while (i < num_glyphs) {
+        if (glyph_ids[i].subset_id != current_subset_id) {
 	    _cairo_output_stream_printf (surface->stream,
 					 "/CairoFont-%d-%d findfont\n"
 					 "[ %f %f %f %f 0 0 ] makefont\n"
 					 "setfont\n",
 					 font_id,
-					 subset_id,
+					 glyph_ids[i].subset_id,
 					 scaled_font->scale.xx,
 					 scaled_font->scale.yx,
 					 -scaled_font->scale.xy,
 					 -scaled_font->scale.yy);
-	    current_subset_id = subset_id;
+	    current_subset_id = glyph_ids[i].subset_id;
 	}
 
-	_cairo_output_stream_printf (surface->stream,
-				     "%f %f M <%02x> S\n",
-				     glyphs[i].x, glyphs[i].y,
-				     subset_glyph_index);
+        _cairo_output_stream_printf (stream, "%f %f M\n",  glyphs[i].x, glyphs[i].y);
+
+        horizontal = TRUE;
+        vertical = TRUE;
+        end = num_glyphs;
+        if (end - i > MAX_GLYPHS_PER_SHOW)
+            end = i + MAX_GLYPHS_PER_SHOW;
+        last = end - 1;
+        for (j = i; j < end - 1; j++) {
+            if ((glyphs[j].y != glyphs[j + 1].y))
+                horizontal = FALSE;
+            if ((glyphs[j].x != glyphs[j + 1].x))
+                vertical = FALSE;
+            if (glyph_ids[j].subset_id != glyph_ids[j + 1].subset_id) {
+                last = j;
+                break;
+            }
+        }
+
+        if (i == last) {
+            _cairo_output_stream_printf (surface->stream, "<%02x> S\n", glyph_ids[i].glyph_id);
+        } else {
+            word_wrap = _word_wrap_stream_create (surface->stream, 79);
+            _cairo_output_stream_printf (word_wrap, "<");
+            for (j = i; j <= last; j++)
+                _cairo_output_stream_printf (word_wrap, "%02x", glyph_ids[j].glyph_id);
+            _cairo_output_stream_printf (word_wrap, ">\n[");
+
+            for (j = i + 1; j <= last; j++) {
+                if (horizontal) {
+                    _cairo_output_stream_printf (word_wrap,
+                                                 "%f ", glyphs[j].x - glyphs[j - 1].x);
+                } else if (vertical) {
+                    _cairo_output_stream_printf (word_wrap,
+                                                 "%f ", glyphs[j].y - glyphs[j - 1].y);
+                } else {
+                    _cairo_output_stream_printf (word_wrap,
+                                                 "%f %f ",
+                                                 glyphs[j].x - glyphs[j - 1].x,
+                                                 glyphs[j].y - glyphs[j - 1].y);
+                }
+            }
+            if (horizontal)
+                _cairo_output_stream_printf (word_wrap, "] xshow\n");
+            else if (vertical)
+                _cairo_output_stream_printf (word_wrap, "] yshow\n");
+            else
+                _cairo_output_stream_printf (word_wrap, "] xyshow\n");
+            _cairo_output_stream_destroy (word_wrap);
+        }
+        i = last + 1;
     }
 
+    free (glyph_ids);
     return _cairo_output_stream_get_status (surface->stream);
+
+fail:
+    free (glyph_ids);
+    return status;
 }
 
 static void
-- 
1.4.2

-------------- next part --------------
>From 406b480cfecdd46580dc70b3e4c5ca78c830a402 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <ajohnson at redneon.com>
Date: Sun, 24 Sep 2006 00:48:36 +0930
Subject: [PATCH] PDF: Use Td where possible instead of Tm for positioning glyphs

This avoids emitting the font matrix for every single glyph.
---
 src/cairo-pdf-surface.c |   38 ++++++++++++++++++++++++++------------
 1 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 6106284..e14c50c 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2618,6 +2618,7 @@ _cairo_pdf_surface_show_glyphs (void			*
     cairo_pdf_surface_t *surface = abstract_surface;
     unsigned int current_subset_id = (unsigned int)-1;
     unsigned int font_id, subset_id, subset_glyph_index;
+    cairo_bool_t diagonal;
     cairo_status_t status;
     int i;
 
@@ -2633,6 +2634,12 @@ _cairo_pdf_surface_show_glyphs (void			*
     _cairo_output_stream_printf (surface->output,
 				 "BT\r\n");
 
+    if (scaled_font->scale.xy == 0.0 &&
+        scaled_font->scale.yx == 0.0)
+        diagonal = TRUE;
+    else
+        diagonal = FALSE;
+
     for (i = 0; i < num_glyphs; i++) {
 	status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
 						       scaled_font, glyphs[i].index,
@@ -2640,22 +2647,29 @@ _cairo_pdf_surface_show_glyphs (void			*
 	if (status)
 	    return status;
 
-	if (subset_id != current_subset_id) {
+	if (subset_id != current_subset_id)
 	    _cairo_output_stream_printf (surface->output,
 					 "/CairoFont-%d-%d 1 Tf\r\n",
 					 font_id, subset_id);
-	    current_subset_id = subset_id;
-	}
 
-	_cairo_output_stream_printf (surface->output,
-				     "%f %f %f %f %f %f Tm <%02x> Tj\r\n",
-				     scaled_font->scale.xx,
-				     scaled_font->scale.yx,
-				     -scaled_font->scale.xy,
-				     -scaled_font->scale.yy,
-				     glyphs[i].x,
-				     glyphs[i].y,
-				     subset_glyph_index);
+        if (subset_id != current_subset_id || !diagonal) {
+            _cairo_output_stream_printf (surface->output,
+                                         "%f %f %f %f %f %f Tm <%02x> Tj\r\n",
+                                         scaled_font->scale.xx,
+                                         scaled_font->scale.yx,
+                                         -scaled_font->scale.xy,
+                                         -scaled_font->scale.yy,
+                                         glyphs[i].x,
+                                         glyphs[i].y,
+                                         subset_glyph_index);
+	    current_subset_id = subset_id;
+        } else {
+            _cairo_output_stream_printf (surface->output,
+                                         "%f %f Td <%02x> Tj\r\n",
+                                         (glyphs[i].x - glyphs[i-1].x)/scaled_font->scale.xx,
+                                         (glyphs[i].y - glyphs[i-1].y)/scaled_font->scale.yy,
+                                         subset_glyph_index);
+        }
     }
 
     _cairo_output_stream_printf (surface->output,
-- 
1.4.2

-------------- next part --------------
>From f2b27cea6a1e610c957e00d7907641467ac6e705 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <ajohnson at redneon.com>
Date: Sun, 24 Sep 2006 00:52:01 +0930
Subject: [PATCH] Add cairo-deflate-stream.c

Add a new stream type that compresses the stream using the zlib deflate method.
This is intended for use by the PDF surface.
---
 src/Makefile.am                   |    1 
 src/cairo-deflate-stream.c        |  142 +++++++++++++++++++++++++++++++++++++
 src/cairo-output-stream-private.h |    4 +
 3 files changed, 147 insertions(+), 0 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index a0e30ee..ae4301f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -175,6 +175,7 @@ libcairo_la_SOURCES =				\
 	cairo-clip-private.h			\
 	cairo-color.c				\
 	cairo-debug.c				\
+	cairo-deflate-stream.c			\
 	cairo-fixed.c				\
 	cairo-font.c				\
 	cairo-font-options.c			\
diff --git a/src/cairo-deflate-stream.c b/src/cairo-deflate-stream.c
new file mode 100644
index 0000000..816f5c5
--- /dev/null
+++ b/src/cairo-deflate-stream.c
@@ -0,0 +1,142 @@
+/* cairo_deflate_stream.c: Output stream abstraction
+ *
+ * Copyright © 2006 Adrian Johnson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is cairo_output_stream.c as distributed with the
+ *   cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Adrian Johnson.
+ *
+ * Author(s):
+ *	Adrian Johnson <ajohnson at redneon.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-output-stream-private.h"
+#include <zlib.h>
+
+#define BUFFER_SIZE 16384
+
+typedef struct _cairo_deflate_stream {
+    cairo_output_stream_t  base;
+    cairo_output_stream_t *output;
+    z_stream               zlib_stream;
+    unsigned char          input_buf[BUFFER_SIZE];
+    unsigned char          output_buf[BUFFER_SIZE];
+} cairo_deflate_stream_t;
+
+static void
+cairo_deflate_stream_deflate (cairo_deflate_stream_t *stream, cairo_bool_t flush)
+{
+    int ret;
+    cairo_bool_t finished;
+
+    do {
+        ret = deflate (&stream->zlib_stream, flush ? Z_FINISH : Z_NO_FLUSH);
+        if (flush || stream->zlib_stream.avail_out == 0)
+        {
+            _cairo_output_stream_write (stream->output,
+                                        stream->output_buf,
+                                        BUFFER_SIZE - stream->zlib_stream.avail_out);
+            stream->zlib_stream.next_out = stream->output_buf;
+            stream->zlib_stream.avail_out = BUFFER_SIZE;
+        }
+
+        finished = TRUE;
+        if (stream->zlib_stream.avail_in != 0)
+            finished = FALSE;
+        if (flush && ret != Z_STREAM_END)
+            finished = FALSE;
+
+    } while (!finished);
+
+    stream->zlib_stream.next_in = stream->input_buf;
+}
+
+static cairo_status_t
+_cairo_deflate_stream_write (cairo_output_stream_t *base,
+                             const unsigned char   *data,
+                             unsigned int	    length)
+{
+    cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
+    unsigned int count;
+    const unsigned char *p = data;
+
+    while (length) {
+        count = length;
+        if (count > BUFFER_SIZE - stream->zlib_stream.avail_in)
+            count = BUFFER_SIZE - stream->zlib_stream.avail_in;
+        memcpy (stream->input_buf + stream->zlib_stream.avail_in, p, count);
+        p += count;
+        stream->zlib_stream.avail_in += count;
+        length -= count;
+
+        if (stream->zlib_stream.avail_in == BUFFER_SIZE)
+            cairo_deflate_stream_deflate (stream, FALSE);
+    }
+
+    return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_status_t
+_cairo_deflate_stream_close (cairo_output_stream_t *base)
+{
+    cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
+
+    cairo_deflate_stream_deflate (stream, TRUE);
+    deflateEnd (&stream->zlib_stream);
+
+    return _cairo_output_stream_get_status (stream->output);
+}
+
+cairo_output_stream_t *
+_cairo_deflate_stream_create (cairo_output_stream_t *output)
+{
+    cairo_deflate_stream_t *stream;
+
+    stream = malloc (sizeof (cairo_deflate_stream_t));
+    if (stream == NULL)
+	return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+    _cairo_output_stream_init (&stream->base,
+			       _cairo_deflate_stream_write,
+			       _cairo_deflate_stream_close);
+    stream->output = output;
+
+    stream->zlib_stream.zalloc = Z_NULL;
+    stream->zlib_stream.zfree  = Z_NULL;
+    stream->zlib_stream.opaque  = Z_NULL;
+
+    if (deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
+	return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+    stream->zlib_stream.next_in = stream->input_buf;
+    stream->zlib_stream.avail_in = 0;
+    stream->zlib_stream.next_out = stream->output_buf;
+    stream->zlib_stream.avail_out = BUFFER_SIZE;
+
+    return &stream->base;
+}
diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index 913fb60..d68fbb4 100644
--- a/src/cairo-output-stream-private.h
+++ b/src/cairo-output-stream-private.h
@@ -159,4 +159,8 @@ _cairo_memory_stream_length (cairo_outpu
 cairo_private cairo_output_stream_t *
 _cairo_base85_stream_create (cairo_output_stream_t *output);
 
+/* cairo_deflate_stream.c */
+cairo_private cairo_output_stream_t *
+_cairo_deflate_stream_create (cairo_output_stream_t *output);
+
 #endif /* CAIRO_OUTPUT_STREAM_PRIVATE_H */
-- 
1.4.2

-------------- next part --------------
>From ab2caf88477caec8f4219589bd1f2311d5a5ea15 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <ajohnson at redneon.com>
Date: Sun, 24 Sep 2006 00:55:20 +0930
Subject: [PATCH] PDF: Compress the content stream

Use cairo-deflate-stream to compress all content streams emitted by the
PDF surface.
---
 src/cairo-pdf-surface.c |   32 +++++++++++++++++++++++++++++---
 1 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index e14c50c..ea22686 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -129,6 +129,8 @@ typedef struct _cairo_pdf_surface {
 	cairo_pdf_resource_t self;
 	cairo_pdf_resource_t length;
 	long start_offset;
+        cairo_bool_t compressed;
+        cairo_output_stream_t *old_output;
     } current_stream;
 
     cairo_bool_t has_clip;
@@ -146,8 +148,9 @@ _cairo_pdf_surface_clear (cairo_pdf_surf
 
 static cairo_pdf_resource_t
 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
+                                cairo_bool_t             compressed,
 				const char		*fmt,
-				...) CAIRO_PRINTF_FORMAT(2, 3);
+				...) CAIRO_PRINTF_FORMAT(3, 4);
 static void
 _cairo_pdf_surface_close_stream (cairo_pdf_surface_t	*surface);
 
@@ -456,6 +459,7 @@ _cairo_pdf_surface_clear (cairo_pdf_surf
 
 static cairo_pdf_resource_t
 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
+                                cairo_bool_t             compressed,
 				const char		*fmt,
 				...)
 {
@@ -464,12 +468,16 @@ _cairo_pdf_surface_open_stream (cairo_pd
     surface->current_stream.active = TRUE;
     surface->current_stream.self = _cairo_pdf_surface_new_object (surface);
     surface->current_stream.length = _cairo_pdf_surface_new_object (surface);
+    surface->current_stream.compressed = compressed;
 
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Length %d 0 R\r\n",
 				 surface->current_stream.self.id,
 				 surface->current_stream.length.id);
+    if (compressed)
+        _cairo_output_stream_printf (surface->output,
+                                     "   /Filter /FlateDecode\r\n");
 
     if (fmt != NULL) {
 	va_start (ap, fmt);
@@ -483,6 +491,11 @@ _cairo_pdf_surface_open_stream (cairo_pd
 
     surface->current_stream.start_offset = _cairo_output_stream_get_position (surface->output);
 
+    if (compressed) {
+        surface->current_stream.old_output = surface->output;
+        surface->output = _cairo_deflate_stream_create (surface->output);
+    }
+
     return surface->current_stream.self;
 }
 
@@ -494,6 +507,13 @@ _cairo_pdf_surface_close_stream (cairo_p
     if (! surface->current_stream.active)
 	return;
 
+    if (surface->current_stream.compressed) {
+        _cairo_output_stream_destroy (surface->output);
+        surface->output = surface->current_stream.old_output;
+        _cairo_output_stream_printf (surface->output,
+                                     "\r\n");
+    }
+
     length = _cairo_output_stream_get_position (surface->output) -
 	surface->current_stream.start_offset;
     _cairo_output_stream_printf (surface->output,
@@ -577,6 +597,7 @@ _cairo_pdf_surface_resume_content_stream
     cairo_pdf_resource_t stream;
 
     stream = _cairo_pdf_surface_open_stream (surface,
+                                             TRUE,
 					     "   /Type /XObject\r\n"
 					     "   /Subtype /Form\r\n"
 					     "   /BBox [ 0 0 %f %f ]\r\n",
@@ -593,6 +614,7 @@ _cairo_pdf_surface_start_page (void *abs
     cairo_pdf_resource_t stream;
 
     stream = _cairo_pdf_surface_open_stream (surface,
+                                             TRUE,
 					     "   /Type /XObject\r\n"
 					     "   /Subtype /Form\r\n"
 					     "   /BBox [ 0 0 %f %f ]\r\n",
@@ -680,6 +702,7 @@ emit_smask (cairo_pdf_surface_t		*surfac
     }
 
     *stream_ret = _cairo_pdf_surface_open_stream (surface,
+                                                  FALSE,
 						  "   /Type /XObject\r\n"
 						  "   /Subtype /Image\r\n"
 						  "   /Width %d\r\n"
@@ -789,12 +812,14 @@ #define IMAGE_DICTIONARY	"   /Type /XObj
 
     if (need_smask)
 	*image_ret = _cairo_pdf_surface_open_stream (surface,
+                                                     FALSE,
 						     IMAGE_DICTIONARY
 						     "   /SMask %d 0 R\r\n",
 						     image->width, image->height,
 						     smask.id);
     else
 	*image_ret = _cairo_pdf_surface_open_stream (surface,
+                                                     FALSE,
 						     IMAGE_DICTIONARY,
 						     image->width, image->height);
 
@@ -928,6 +953,7 @@ emit_surface_pattern (cairo_pdf_surface_
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
 
     stream = _cairo_pdf_surface_open_stream (surface,
+                                             FALSE,
 					     "   /BBox [0 0 %d %d]\r\n"
 					     "   /XStep %d\r\n"
 					     "   /YStep %d\r\n"
@@ -1837,7 +1863,7 @@ _cairo_pdf_surface_emit_outline_glyph (c
     if (status)
 	return status;
 
-    *glyph_ret = _cairo_pdf_surface_open_stream (surface, NULL);
+    *glyph_ret = _cairo_pdf_surface_open_stream (surface, FALSE, NULL);
 
     _cairo_output_stream_printf (surface->output,
 				 "0 0 %f %f %f %f d1\r\n",
@@ -1892,7 +1918,7 @@ _cairo_pdf_surface_emit_bitmap_glyph (ca
 	    return cairo_surface_status (&image->base);
     }
 
-    *glyph_ret = _cairo_pdf_surface_open_stream (surface, NULL);
+    *glyph_ret = _cairo_pdf_surface_open_stream (surface, FALSE, NULL);
 
     _cairo_output_stream_printf (surface->output,
 				 "0 0 %f %f %f %f d1\r\n",
-- 
1.4.2



More information about the cairo mailing list