[cairo-commit] 9 commits - configure.in src/cairo-base85-stream.c src/cairoint.h src/cairo-output-stream.c src/cairo-output-stream-private.h src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-svg-surface.c src/cairo-type1-subset.c test/Makefile.am

Kristian Høgsberg krh at kemper.freedesktop.org
Wed Jun 14 12:02:13 PDT 2006


 configure.in                      |   14 
 src/cairo-base85-stream.c         |   28 
 src/cairo-output-stream-private.h |  156 +++++
 src/cairo-output-stream.c         |  185 ++++--
 src/cairo-pdf-surface.c           |    1 
 src/cairo-ps-surface.c            |   45 -
 src/cairo-svg-surface.c           | 1170 +++++++++++++++-----------------------
 src/cairo-type1-subset.c          |    1 
 src/cairoint.h                    |   84 --
 test/Makefile.am                  |    9 
 10 files changed, 829 insertions(+), 864 deletions(-)

New commits:
diff-tree 2cea3a2710cd4c6eb68e25eadaaf96cdc921ef14 (from parents)
Merge: 17ea7552355d9925fb99cd4ca98cf38946f99421 4932d09a06228a08d1c8f4d2892378c004ff3313
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Wed Jun 14 15:00:33 2006 -0400

    Merge branch 'svg-rewrite'

diff --cc src/cairo-ps-surface.c
index 00e0468,bed1f9f..729639e
@@@ -85,117 -86,6 +86,115 @@@
  
  #define PS_SURFACE_MAX_GLYPHS_PER_FONT	256
  
 +/* A word wrap stream can be used as a filter to do word wrapping on
 + * top of an existing output stream. The word wrapping is quite
 + * simple, using isspace to determine characters that separate
 + * words. Any word that will cause the column count exceeed the given
 + * max_column will have a '\n' character emitted before it.
 + *
 + * The stream is careful to maintain integrity for words that cross
 + * the boundary from one call to write to the next.
 + *
 + * Note: This stream does not guarantee that the output will never
 + * exceed max_column. In particular, if a single word is larger than
 + * max_column it will not be broken up.
 + */
 +typedef struct _word_wrap_stream {
++    cairo_output_stream_t base;
 +    cairo_output_stream_t *output;
 +    int max_column;
 +    int column;
 +    cairo_bool_t last_write_was_space;
 +} word_wrap_stream_t;
 +
 +static int
 +_count_word_up_to (const unsigned char *s, int length)
 +{
 +    int word = 0;
 +
 +    while (length--) {
 +	if (! isspace (*s++))
 +	    word++;
 +	else
 +	    return word;
 +    }
 +
 +    return word;
 +}
 +
 +static cairo_status_t
- _word_wrap_stream_write (void			*closure,
++_word_wrap_stream_write (cairo_output_stream_t  *base,
 +			 const unsigned char	*data,
 +			 unsigned int		 length)
 +{
-     word_wrap_stream_t *stream = closure;
++    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
 +    cairo_bool_t newline;
 +    int word;
 +
 +    while (length) {
 +	if (isspace (*data)) {
 +	    newline =  (*data == '\n' || *data == '\r');
 +	    if (! newline && stream->column >= stream->max_column) {
 +		_cairo_output_stream_printf (stream->output, "\n");
 +		stream->column = 0;
 +	    }
 +	    _cairo_output_stream_write (stream->output, data, 1);
 +	    data++;
 +	    length--;
 +	    if (newline)
 +		stream->column = 0;
 +	    else
 +		stream->column++;
 +	    stream->last_write_was_space = TRUE;
 +	} else {
 +	    word = _count_word_up_to (data, length);
 +	    /* Don't wrap if this word is a continuation of a word
 +	     * from a previous call to write. */
 +	    if (stream->column + word >= stream->max_column &&
 +		stream->last_write_was_space)
 +	    {
 +		_cairo_output_stream_printf (stream->output, "\n");
 +		stream->column = 0;
 +	    }
 +	    _cairo_output_stream_write (stream->output, data, word);
 +	    data += word;
 +	    length -= word;
 +	    stream->column += word;
 +	    stream->last_write_was_space = FALSE;
 +	}
 +    }
 +
 +    return _cairo_output_stream_get_status (stream->output);
 +}
 +
 +static cairo_status_t
- _word_wrap_stream_close (void *closure)
++_word_wrap_stream_close (cairo_output_stream_t *base)
 +{
-     cairo_status_t status;
-     word_wrap_stream_t *stream = closure;
- 
-     status = _cairo_output_stream_get_status (stream->output);
- 
-     free (stream);
++    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
 +
-     return status;
++    return _cairo_output_stream_get_status (stream->output);
 +}
 +
 +static cairo_output_stream_t *
 +_word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
 +{
 +    word_wrap_stream_t *stream;
 +
 +    stream = malloc (sizeof (word_wrap_stream_t));
 +    if (stream == NULL)
 +	return (cairo_output_stream_t *) &cairo_output_stream_nil;
 +
++    _cairo_output_stream_init (&stream->base,
++			       _word_wrap_stream_write,
++			       _word_wrap_stream_close);
 +    stream->output = output;
 +    stream->max_column = max_column;
 +    stream->column = 0;
 +    stream->last_write_was_space = FALSE;
 +
-     return _cairo_output_stream_create (_word_wrap_stream_write,
- 					_word_wrap_stream_close, stream);
++    return &stream->base;
 +}
 +
  static cairo_status_t
  _cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
  {
diff --cc src/cairo-type1-subset.c
index 703529c,0000000..1daa2f4
mode 100644,000000..100644
@@@ -1,1040 -1,0 +1,1041 @@@
 +/* cairo - a vector graphics library with display and print output
 + *
 + * Copyright © 2006 Red Hat, Inc
 + *
 + * 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 the cairo graphics library.
 + *
 + * The Initial Developer of the Original Code is Red Hat, Inc.
 + *
 + * Contributor(s):
 + *	Kristian Høgsberg <krh at redhat.com>
 + */
 +
 +#include "cairoint.h"
 +#include "cairo-scaled-font-subsets-private.h"
++#include "cairo-output-stream-private.h"
 +
 +/* XXX: Eventually, we need to handle other font backends */
 +#include "cairo-ft-private.h"
 +
 +#include <ft2build.h>
 +#include FT_FREETYPE_H
 +#include FT_OUTLINE_H
 +#include FT_TYPE1_TABLES_H
 +
 +typedef struct _cairo_type1_font_subset {
 +
 +    cairo_scaled_font_subset_t *scaled_font_subset;
 +
 +    struct {
 +	cairo_unscaled_font_t *unscaled_font;
 +	unsigned int font_id;
 +	char *base_font;
 +	int num_glyphs;
 +	long x_min, y_min, x_max, y_max;
 +	long ascent, descent;
 +
 +	const char    *data;
 +	unsigned long  header_size;
 +	unsigned long  data_size;
 +	unsigned long  trailer_size;
 +
 +    } base;
 +
 +    FT_Face face;
 +    int num_glyphs;
 +
 +    struct {
 +	int subset_index;
 +	int width;
 +	char *name;
 +    } *glyphs;
 +
 +    cairo_output_stream_t *output;
 +    cairo_array_t contents;
 +
 +    const char *rd, *nd;
 +
 +    char *type1_data;
 +    unsigned int type1_length;
 +    char *type1_end;
 +
 +    char *header_segment;
 +    int header_segment_size;
 +    char *eexec_segment;
 +    int eexec_segment_size;
 +    cairo_bool_t eexec_segment_is_ascii;
 +
 +    char *cleartext;
 +    char *cleartext_end;
 +
 +    int header_size;
 +
 +    unsigned short eexec_key;
 +    cairo_bool_t hex_encode;
 +    int hex_column;
 +
 +    cairo_status_t status;
 +} cairo_type1_font_subset_t;
 +
 +
 +static cairo_status_t
 +_cairo_type1_font_subset_create (cairo_unscaled_font_t      *unscaled_font,
 +				 cairo_type1_font_subset_t **subset_return)
 +{
 +    cairo_ft_unscaled_font_t *ft_unscaled_font;
 +    FT_Face face;
 +    PS_FontInfoRec font_info;
 +    cairo_type1_font_subset_t *font;
 +    int i, j;
 +
 +    ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font;
 +
 +    face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
 +
 +    if (FT_Get_PS_Font_Info(face, &font_info) != 0)
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +    font = calloc (sizeof (cairo_type1_font_subset_t), 1);
 +    if (font == NULL)
 +	return CAIRO_STATUS_NO_MEMORY;
 +
 +    font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font);
 +    font->base.num_glyphs = face->num_glyphs;
 +    font->base.x_min = face->bbox.xMin;
 +    font->base.y_min = face->bbox.yMin;
 +    font->base.x_max = face->bbox.xMax;
 +    font->base.y_max = face->bbox.yMax;
 +    font->base.ascent = face->ascender;
 +    font->base.descent = face->descender;
 +    font->base.base_font = strdup (face->family_name);
 +    if (font->base.base_font == NULL)
 +	goto fail1;
 +
 +    for (i = 0, j = 0; font->base.base_font[j]; j++) {
 +	if (font->base.base_font[j] == ' ')
 +	    continue;
 +	font->base.base_font[i++] = font->base.base_font[j];
 +    }
 +    font->base.base_font[i] = '\0';
 +
 +    font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]);
 +    if (font->glyphs == NULL)
 +	goto fail2;
 +
 +    font->num_glyphs = 0;
 +    for (i = 0; i < face->num_glyphs; i++)
 +	font->glyphs[i].subset_index = -1;
 +
 +    _cairo_array_init (&font->contents, sizeof (char));
 +
 +    _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font);
 +
 +    *subset_return = font;
 +
 +    return CAIRO_STATUS_SUCCESS;
 +
 + fail2:
 +    free (font->base.base_font);
 + fail1:
 +    free (font);
 +
 +    return CAIRO_STATUS_NO_MEMORY;
 +}
 +
 +static int
 +cairo_type1_font_subset_use_glyph (cairo_type1_font_subset_t *font, int glyph)
 +{
 +    if (font->glyphs[glyph].subset_index >= 0)
 +	return font->glyphs[glyph].subset_index;
 +
 +    font->glyphs[glyph].subset_index = font->num_glyphs;
 +    font->num_glyphs++;
 +
 +    return font->glyphs[glyph].subset_index;
 +}
 +
 +/* Magic constants for the type1 eexec encryption */
 +static const unsigned short c1 = 52845, c2 = 22719;
 +static const unsigned short private_dict_key = 55665;
 +static const unsigned short charstring_key = 4330;
 +
 +static cairo_bool_t
 +is_ps_delimiter(int c)
 +{
 +    const static char delimiters[] = "()[]{}<>/% \t\r\n";
 +
 +    return strchr (delimiters, c) != NULL;
 +}
 +
 +static const char *
 +find_token (const char *buffer, const char *end, const char *token)
 +{
 +    int i, length;
 +    /* FIXME: find substring really must be find_token */
 +
 +    length = strlen (token);
 +    for (i = 0; buffer + i < end - length + 1; i++)
 +	if (memcmp (buffer + i, token, length) == 0)
 +	    if ((i == 0 || token[0] == '/' || is_ps_delimiter(buffer[i - 1])) &&
 +		(buffer + i == end - length || is_ps_delimiter(buffer[i + length])))
 +		return buffer + i;
 +
 +    return NULL;
 +}
 +
 +static cairo_status_t
 +cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font)
 +{
 +    unsigned char *p;
 +    const char *eexec_token;
 +    int size;
 +
 +    p = (unsigned char *) font->type1_data;
 +    font->type1_end = font->type1_data + font->type1_length;
 +    if (p[0] == 0x80 && p[1] == 0x01) {
 +	font->header_segment_size =
 +	    p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
 +	font->header_segment = (char *) p + 6;
 +
 +	p += 6 + font->header_segment_size;
 +	font->eexec_segment_size =
 +	    p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
 +	font->eexec_segment = (char *) p + 6;
 +	font->eexec_segment_is_ascii = (p[1] == 1);
 +
 +        p += 6 + font->eexec_segment_size;
 +        while (p < (unsigned char *) (font->type1_end) && p[1] != 0x03) {
 +            size = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
 +            p += 6 + size;
 +        }
 +        font->type1_end = (char *) p;
 +    } else {
 +	eexec_token = find_token ((char *) p, font->type1_end, "eexec");
 +	if (eexec_token == NULL)
 +	    return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +	font->header_segment_size = eexec_token - (char *) p + strlen ("eexec\n");
 +	font->header_segment = (char *) p;
 +	font->eexec_segment_size = font->type1_length - font->header_segment_size;
 +	font->eexec_segment = (char *) p + font->header_segment_size;
 +	font->eexec_segment_is_ascii = TRUE;
 +    }
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_status_t
 +cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
 +					 const char *name)
 +{
 +    const char *start, *end, *segment_end;
 +    int i;
 +
 +    segment_end = font->header_segment + font->header_segment_size;
 +
 +    start = find_token (font->header_segment, segment_end, "/FontName");
 +    if (start == NULL)
 +	return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +    _cairo_output_stream_write (font->output, font->header_segment,
 +				start - font->header_segment);
 +
 +    _cairo_output_stream_printf (font->output, "/FontName /%s def", name);
 +
 +    end = find_token (start, segment_end, "def");
 +    if (end == NULL)
 +	return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +    end += 3;
 +
 +    start = find_token (end, segment_end, "/Encoding");
 +    if (start == NULL)
 +	return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +    _cairo_output_stream_write (font->output, end, start - end);
 +
 +    _cairo_output_stream_printf (font->output,
 +				 "/Encoding 256 array\n"
 +				 "0 1 255 {1 index exch /.notdef put} for\n");
 +    for (i = 0; i < font->base.num_glyphs; i++) {
 +	if (font->glyphs[i].subset_index < 0)
 +	    continue;
 +	_cairo_output_stream_printf (font->output,
 +				     "dup %d /%s put\n",
 +				     font->glyphs[i].subset_index,
 +				     font->glyphs[i].name);
 +    }
 +    _cairo_output_stream_printf (font->output, "readonly def");
 +
 +    end = find_token (start, segment_end, "def");
 +    if (end == NULL)
 +	return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +    end += 3;
 +
 +    _cairo_output_stream_write (font->output, end, segment_end - end);
 +
 +    return font->status;
 +}
 +
 +static int
 +hex_to_int (int ch)
 +{
 +    if (ch <= '9')
 +	return ch - '0';
 +    else if (ch <= 'F')
 +	return ch - 'A' + 10;
 +    else
 +	return ch - 'a' + 10;
 +}
 +
 +static void
 +cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font,
 +					 const char *data, unsigned int length)
 +{
 +    const unsigned char *in, *end;
 +    int c, p;
 +    static const char hex_digits[16] = "0123456789abcdef";
 +    char digits[3];
 +
 +    in = (const unsigned char *) data;
 +    end = (const unsigned char *) data + length;
 +    while (in < end) {
 +	p = *in++;
 +	c = p ^ (font->eexec_key >> 8);
 +	font->eexec_key = (c + font->eexec_key) * c1 + c2;
 +
 +	if (font->hex_encode) {
 +	    digits[0] = hex_digits[c >> 4];
 +	    digits[1] = hex_digits[c & 0x0f];
 +	    digits[2] = '\n';
 +	    font->hex_column += 2;
 +
 +	    if (font->hex_column == 78) {
 +		_cairo_output_stream_write (font->output, digits, 3);
 +		font->hex_column = 0;
 +	    } else {
 +		_cairo_output_stream_write (font->output, digits, 2);
 +	    }
 +	} else {
 +	    digits[0] = c;
 +	    _cairo_output_stream_write (font->output, digits, 1);
 +	}
 +    }
 +}
 +
 +static cairo_status_t
 +cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
 +{
 +    unsigned short r = private_dict_key;
 +    unsigned char *in, *end;
 +    char *out;
 +    int c, p;
 +
 +    in = (unsigned char *) font->eexec_segment;
 +    end = (unsigned char *) in + font->eexec_segment_size;
 +
 +    font->cleartext = malloc (font->eexec_segment_size);
 +    if (font->cleartext == NULL)
 +	return font->status = CAIRO_STATUS_NO_MEMORY;
 +    out = font->cleartext;
 +
 +    while (in < end) {
 +	if (font->eexec_segment_is_ascii) {
 +	    c = *in++;
 +	    if (isspace (c))
 +		continue;
 +	    c = (hex_to_int (c) << 4) | hex_to_int (*in++);
 +	} else {
 +	    c = *in++;
 +	}
 +	p = c ^ (r >> 8);
 +	r = (c + r) * c1 + c2;
 +
 +	*out++ = p;
 +    }
 +
 +    font->cleartext_end = out;
 +
 +    return font->status;
 +}
 +
 +static const char *
 +skip_token (const char *p, const char *end)
 +{
 +    while (p < end && isspace(*p))
 +	p++;
 +
 +    while (p < end && !isspace(*p))
 +	p++;
 +
 +    if (p == end)
 +	return NULL;
 +
 +    return p;
 +}
 +
 +static int
 +cairo_type1_font_subset_lookup_glyph (cairo_type1_font_subset_t *font,
 +				      const char *glyph_name, int length)
 +{
 +    int i;
 +
 +    for (i = 0; i < font->base.num_glyphs; i++) {
 +	if (font->glyphs[i].name &&
 +	    strncmp (font->glyphs[i].name, glyph_name, length) == 0 &&
 +	    font->glyphs[i].name[length] == '\0')
 +	    return i;
 +    }
 +
 +    return -1;
 +}
 +
 +static cairo_status_t
 +cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *font)
 +{
 +    int i;
 +    char buffer[256];
 +    FT_Error error;
 +
 +    /* Get glyph names and width using the freetype API */
 +    for (i = 0; i < font->base.num_glyphs; i++) {
 +	if (font->glyphs[i].name != NULL)
 +	    continue;
 +
 +	error = FT_Load_Glyph (font->face, i,
 +			       FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING |
 +			       FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
 +	if (error != 0) {
 +	    printf ("could not load glyph %d\n", i);
 +	    return font->status = CAIRO_STATUS_NO_MEMORY;
 +	}
 +
 +	font->glyphs[i].width = font->face->glyph->metrics.horiAdvance;
 +
 +	error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer);
 +	if (error != 0) {
 +	    printf ("could not get glyph name for glyph %d\n", i);
 +	    return font->status = CAIRO_STATUS_NO_MEMORY;
 +	}
 +
 +	font->glyphs[i].name = strdup (buffer);
 +	if (font->glyphs[i].name == NULL)
 +	    return font->status = CAIRO_STATUS_NO_MEMORY;
 +    }
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static void
 +cairo_type1_font_subset_decrypt_charstring (const unsigned char *in, int size, unsigned char *out)
 +{
 +    unsigned short r = charstring_key;
 +    int c, p, i;
 +
 +    for (i = 0; i < size; i++) {
 +        c = *in++;
 +	p = c ^ (r >> 8);
 +	r = (c + r) * c1 + c2;
 +	*out++ = p;
 +    }
 +}
 +
 +static const unsigned char *
 +cairo_type1_font_subset_decode_integer (const unsigned char *p, int *integer)
 +{
 +    if (*p <= 246) {
 +        *integer = *p++ - 139;
 +    } else if (*p <= 250) {
 +        *integer = (p[0] - 247) * 256 + p[1] + 108;
 +        p += 2;
 +    } else if (*p <= 254) {
 +        *integer = -(p[0] - 251) * 256 - p[1] - 108;
 +        p += 2;
 +    } else {
 +        *integer = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4];
 +        p += 5;
 +    }
 +
 +    return p;
 +}
 +
 +static const char *ps_standard_encoding[256] = {
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*   0 */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*  16 */
 +    "space", "exclam", "quotedbl", "numbersign",	/*  32 */
 +    "dollar", "percent", "ampersand", "quoteright",
 +    "parenleft", "parenright", "asterisk", "plus",
 +    "comma", "hyphen", "period", "slash",
 +    "zero", "one", "two", "three",			/*  48 */
 +    "four", "five", "six", "seven", "eight",
 +    "nine", "colon", "semicolon", "less",
 +    "equal", "greater", "question", "at",
 +    "A", "B", "C", "D", "E", "F", "G", "H",		/*  64 */
 +    "I", "J", "K", "L", "M", "N", "O", "P",
 +    "Q", "R", "S", "T", "U", "V", "W", "X",		/*  80 */
 +    "Y", "Z", "bracketleft", "backslash",
 +    "bracketright", "asciicircum", "underscore", "quoteleft",
 +    "a", "b", "c", "d", "e", "f", "g", "h",		/*  96 */
 +    "i", "j", "k", "l", "m", "n", "o", "p",
 +    "q", "r", "s", "t", "u", "v", "w", "x",		/* 112 */
 +    "y", "z", "braceleft", "bar",
 +    "braceright", "asciitilde", 0, 0,
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 128 */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 144 */
 +    "exclamdown", "cent", "sterling", "fraction",
 +    "yen", "florin", "section", "currency",
 +    "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
 +    "guilsinglright", "fi", "fl", NULL,
 +    "endash", "dagger", "daggerdbl", "periodcentered",	/* 160 */
 +    NULL, "paragraph", "bullet", "quotesinglbase",
 +    "quotedblbase", "quotedblright", "guillemotright", "ellipsis",
 +    "perthousand", NULL, "questiondown", NULL,
 +    "grave", "acute", "circumflex", "tilde",		/* 176 */
 +    "macron", "breve", "dotaccent", "dieresis",
 +    NULL, "ring", "cedilla", NULL,
 +    "hungarumlaut", "ogonek", "caron", "emdash",
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 192 */
 +    "AE", 0, "ordfeminine", 0, 0, 0, 0, "Lslash",	/* 208 */
 +    "Oslash", "OE", "ordmasculine", 0, 0, 0, 0, 0,
 +    "ae", 0, 0, 0, "dotlessi", 0, 0, "lslash",		/* 224 */
 +    "oslash", "oe", "germandbls", 0, 0, 0, 0
 +};
 +
 +static void
 +use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index)
 +{
 +    const char *glyph_name;
 +
 +    if (index < 0 || index > 255)
 +	return;
 +
 +    glyph_name = ps_standard_encoding[index];
 +    if (glyph_name == NULL)
 +	return;
 +
 +    index = cairo_type1_font_subset_lookup_glyph (font,
 +						  glyph_name,
 +						  strlen(glyph_name));
 +    if (index < 0)
 +	return;
 +
 +    cairo_type1_font_subset_use_glyph (font, index);
 +}
 +
 +#define TYPE1_CHARSTRING_COMMAND_ESCAPE		(12)
 +#define TYPE1_CHARSTRING_COMMAND_SEAC		(32 + 6)
 +
 +static void
 +cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
 +				      const char *name, int name_length,
 +				      const char *encrypted_charstring, int encrypted_charstring_length)
 +{
 +    unsigned char *charstring;
 +    const unsigned char *end;
 +    const unsigned char *p;
 +    int stack[5], sp, value;
 +    int command;
 +
 +    charstring = malloc (encrypted_charstring_length);
 +    if (charstring == NULL)
 +	return;
 +
 +    cairo_type1_font_subset_decrypt_charstring ((const unsigned char *)
 +						encrypted_charstring,
 +						encrypted_charstring_length,
 +						charstring);
 +    end = charstring + encrypted_charstring_length;
 +
 +    p = charstring + 4;
 +    sp = 0;
 +
 +    while (p < end) {
 +        if (*p < 32) {
 +	    command = *p++;
 +
 +	    if (command == TYPE1_CHARSTRING_COMMAND_ESCAPE)
 +		command = 32 + *p++;
 +
 +	    switch (command) {
 +	    case TYPE1_CHARSTRING_COMMAND_SEAC:
 +		/* The seac command takes five integer arguments.  The
 +		 * last two are glyph indices into the PS standard
 +		 * encoding give the names of the glyphs that this
 +		 * glyph is composed from.  All we need to do is to
 +		 * make sure those glyphs are present in the subset
 +		 * under their standard names. */
 +		use_standard_encoding_glyph (font, stack[3]);
 +		use_standard_encoding_glyph (font, stack[4]);
 +		sp = 0;
 +		break;
 +
 +	    default:
 +		sp = 0;
 +		break;
 +	    }
 +        } else {
 +            /* integer argument */
 +	    p = cairo_type1_font_subset_decode_integer (p, &value);
 +	    if (sp < 5)
 +		stack[sp++] = value;
 +        }
 +    }
 +
 +    free (charstring);
 +}
 +
 +static void
 +write_used_glyphs (cairo_type1_font_subset_t *font,
 +		   const char *name, int name_length,
 +		   const char *charstring, int charstring_length)
 +{
 +    char buffer[256];
 +    int length;
 +
 +    length = snprintf (buffer, sizeof buffer,
 +		       "/%.*s %d %s ",
 +		       name_length, name, charstring_length, font->rd);
 +    cairo_type1_font_subset_write_encrypted (font, buffer, length);
 +    cairo_type1_font_subset_write_encrypted (font,
 +					     charstring, charstring_length);
 +    length = snprintf (buffer, sizeof buffer, "%s\n", font->nd);
 +    cairo_type1_font_subset_write_encrypted (font, buffer, length);
 +}
 +
 +typedef void (*glyph_func_t) (cairo_type1_font_subset_t *font,
 +			      const char *name, int name_length,
 +			      const char *charstring, int charstring_length);
 +
 +static const char *
 +cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font,
 +					const char *dict_start,
 +					const char *dict_end,
 +					glyph_func_t func)
 +{
 +    int charstring_length, name_length, glyph_index;
 +    const char *p, *charstring, *name;
 +    char *end;
 +
 +    /* We're looking at '/' in the name of the first glyph.  The glyph
 +     * definitions are on the form:
 +     *
 +     *   /name 23 RD <23 binary bytes> ND
 +     *
 +     * or alternatively using -| and |- instead of RD and ND.
 +     *
 +     * We parse the glyph name and see if it is in the subset.  If it
 +     * is, we call the specified callback with the glyph name and
 +     * glyph data, otherwise we just skip it.  We need to parse
 +     * through a glyph definition; we can't just find the next '/',
 +     * since the binary data could contain a '/'.
 +     */
 +
 +    p = dict_start;
 +
 +    while (*p == '/') {
 +	name = p + 1;
 +	p = skip_token (p, dict_end);
 +	name_length = p - name;
 +
 +	charstring_length = strtol (p, &end, 10);
 +	if (p == end) {
 +	    font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +	    return NULL;
 +	}
 +
 +	/* Skip past -| or RD to binary data.  There is exactly one space
 +	 * between the -| or RD token and the encrypted data, thus '+ 1'. */
 +	charstring = skip_token (end, dict_end) + 1;
 +
 +	/* Skip binary data and |- or ND token. */
 +	p = skip_token (charstring + charstring_length, dict_end);
 +	while (p < dict_end && isspace(*p))
 +	    p++;
 +
 +	/* In case any of the skip_token() calls above reached EOF, p will
 +	 * be equal to dict_end. */
 +	if (p == dict_end) {
 +	    font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +	    return NULL;
 +	}
 +
 +	glyph_index = cairo_type1_font_subset_lookup_glyph (font,
 +							    name, name_length);
 +	if (font->glyphs[glyph_index].subset_index >= 0)
 +	    func (font, name, name_length, charstring, charstring_length);
 +    }
 +
 +    return p;
 +}
 +
 +
 +static const char *
 +cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
 +					    const char                *name)
 +{
 +    const char *p, *charstrings, *dict_start;
 +    const char *closefile_token;
 +    char buffer[32], *glyph_count_end;
 +    int num_charstrings, length;
 +
 +    /* The private dict holds hint information, common subroutines and
 +     * the actual glyph definitions (charstrings).
 +     *
 +     * FIXME: update this comment.
 +     *
 +     * What we do here is scan directly the /CharString token, which
 +     * marks the beginning of the glyph definitions.  Then we parse
 +     * through the glyph definitions and weed out the glyphs not in
 +     * our subset.  Everything else before and after the glyph
 +     * definitions is copied verbatim to the output.  It might be
 +     * worthwile to figure out which of the common subroutines are
 +     * used by the glyphs in the subset and get rid of the rest. */
 +
 +    /* FIXME: The /Subrs array contains binary data and could
 +     * conceivably have "/CharStrings" in it, so we might need to skip
 +     * this more cleverly. */
 +    charstrings = find_token (font->cleartext, font->cleartext_end, "/CharStrings");
 +    if (charstrings == NULL) {
 +	font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +	return NULL;
 +    }
 +
 +    /* Scan past /CharStrings and the integer following it. */
 +    p = charstrings + strlen ("/CharStrings");
 +    num_charstrings = strtol (p, &glyph_count_end, 10);
 +    if (p == glyph_count_end) {
 +	font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +	return NULL;
 +    }
 +
 +    /* Look for a '/' which marks the beginning of the first glyph
 +     * definition. */
 +    for (p = glyph_count_end; p < font->cleartext_end; p++)
 +	if (*p == '/')
 +	    break;
 +    if (p == font->cleartext_end) {
 +	font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +	return NULL;
 +    }
 +    dict_start = p;
 +
 +    if (cairo_type1_font_subset_get_glyph_names_and_widths (font))
 +	return NULL;
 +
 +    /* Now that we have the private dictionary broken down in
 +     * sections, do the first pass through the glyph definitions to
 +     * figure out which subrs and othersubrs are use and which extra
 +     * glyphs may be required by the seac operator. */
 +    p = cairo_type1_font_subset_for_each_glyph (font,
 +						dict_start,
 +						font->cleartext_end,
 +						cairo_type1_font_subset_look_for_seac);
 +
 +    closefile_token = find_token (p, font->cleartext_end, "closefile");
 +    if (closefile_token == NULL) {
 +	font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +	return NULL;
 +    }
 +
 +    if (cairo_type1_font_subset_get_glyph_names_and_widths (font))
 +	return NULL;
 +
 +    /* We're ready to start outputting. First write the header,
 +     * i.e. the public part of the font dict.*/
 +    if (cairo_type1_font_subset_write_header (font, name))
 +	return NULL;
 +
 +    font->base.header_size = _cairo_output_stream_get_position (font->output);
 +
 +
 +    /* Start outputting the private dict.  First output everything up
 +     * to the /CharStrings token. */
 +    cairo_type1_font_subset_write_encrypted (font, font->cleartext,
 +					     charstrings - font->cleartext);
 +
 +    /* Write out new charstring count */
 +    length = snprintf (buffer, sizeof buffer,
 +		       "/CharStrings %d", font->num_glyphs);
 +    cairo_type1_font_subset_write_encrypted (font, buffer, length);
 +
 +    /* Write out text between the charstring count and the first
 +     * charstring definition */
 +    cairo_type1_font_subset_write_encrypted (font, glyph_count_end,
 +					     dict_start - glyph_count_end);
 +
 +    /* Write out the charstring definitions for each of the glyphs in
 +     * the subset. */
 +    p = cairo_type1_font_subset_for_each_glyph (font,
 +						dict_start,
 +						font->cleartext_end,
 +						write_used_glyphs);
 +
 +    /* Output what's left between the end of the glyph definitions and
 +     * the end of the private dict to the output. */
 +    cairo_type1_font_subset_write_encrypted (font, p,
 +					     closefile_token - p + strlen ("closefile") + 1);
 +    _cairo_output_stream_write (font->output, "\n", 1);
 +
 +    return p;
 +}
 +
 +static cairo_status_t
 +cairo_type1_font_subset_write_trailer(cairo_type1_font_subset_t *font)
 +{
 +    const char *cleartomark_token;
 +    int i;
 +    static const char zeros[65] =
 +	"0000000000000000000000000000000000000000000000000000000000000000\n";
 +
 +    /* Some fonts have conditional save/restore around the entire font
 +     * dict, so we need to retain whatever postscript code that may
 +     * come after 'cleartomark'. */
 +
 +    for (i = 0; i < 8; i++)
 +	_cairo_output_stream_write (font->output, zeros, sizeof zeros);
 +
 +    cleartomark_token = find_token (font->type1_data, font->type1_end, "cleartomark");
 +    if (cleartomark_token == NULL)
 +	return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +    _cairo_output_stream_write (font->output, cleartomark_token,
 +				font->type1_end - cleartomark_token);
 +
 +    return font->status;
 +}
 +
 +static cairo_status_t
 +type1_font_write (void *closure, const unsigned char *data, unsigned int length)
 +{
 +    cairo_type1_font_subset_t *font = closure;
 +
 +    font->status =
 +	_cairo_array_append_multiple (&font->contents, data, length);
 +
 +    return font->status;
 +}
 +
 +static cairo_status_t
 +cairo_type1_font_subset_write (cairo_type1_font_subset_t *font,
 +			       const char *name)
 +{
 +    if (cairo_type1_font_subset_find_segments (font))
 +	return font->status;
 +
 +    if (cairo_type1_font_subset_decrypt_eexec_segment (font))
 +	return font->status;
 +
 +    /* Determine which glyph definition delimiters to use. */
 +    if (find_token (font->cleartext, font->cleartext_end, "/-|") != NULL) {
 +	font->rd = "-|";
 +	font->nd = "|-";
 +    } else if (find_token (font->cleartext, font->cleartext_end, "/RD") != NULL) {
 +	font->rd = "RD";
 +	font->nd = "ND";
 +    } else {
 +	/* Don't know *what* kind of font this is... */
 +	return font->status = CAIRO_INT_STATUS_UNSUPPORTED;
 +    }
 +
 +    font->eexec_key = private_dict_key;
 +    font->hex_encode = TRUE;
 +    font->hex_column = 0;
 +
 +    cairo_type1_font_subset_write_private_dict (font, name);
 +
 +    font->base.data_size = _cairo_output_stream_get_position (font->output) -
 +	font->base.header_size;
 +
 +    cairo_type1_font_subset_write_trailer (font);
 +
 +    font->base.trailer_size =
 +	_cairo_output_stream_get_position (font->output) -
 +	font->base.header_size - font->base.data_size;
 +
 +    return font->status;
 +}
 +
 +static cairo_status_t
 +cairo_type1_font_subset_generate (void       *abstract_font,
 +				  const char *name)
 +
 +{
 +    cairo_type1_font_subset_t *font = abstract_font;
 +    cairo_ft_unscaled_font_t *ft_unscaled_font;
 +    unsigned long ret;
 +
 +    ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font;
 +    font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
 +
 +    /* If anything fails below, it's out of memory. */
 +    font->status = CAIRO_STATUS_NO_MEMORY;
 +
 +    font->type1_length = font->face->stream->size;
 +    font->type1_data = malloc (font->type1_length);
 +    if (font->type1_data == NULL)
 +	goto fail;
 +
 +    if (font->face->stream->read) {
 +	ret = font->face->stream->read (font->face->stream, 0,
 +					(unsigned char *) font->type1_data,
 +					font->type1_length);
 +	if (ret != font->type1_length)
 +	    goto fail;
 +    } else {
 +	memcpy (font->type1_data,
 +		font->face->stream->base, font->type1_length);
 +    }
 +
 +    if (_cairo_array_grow_by (&font->contents, 4096) != CAIRO_STATUS_SUCCESS)
 +	goto fail;
 +
 +    font->output = _cairo_output_stream_create (type1_font_write, NULL, font);
 +    if (font->output == NULL)
 +	goto fail;
 +
 +    font->status = CAIRO_STATUS_SUCCESS;
 +    cairo_type1_font_subset_write (font, name);
 +
 +    font->base.data = _cairo_array_index (&font->contents, 0);
 +
 + fail:
 +    _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font);
 +
 +    return font->status;
 +}
 +
 +static void
 +cairo_type1_font_subset_destroy (void *abstract_font)
 +{
 +    cairo_type1_font_subset_t *font = abstract_font;
 +    int i;
 +
 +    /* If the subset generation failed, some of the pointers below may
 +     * be NULL depending on at which point the error occurred. */
 +
 +    _cairo_array_fini (&font->contents);
 +
 +    free (font->type1_data);
 +    if (font->glyphs != NULL)
 +	for (i = 0; i < font->base.num_glyphs; i++) {
 +	    free (font->glyphs[i].name);
 +	}
 +
 +    _cairo_unscaled_font_destroy (font->base.unscaled_font);
 +
 +    free (font->base.base_font);
 +    free (font->glyphs);
 +    free (font);
 +}
 +
 +
 +cairo_status_t
 +_cairo_type1_subset_init (cairo_type1_subset_t		*type1_subset,
 +			  const char			*name,
 +			  cairo_scaled_font_subset_t	*scaled_font_subset)
 +{
 +    cairo_type1_font_subset_t *font;
 +    cairo_status_t status;
 +    unsigned long parent_glyph, length;
 +    int i;
 +    cairo_unscaled_font_t *unscaled_font;
 +
 +    /* XXX: Need to fix this to work with a general cairo_unscaled_font_t. */
 +    if (!_cairo_scaled_font_is_ft (scaled_font_subset->scaled_font))
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +    unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font_subset->scaled_font);
 +
 +    status = _cairo_type1_font_subset_create (unscaled_font, &font);
 +    if (status)
 +	return status;
 +
 +    for (i = 0; i < scaled_font_subset->num_glyphs; i++) {
 +	parent_glyph = scaled_font_subset->glyphs[i];
 +	cairo_type1_font_subset_use_glyph (font, parent_glyph);
 +    }
 +
 +    /* Pull in the .notdef glyph */
 +    cairo_type1_font_subset_use_glyph (font, 0);
 +
 +    status = cairo_type1_font_subset_generate (font, name);
 +    if (status)
 +	goto fail1;
 +
 +    type1_subset->base_font = strdup (font->base.base_font);
 +    if (type1_subset->base_font == NULL)
 +	goto fail1;
 +
 +    type1_subset->widths = calloc (sizeof (int), font->num_glyphs);
 +    if (type1_subset->widths == NULL)
 +	goto fail2;
 +    for (i = 0; i < font->base.num_glyphs; i++) {
 +	if (font->glyphs[i].subset_index < 0)
 +	    continue;
 +	type1_subset->widths[font->glyphs[i].subset_index] =
 +	    font->glyphs[i].width;
 +    }
 +
 +    type1_subset->x_min = font->base.x_min;
 +    type1_subset->y_min = font->base.y_min;
 +    type1_subset->x_max = font->base.x_max;
 +    type1_subset->y_max = font->base.y_max;
 +    type1_subset->ascent = font->base.ascent;
 +    type1_subset->descent = font->base.descent;
 +
 +    length = font->base.header_size + font->base.data_size +
 +	font->base.trailer_size;
 +    type1_subset->data = malloc (length);
 +    if (type1_subset->data == NULL)
 +	goto fail3;
 +
 +    memcpy (type1_subset->data,
 +	    _cairo_array_index (&font->contents, 0), length);
 +
 +    type1_subset->header_length = font->base.header_size;
 +    type1_subset->data_length = font->base.data_size;
 +    type1_subset->trailer_length = font->base.trailer_size;
 +
 +    cairo_type1_font_subset_destroy (font);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +
 + fail3:
 +    free (type1_subset->widths);
 + fail2:
 +    free (type1_subset->base_font);
 + fail1:
 +    cairo_type1_font_subset_destroy (font);
 +
 +    return status;
 +}
 +
 +void
 +_cairo_type1_subset_fini (cairo_type1_subset_t *subset)
 +{
 +    free (subset->base_font);
 +    free (subset->widths);
 +    free (subset->data);
 +}
 +
diff-tree 4932d09a06228a08d1c8f4d2892378c004ff3313 (from cdf07a9be87515b75156a6f02f050bc5b1e6b5d1)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Wed Jun 14 14:12:55 2006 -0400

    Actually add src/cairo-output-stream-private.h.

diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
new file mode 100644
index 0000000..d1eeeeb
--- /dev/null
+++ b/src/cairo-output-stream-private.h
@@ -0,0 +1,156 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2006 Red Hat, Inc
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Author(s):
+ *	Kristian Høgsberg <krh at redhat.com>
+ */
+
+#ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H
+#define CAIRO_OUTPUT_STREAM_PRIVATE_H
+
+typedef struct _cairo_output_stream cairo_output_stream_t;
+
+typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
+							    const unsigned char   *data,
+							    unsigned int           length);
+
+typedef cairo_status_t (*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream);
+
+struct _cairo_output_stream {
+    cairo_output_stream_write_func_t write_func;
+    cairo_output_stream_close_func_t close_func;
+    unsigned long		     position;
+    cairo_status_t		     status;
+    cairo_bool_t		     closed;
+};
+
+extern const cairo_private cairo_output_stream_t cairo_output_stream_nil;
+
+cairo_private void
+_cairo_output_stream_init (cairo_output_stream_t            *stream,
+			   cairo_output_stream_write_func_t  write_func,
+			   cairo_output_stream_close_func_t  close_func);
+
+cairo_private void
+_cairo_output_stream_fini (cairo_output_stream_t *stream);
+
+
+/* We already have the following declared in cairo.h:
+
+typedef cairo_status_t (*cairo_write_func_t) (void		  *closure,
+					      const unsigned char *data,
+					      unsigned int	   length);
+*/
+typedef cairo_status_t (*cairo_close_func_t) (void *closure);
+
+
+/* This function never returns NULL. If an error occurs (NO_MEMORY)
+ * while trying to create the output stream this function returns a
+ * valid pointer to a nil output stream.
+ *
+ * Note that even with a nil surface, the close_func callback will be
+ * called by a call to _cairo_output_stream_close or
+ * _cairo_output_stream_destroy.
+ */
+cairo_private cairo_output_stream_t *
+_cairo_output_stream_create (cairo_write_func_t		write_func,
+			     cairo_close_func_t		close_func,
+			     void			*closure);
+
+cairo_private void
+_cairo_output_stream_close (cairo_output_stream_t *stream);
+
+cairo_private void
+_cairo_output_stream_destroy (cairo_output_stream_t *stream);
+
+cairo_private void
+_cairo_output_stream_write (cairo_output_stream_t *stream,
+			    const void *data, size_t length);
+
+cairo_private void
+_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
+				       const char *data,
+				       size_t length);
+
+cairo_private int
+_cairo_dtostr (char *buffer, size_t size, double d);
+
+cairo_private void
+_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
+			      const char *fmt, va_list ap);
+
+cairo_private void
+_cairo_output_stream_printf (cairo_output_stream_t *stream,
+			     const char *fmt, ...);
+
+cairo_private long
+_cairo_output_stream_get_position (cairo_output_stream_t *stream);
+
+cairo_private cairo_status_t
+_cairo_output_stream_get_status (cairo_output_stream_t *stream);
+
+/* This function never returns NULL. If an error occurs (NO_MEMORY or
+ * WRITE_ERROR) while trying to create the output stream this function
+ * returns a valid pointer to a nil output stream.
+ *
+ * NOTE: Even if a nil surface is returned, the caller should still
+ * call _cairo_output_stream_destroy (or _cairo_output_stream_close at
+ * least) in order to ensure that everything is properly cleaned up.
+ */
+cairo_private cairo_output_stream_t *
+_cairo_output_stream_create_for_filename (const char *filename);
+
+/* This function never returns NULL. If an error occurs (NO_MEMORY or
+ * WRITE_ERROR) while trying to create the output stream this function
+ * returns a valid pointer to a nil output stream.
+ *
+ * The caller still "owns" file and is responsible for calling fclose
+ * on it when finished. The stream will not do this itself.
+ */
+cairo_private cairo_output_stream_t *
+_cairo_output_stream_create_for_file (FILE *file);
+
+cairo_private cairo_output_stream_t *
+_cairo_memory_stream_create (void);
+
+cairo_private void
+_cairo_memory_stream_copy (cairo_output_stream_t *base,
+			   cairo_output_stream_t *dest);
+
+cairo_private int
+_cairo_memory_stream_length (cairo_output_stream_t *stream);
+
+/* cairo_base85_stream.c */
+cairo_private cairo_output_stream_t *
+_cairo_base85_stream_create (cairo_output_stream_t *output);
+
+#endif /* CAIRO_OUTPUT_STREAM_PRIVATE_H */
diff-tree cdf07a9be87515b75156a6f02f050bc5b1e6b5d1 (from ed60128bd0822e56c8002f3503044d5b0efaec79)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Tue Jun 13 17:45:55 2006 -0400

    Remove libxml2 checks from configure.in.

diff --git a/configure.in b/configure.in
index 1335e4c..a462ac5 100644
--- a/configure.in
+++ b/configure.in
@@ -525,17 +525,6 @@ CAIRO_BACKEND_ENABLE(svg, SVG, auto, [
   fi
 ])
 
-if test "x$use_svg" = "xyes" ; then
-	use_svg="no (SVG backend requires libxml2)"
-	if $PKG_CONFIG --exists libxml-2.0 ; then
-		# Sets XML_CFLAGS, XML_LIBS
-		PKG_CHECK_MODULES(XML, libxml-2.0)
-		use_svg=yes
-	else
-		AC_MSG_WARN([SVG requires libxml2, which is not found in pkg-config search path, disabling])
-	fi
-fi
-
 AM_CONDITIONAL(CAIRO_HAS_SVG_SURFACE, test "x$use_svg" = "xyes")
 if test "x$use_svg" = "xyes"; then
   SVG_SURFACE_FEATURE="#define CAIRO_HAS_SVG_SURFACE 1"
@@ -552,9 +541,6 @@ AM_CONDITIONAL(CAIRO_CAN_TEST_SVG_SURFAC
 AC_SUBST(LIBRSVG_CFLAGS)
 AC_SUBST(LIBRSVG_LIBS)
 
-CAIRO_CFLAGS="$CAIRO_CFLAGS $XML_CFLAGS"
-CAIRO_LIBS="$CAIRO_LIBS $XML_LIBS"
-
 dnl ===========================================================================
 
 dnl This check should default to 'yes' once we have code to actually
diff-tree ed60128bd0822e56c8002f3503044d5b0efaec79 (from 17d41d1f71a5d5af489bc395e3bb3cf414aeda57)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Tue Jun 13 17:25:24 2006 -0400

    Rewrite SVG backend to just use cairo output stream instead of libxml2.

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 893ef89..9a3bda4 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -48,16 +48,11 @@
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-output-stream-private.h"
 
-#include <libxml/tree.h>
-
-#define CC2XML(s) ((const xmlChar *)(s))
-#define C2XML(s) ((xmlChar *)(s))
-
-#define CAIRO_SVG_DTOSTR_BUFFER_LEN 30
-
 typedef struct cairo_svg_document cairo_svg_document_t;
 typedef struct cairo_svg_surface cairo_svg_surface_t;
 
+static const int invalid_pattern_id = -1;
+
 static const cairo_svg_version_t _cairo_svg_versions[CAIRO_SVG_VERSION_LAST] =
 {
     CAIRO_SVG_VERSION_1_1,
@@ -85,10 +80,8 @@ struct cairo_svg_document {
     double width;
     double height;
 
-    xmlDocPtr	xml_doc;
-    xmlNodePtr	xml_node_defs;
-    xmlNodePtr  xml_node_main;
-    xmlNodePtr	xml_node_glyphs;
+    cairo_output_stream_t *xml_node_defs;
+    cairo_output_stream_t *xml_node_glyphs;
 
     unsigned int surface_id;
     unsigned int linear_pattern_id;
@@ -119,10 +112,10 @@ struct cairo_svg_surface {
 
     cairo_svg_document_t *document;
 
-    xmlNodePtr  xml_node;
-    xmlNodePtr  xml_root_node;
+    cairo_output_stream_t *xml_node;
 
     unsigned int clip_level;
+    unsigned int base_clip;
 
     cairo_paginated_mode_t paginated_mode;
 };
@@ -340,9 +333,6 @@ _cairo_svg_surface_create_for_document (
 					double			 height)
 {
     cairo_svg_surface_t *surface;
-    xmlNodePtr clip, rect;
-    int clip_id;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
 
     surface = malloc (sizeof (cairo_svg_surface_t));
     if (surface == NULL) {
@@ -361,36 +351,23 @@ _cairo_svg_surface_create_for_document (
     surface->clip_level = 0;
 
     surface->id = document->surface_id++;
-    clip_id = document->clip_id++;
+    surface->base_clip = document->clip_id++;
+
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<clipPath id=\"clip%d\">\n"
+				 "  <rect width=\"%f\" height=\"%f\"/>\n"
+				 "</clipPath>\n",
+				 surface->base_clip,
+				 width, height);
 
-    clip = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("clipPath"), NULL);
-    snprintf (buffer, sizeof buffer, "clip%d", clip_id);
-    xmlSetProp (clip, CC2XML ("id"), C2XML (buffer));
-    rect = xmlNewChild (clip, NULL, CC2XML ("rect"), NULL);
-    _cairo_dtostr (buffer, sizeof buffer, width);
-    xmlSetProp (rect, CC2XML ("width"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, height);
-    xmlSetProp (rect, CC2XML ("height"), C2XML (buffer));
-
-    /* Use of xlink namespace requires node to be linked to tree.
-     * So by default we link surface main node to document svg node.
-     * For surfaces that don't own document, their main node will be
-     * unlinked and freed in surface finish. */
-    surface->xml_node = xmlNewChild (document->xml_node_main, NULL, CC2XML ("g"), NULL);
-    surface->xml_root_node = surface->xml_node;
-
-    snprintf (buffer, sizeof buffer, "surface%d", surface->id);
-    xmlSetProp (surface->xml_node, CC2XML ("id"), C2XML (buffer));
-    snprintf (buffer, sizeof buffer, "url(#clip%d)", clip_id);
-    xmlSetProp (surface->xml_node, CC2XML ("clip-path"), C2XML (buffer));
+    surface->xml_node = _cairo_memory_stream_create ();
 
     if (content == CAIRO_CONTENT_COLOR) {
-	rect = xmlNewChild (surface->xml_node, NULL, CC2XML ("rect"), NULL);
-	_cairo_dtostr (buffer, sizeof buffer, width);
-	xmlSetProp (rect, CC2XML ("width"), C2XML (buffer));
-	_cairo_dtostr (buffer, sizeof buffer, height);
-	xmlSetProp (rect, CC2XML ("height"), C2XML (buffer));
-	xmlSetProp (rect, CC2XML ("style"), CC2XML ("opacity:1; stroke:none; fill:rgb(0,0,0);"));
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<rect width=\"%f\" height=\"%f\" "
+				     "style=\"opacity: 1; stroke: none; "
+				     "fill: rgb(0,0,0);\"/>\n",
+				     width, height);
     }
 
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
@@ -428,8 +405,7 @@ _cairo_svg_surface_create_for_stream_int
 
 typedef struct
 {
-    cairo_svg_document_t *document;
-    xmlBufferPtr path;
+    cairo_output_stream_t *output;
     cairo_matrix_t *ctm_inverse;
 } svg_path_info_t;
 
@@ -437,21 +413,13 @@ static cairo_status_t
 _cairo_svg_path_move_to (void *closure, cairo_point_t *point)
 {
     svg_path_info_t *info = closure;
-    xmlBufferPtr path = info->path;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
     if (info->ctm_inverse)
 	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
-    xmlBufferCat (path, CC2XML ("M "));
-    _cairo_dtostr (buffer, sizeof buffer, x);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, y);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
+    _cairo_output_stream_printf (info->output, "M %f %f ", x, y);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -460,22 +428,13 @@ static cairo_status_t
 _cairo_svg_path_line_to (void *closure, cairo_point_t *point)
 {
     svg_path_info_t *info = closure;
-    xmlBufferPtr path = info->path;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
     double x = _cairo_fixed_to_double (point->x);
     double y = _cairo_fixed_to_double (point->y);
 
     if (info->ctm_inverse)
 	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
-    xmlBufferCat (path, CC2XML ("L "));
-
-    _cairo_dtostr (buffer, sizeof buffer, x);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, y);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
+    _cairo_output_stream_printf (info->output, "L %f %f ", x, y);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -487,8 +446,6 @@ _cairo_svg_path_curve_to (void          
 			  cairo_point_t *d)
 {
     svg_path_info_t *info = closure;
-    xmlBufferPtr path = info->path;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
     double bx = _cairo_fixed_to_double (b->x);
     double by = _cairo_fixed_to_double (b->y);
     double cx = _cairo_fixed_to_double (c->x);
@@ -502,25 +459,9 @@ _cairo_svg_path_curve_to (void          
 	cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
     }
 
-    xmlBufferCat (path, CC2XML ("C "));
-    _cairo_dtostr (buffer, sizeof buffer, bx);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, by);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, cx);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, cy);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, dx);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, dy);
-    xmlBufferCat (path, CC2XML (buffer));
-    xmlBufferCat (path, CC2XML (" "));
+    _cairo_output_stream_printf (info->output,
+ 				 "C %f %f %f %f %f %f ",
+				 bx, by, cx, cy, dx, dy);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -530,11 +471,36 @@ _cairo_svg_path_close_path (void *closur
 {
     svg_path_info_t *info = closure;
 
-    xmlBufferCat (info->path, CC2XML ("Z "));
+    _cairo_output_stream_printf (info->output, "Z ");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+emit_path (cairo_output_stream_t *output,
+	   cairo_path_fixed_t    *path,
+	   cairo_matrix_t	 *ctm_inverse)
+{
+    cairo_status_t status;
+    svg_path_info_t info;
+
+    _cairo_output_stream_printf (output, "d=\"");
+
+    info.output = output;
+    info.ctm_inverse = ctm_inverse;
+    status = _cairo_path_fixed_interpret (path,
+					  CAIRO_DIRECTION_FORWARD,
+					  _cairo_svg_path_move_to,
+					  _cairo_svg_path_line_to,
+					  _cairo_svg_path_curve_to,
+					  _cairo_svg_path_close_path,
+					  &info);
+
+    _cairo_output_stream_printf (output, "\"");
+
+    return status;
+}
+
 static void
 _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
 				cairo_scaled_font_t	*scaled_font,
@@ -544,9 +510,6 @@ _cairo_svg_document_emit_glyph (cairo_sv
 {
     cairo_scaled_glyph_t    *scaled_glyph;
     cairo_status_t	     status;
-    svg_path_info_t	     info;
-    xmlNodePtr		     symbol, child;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
 
     status = _cairo_scaled_glyph_lookup (scaled_font,
 					 scaled_font_glyph_index,
@@ -567,29 +530,15 @@ _cairo_svg_document_emit_glyph (cairo_sv
 	return;
     }
 
-    info.document = document;
-    info.path = xmlBufferCreate ();
-    info.ctm_inverse = NULL;
-
-    status = _cairo_path_fixed_interpret (scaled_glyph->path,
-					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_svg_path_move_to,
-					  _cairo_svg_path_line_to,
-					  _cairo_svg_path_curve_to,
-					  _cairo_svg_path_close_path,
-					  &info);
+    _cairo_output_stream_printf (document->xml_node_glyphs,
+ 				 "<symbol id=\"glyph%d-%d\">\n"
+ 				 "<path style=\"stroke: none;\" ",
+ 				 font_id,
+ 				 subset_glyph_index);
 
-    symbol = xmlNewChild (document->xml_node_glyphs, NULL,
-			  CC2XML ("symbol"), NULL);
-    snprintf (buffer, sizeof buffer, "glyph%d-%d",
-	      font_id,
-	      subset_glyph_index);
-    xmlSetProp (symbol, CC2XML ("id"), C2XML (buffer));
-    child = xmlNewChild (symbol, NULL, CC2XML ("path"), NULL);
-    xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
-    xmlSetProp (child, CC2XML ("style"), CC2XML ("stroke: none;"));
+    status = emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL);
 
-    xmlBufferFree (info.path);
+    _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n</symbol>\n");
 }
 
 static void
@@ -681,14 +630,12 @@ _cairo_svg_surface_finish (void *abstrac
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_svg_document_t *document = surface->document;
 
-    if (_cairo_paginated_surface_get_target (document->owner) == &surface->base) {
+    if (_cairo_paginated_surface_get_target (document->owner) == &surface->base)
 	status = _cairo_svg_document_finish (document);
-    } else {
-	/* See _cairo_svg_surface_create_for_document */
-	xmlUnlinkNode (surface->xml_root_node);
-	xmlFreeNode (surface->xml_root_node);
+    else
 	status = CAIRO_STATUS_SUCCESS;
-    }
+
+    _cairo_output_stream_destroy (surface->xml_node);
 
     _cairo_svg_document_destroy (document);
 
@@ -698,60 +645,39 @@ _cairo_svg_surface_finish (void *abstrac
 static void
 emit_alpha_filter (cairo_svg_document_t *document)
 {
-    if (!document->alpha_filter) {
-	xmlNodePtr node;
-	xmlNodePtr child;
-
-	node = xmlNewChild (document->xml_node_defs, NULL,
-			    CC2XML ("filter"), NULL);
-	xmlSetProp (node, CC2XML ("id"), CC2XML ("alpha"));
-	xmlSetProp (node, CC2XML ("filterUnits"), CC2XML ("objectBoundingBox"));
-	xmlSetProp (node, CC2XML ("x"), CC2XML ("0%"));
-	xmlSetProp (node, CC2XML ("y"), CC2XML ("0%"));
-	xmlSetProp (node, CC2XML ("width"), CC2XML ("100%"));
-	xmlSetProp (node, CC2XML ("height"), CC2XML ("100%"));
-	child = xmlNewChild (node, NULL, CC2XML ("feColorMatrix"), NULL);
-	xmlSetProp (child, CC2XML("type"), CC2XML ("matrix"));
-	xmlSetProp (child, CC2XML("in"), CC2XML ("SourceGraphic"));
-	xmlSetProp (child, CC2XML("values"), CC2XML ("0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"));
-	document->alpha_filter = TRUE;
-    }
+    if (document->alpha_filter)
+ 	return;
+
+    _cairo_output_stream_printf (document->xml_node_defs,
+ 				 "<filter id=\"alpha\" "
+ 				 "filterUnits=\"objectBoundingBox\" "
+ 				 "x=\"0%%\" y=\"0%%\" "
+ 				 "width=\"100%%\" height=\"100%%\">\n"
+ 				 "  <feColorMatrix type=\"matrix\" "
+ 				 "in=\"SourceGraphic\" "
+ 				 "values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0\"/>\n"
+ 				 "</filter>\n");
+
+    document->alpha_filter = TRUE;
 }
 
 static void
-emit_transform (xmlNodePtr node,
+emit_transform (cairo_output_stream_t *output,
 		char const *attribute_str,
+		char const *trailer,
 		cairo_matrix_t *matrix)
 {
-    xmlBufferPtr matrix_buffer;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
-    matrix_buffer = xmlBufferCreate ();
-    xmlBufferCat (matrix_buffer, CC2XML ("matrix("));
-    _cairo_dtostr (buffer, sizeof buffer, matrix->xx);
-    xmlBufferCat (matrix_buffer, C2XML (buffer));
-    xmlBufferCat (matrix_buffer, CC2XML (","));
-    _cairo_dtostr (buffer, sizeof buffer, matrix->yx);
-    xmlBufferCat (matrix_buffer, C2XML (buffer));
-    xmlBufferCat (matrix_buffer, CC2XML (","));
-    _cairo_dtostr (buffer, sizeof buffer, matrix->xy);
-    xmlBufferCat (matrix_buffer, C2XML (buffer));
-    xmlBufferCat (matrix_buffer, CC2XML (","));
-    _cairo_dtostr (buffer, sizeof buffer, matrix->yy);
-    xmlBufferCat (matrix_buffer, C2XML (buffer));
-    xmlBufferCat (matrix_buffer, CC2XML (","));
-    _cairo_dtostr (buffer, sizeof buffer, matrix->x0);
-    xmlBufferCat (matrix_buffer, C2XML (buffer));
-    xmlBufferCat (matrix_buffer, CC2XML(","));
-    _cairo_dtostr (buffer, sizeof buffer, matrix->y0);
-    xmlBufferCat (matrix_buffer, C2XML (buffer));
-    xmlBufferCat (matrix_buffer, CC2XML (")"));
-    xmlSetProp (node, CC2XML (attribute_str), C2XML (xmlBufferContent (matrix_buffer)));
-    xmlBufferFree (matrix_buffer);
+    _cairo_output_stream_printf (output,
+ 				 "%s=\"matrix(%f,%f,%f,%f,%f,%f)\"%s",
+ 				 attribute_str,
+ 				 matrix->xx, matrix->yx,
+ 				 matrix->xy, matrix->yy,
+ 				 matrix->x0, matrix->y0,
+ 				 trailer);
 }
 
 typedef struct {
-    xmlBufferPtr buffer;
+    cairo_output_stream_t *output;
     unsigned int in_mem;
     unsigned char src[3];
     unsigned char dst[5];
@@ -801,7 +727,7 @@ base64_write_func (void *closure,
 	    default:
 		break;
 	}
-	xmlBufferCat (info->buffer, dst);
+	_cairo_output_stream_write (info->output, dst, 4);
 	info->in_mem = 0;
     }
 
@@ -815,32 +741,25 @@ base64_write_func (void *closure,
 }
 
 static cairo_int_status_t
-_cairo_surface_base64_encode (cairo_surface_t *surface,
-			      xmlBufferPtr *buffer)
+_cairo_surface_base64_encode (cairo_surface_t       *surface,
+			      cairo_output_stream_t *output)
 {
     cairo_status_t status;
     base64_write_closure_t info;
     unsigned int i;
 
-    if (buffer == NULL)
-	return CAIRO_STATUS_NULL_POINTER;
-
-    info.buffer = xmlBufferCreate();
+    info.output = output;
     info.in_mem = 0;
     info.trailing = 0;
     memset (info.dst, '\x0', 5);
-    *buffer = info.buffer;
 
-    xmlBufferCat (info.buffer, CC2XML ("data:image/png;base64,"));
+    _cairo_output_stream_printf (info.output, "data:image/png;base64,");
 
     status = cairo_surface_write_to_png_stream (surface, base64_write_func,
 						(void *) &info);
 
-    if (status) {
-	xmlBufferFree (*buffer);
-	*buffer = NULL;
+    if (status)
 	return status;
-    }
 
     if (info.in_mem > 0) {
 	for (i = info.in_mem; i < 3; i++)
@@ -853,66 +772,65 @@ _cairo_surface_base64_encode (cairo_surf
     return CAIRO_STATUS_SUCCESS;
 }
 
-static xmlNodePtr
-emit_composite_image_pattern (xmlNodePtr 		 node,
+static cairo_status_t
+emit_composite_image_pattern (cairo_output_stream_t     *output,
 			      cairo_svg_surface_t	*svg_surface,
 			      cairo_surface_pattern_t 	*pattern,
-			      double 			*width,
-			      double 			*height,
-			      cairo_bool_t 		 is_pattern)
+			      int	 		 pattern_id,
+			      const char		*extra_attributes)
 {
-    cairo_surface_t *surface = pattern->surface;
     cairo_image_surface_t *image;
     cairo_status_t status;
     cairo_matrix_t p2u;
-    xmlNodePtr child = NULL;
-    xmlBufferPtr image_buffer;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
     void *image_extra;
 
-    status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
-    if (status)	 {
-	if (width != NULL)
-	    *width = 0;
-	if (height != NULL)
-	    *height = 0;
-	return NULL;
+    status = _cairo_surface_acquire_source_image (pattern->surface,
+						  &image, &image_extra);
+    if (status)
+	return status;
+
+    p2u = pattern->base.matrix;
+    cairo_matrix_invert (&p2u);
+
+    if (pattern_id != invalid_pattern_id) {
+	_cairo_output_stream_printf (output,
+				     "<pattern id=\"pattern%d\" "
+				     "patternUnits=\"userSpaceOnUse\" "
+				     "width=\"%d\" height=\"%d\"",
+				     pattern_id,
+				     image->width, image->height);
+	emit_transform (output, " patternTransform", ">\n", &p2u);
     }
 
-    status = _cairo_surface_base64_encode (surface, &image_buffer);
-    if (status)
-	goto BAIL;
+    _cairo_output_stream_printf (output,
+				 "  <image width=\"%d\" height=\"%d\"",
+				 image->width, image->height);
 
-    child = xmlNewChild (node, NULL, CC2XML ("image"), NULL);
-    _cairo_dtostr (buffer, sizeof buffer, image->width);
-    xmlSetProp (child, CC2XML ("width"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, image->height);
-    xmlSetProp (child, CC2XML ("height"), C2XML (buffer));
-    xmlSetProp (child, CC2XML ("xlink:href"), C2XML (xmlBufferContent (image_buffer)));
+    if (pattern_id == invalid_pattern_id)
+	emit_transform (output, " transform", "", &p2u);
 
-    xmlBufferFree (image_buffer);
+    if (extra_attributes)
+	_cairo_output_stream_printf (output, " %s", extra_attributes);
 
-    if (!is_pattern) {
-	p2u = pattern->base.matrix;
-	cairo_matrix_invert (&p2u);
-	emit_transform (child, "transform", &p2u);
-    }
+    _cairo_output_stream_printf (output, " xlink:href=\"");
+
+    status = _cairo_surface_base64_encode (pattern->surface, output);
 
-    if (width != NULL)
-	    *width = image->width;
-    if (height != NULL)
-	    *height = image->height;
+    _cairo_output_stream_printf (output, "\"/>\n");
+
+    if (pattern_id != invalid_pattern_id)
+	_cairo_output_stream_printf (output, "</pattern>\n");
 
-BAIL:
     _cairo_surface_release_source_image (pattern->surface, image, image_extra);
 
-    return child;
+    return status;
 }
 
 static int
 emit_meta_surface (cairo_svg_document_t *document,
 		   cairo_meta_surface_t *surface)
 {
+    cairo_output_stream_t *contents;
     cairo_meta_surface_t *meta;
     cairo_meta_snapshot_t *snapshot;
     int num_elements;
@@ -933,7 +851,6 @@ emit_meta_surface (cairo_svg_document_t 
 	cairo_surface_t *paginated_surface;
 	cairo_surface_t *svg_surface;
 	cairo_meta_snapshot_t new_snapshot;
-	xmlNodePtr child;
 
 	meta = (cairo_meta_surface_t *) _cairo_surface_snapshot ((cairo_surface_t *)surface);
 	paginated_surface = _cairo_svg_surface_create_for_document (document,
@@ -951,78 +868,114 @@ emit_meta_surface (cairo_svg_document_t 
 	new_snapshot.id = ((cairo_svg_surface_t *) svg_surface)->id;
 	_cairo_array_append (&document->meta_snapshots, &new_snapshot);
 
-	if (meta->content == CAIRO_CONTENT_ALPHA)
+	if (meta->content == CAIRO_CONTENT_ALPHA) {
 	    emit_alpha_filter (document);
-	child = xmlAddChild (document->xml_node_defs,
-			     xmlCopyNode (((cairo_svg_surface_t *) svg_surface)->xml_root_node, 1));
-	if (meta->content == CAIRO_CONTENT_ALPHA)
-	    xmlSetProp (child, CC2XML ("filter"), CC2XML("url(#alpha)"));
+	    _cairo_output_stream_printf (document->xml_node_defs,
+					 "<g id=\"surface%d\" "
+					 "clip-path=\"url(#clip%d)\" "
+					 "filter=\"url(#alpha)\">\n",
+					 ((cairo_svg_surface_t *) svg_surface)->id,
+					 ((cairo_svg_surface_t *) svg_surface)->base_clip);
+	} else {
+	    _cairo_output_stream_printf (document->xml_node_defs,
+					 "<g id=\"surface%d\" "
+					 "clip-path=\"url(#clip%d)\">\n",
+					 ((cairo_svg_surface_t *) svg_surface)->id,
+					 ((cairo_svg_surface_t *) svg_surface)->base_clip);
+	}
+
+	contents = ((cairo_svg_surface_t *) svg_surface)->xml_node;
+	_cairo_memory_stream_copy (contents, document->xml_node_defs);
+
+	for (i = 0; i < ((cairo_svg_surface_t *) svg_surface)->clip_level; i++)
+	    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
 	id = new_snapshot.id;
 
 	cairo_surface_destroy (paginated_surface);
+
+	/* FIXME: cairo_paginated_surface doesn't take a ref to the
+	 * passed in target surface so we can't call destroy here.
+	 * cairo_paginated_surface should be fixed, but for now just
+	 * work around it. */
+
+	/* cairo_surface_destroy (svg_surface); */
     }
 
     return id;
 }
 
-static xmlNodePtr
-emit_composite_meta_pattern (xmlNodePtr node,
+static cairo_status_t
+emit_composite_meta_pattern (cairo_output_stream_t	*output,
 			     cairo_svg_surface_t	*surface,
 			     cairo_surface_pattern_t	*pattern,
-			     double *width,
-			     double *height,
-			     cairo_bool_t is_pattern)
+			     int			 pattern_id,
+			     const char			*extra_attributes)
 {
     cairo_svg_document_t *document = surface->document;
     cairo_meta_surface_t *meta_surface;
     cairo_matrix_t p2u;
-    xmlNodePtr child;
     int id;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
 
     meta_surface = (cairo_meta_surface_t *) pattern->surface;
 
     id = emit_meta_surface (document, meta_surface);
 
-    child = xmlNewChild (node, NULL, CC2XML("use"), NULL);
-    snprintf (buffer, sizeof buffer, "#surface%d", id);
-    xmlSetProp (child, CC2XML ("xlink:href"), C2XML (buffer));
+    p2u = pattern->base.matrix;
+    cairo_matrix_invert (&p2u);
 
-    if (!is_pattern) {
-	p2u = pattern->base.matrix;
-	cairo_matrix_invert (&p2u);
-	emit_transform (child, "transform", &p2u);
-    }
+    if (pattern_id != invalid_pattern_id) {
+	_cairo_output_stream_printf (output,
+				     "<pattern id=\"pattern%d\" "
+				     "patternUnits=\"userSpaceOnUse\" "
+				     "width=\"%d\" height=\"%d\"",
+				     pattern_id,
+				     meta_surface->width_pixels,
+				     meta_surface->height_pixels);
+	emit_transform (output, " patternTransform", ">\n", &p2u);
+    }
+
+    _cairo_output_stream_printf (output,
+				 "<use xlink:href=\"#surface%d\"",
+				 id);
+
+    if (pattern_id == invalid_pattern_id)
+	emit_transform (output, " transform", "", &p2u);
 
-    if (width != NULL)
-	    *width = meta_surface->width_pixels;
-    if (height != NULL)
-	    *height = meta_surface->height_pixels;
+    if (extra_attributes)
+	_cairo_output_stream_printf (output, " %s", extra_attributes);
 
-    return child;
+    _cairo_output_stream_printf (output, "/>\n");
+
+    if (pattern_id != invalid_pattern_id)
+	_cairo_output_stream_printf (output, "</pattern>\n");
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
-static xmlNodePtr
-emit_composite_pattern (xmlNodePtr node,
+static cairo_status_t
+emit_composite_pattern (cairo_output_stream_t   *output,
 			cairo_svg_surface_t	*surface,
 			cairo_surface_pattern_t *pattern,
-			double *width,
-			double *height,
-			int is_pattern)
+			int			 pattern_id,
+			const char		*extra_attributes)
 {
 
     if (_cairo_surface_is_meta (pattern->surface)) {
-	return emit_composite_meta_pattern (node, surface, pattern, width, height, is_pattern);
+	return emit_composite_meta_pattern (output, surface, pattern,
+					    pattern_id, extra_attributes);
     }
 
-    return emit_composite_image_pattern (node, surface, pattern, width, height, is_pattern);
+    return emit_composite_image_pattern (output, surface, pattern,
+					 pattern_id, extra_attributes);
 }
 
 static void
-emit_operator (xmlNodePtr	     node,
-	       cairo_svg_surface_t  *surface,
-	       cairo_operator_t	     op)
+emit_operator (cairo_output_stream_t *output,
+	       cairo_svg_surface_t   *surface,
+	      cairo_operator_t	      op)
 {
     char const *op_str[] = {
 	"clear",
@@ -1038,129 +991,77 @@ emit_operator (xmlNodePtr	     node,
     };
 
     if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2)
-	xmlSetProp (node, CC2XML ("comp-op"), C2XML (op_str[op]));
-}
-
-static void
-emit_color (cairo_color_t const *color,
-	    xmlBufferPtr	 style,
-	    char const		*color_str,
-	    char const		*opacity_str)
-{
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
-    xmlBufferCat (style, CC2XML (color_str));
-    xmlBufferCat (style, CC2XML (": rgb("));
-    _cairo_dtostr (buffer, sizeof buffer, color->red * 100.0);
-    xmlBufferCat (style, C2XML (buffer));
-    xmlBufferCat (style, CC2XML ("%,"));
-    _cairo_dtostr (buffer, sizeof buffer, color->green * 100.0);
-    xmlBufferCat (style, C2XML (buffer));
-    xmlBufferCat (style, CC2XML ("%,"));
-    _cairo_dtostr (buffer, sizeof buffer, color->blue * 100.0);
-    xmlBufferCat (style, C2XML (buffer));
-    xmlBufferCat (style, CC2XML ("%); "));
-    xmlBufferCat (style, CC2XML (opacity_str));
-    xmlBufferCat (style, CC2XML (": "));
-    _cairo_dtostr (buffer, sizeof buffer, color->alpha);
-    xmlBufferCat (style, CC2XML (buffer));
-    xmlBufferCat (style, CC2XML (";"));
+	_cairo_output_stream_printf (output, "comp-op: %s; ", op_str[op]);
 }
 
 static void
 emit_solid_pattern (cairo_svg_surface_t	    *surface,
 		    cairo_solid_pattern_t   *pattern,
-		    xmlBufferPtr	     style,
-		    int			     is_stroke)
+		    cairo_output_stream_t   *style,
+		    cairo_bool_t	     is_stroke)
 {
-    emit_color (&pattern->color,
-		style, is_stroke ? "stroke" : "fill",
-		"opacity");
+    _cairo_output_stream_printf (style,
+				 "%s: rgb(%f%%,%f%%,%f%%); "
+				 "opacity: %f;",
+				 is_stroke ? "stroke" : "fill",
+				 pattern->color.red * 100.0,
+				 pattern->color.green * 100.0,
+				 pattern->color.blue * 100.0,
+				 pattern->color.alpha);
 }
 
 static void
 emit_surface_pattern (cairo_svg_surface_t	*surface,
 		      cairo_surface_pattern_t	*pattern,
-		      xmlBufferPtr		 style,
-		      int			 is_stroke)
+		      cairo_output_stream_t     *style,
+		      cairo_bool_t		 is_stroke)
 {
     cairo_svg_document_t *document = surface->document;
-    xmlNodePtr child;
-    xmlBufferPtr id;
-    cairo_matrix_t p2u;
-    double width, height;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
-    child = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("pattern"), NULL);
-
-    id = xmlBufferCreate ();
-    xmlBufferCat (id, CC2XML ("pattern"));
-    snprintf (buffer, sizeof buffer, "%d", document->pattern_id);
-    xmlBufferCat (id, C2XML (buffer));
-    xmlSetProp (child, CC2XML ("id"), C2XML (xmlBufferContent (id)));
-
-    xmlBufferCat (style, CC2XML (is_stroke ? "color: url(#" : "fill: url(#"));
-    xmlBufferCat (style, xmlBufferContent (id));
-    xmlBufferCat (style, CC2XML (");"));
-    xmlBufferFree (id);
-
-    document->pattern_id++;
-
-    emit_composite_pattern (child, surface, pattern, &width, &height, TRUE);
-
-    _cairo_dtostr (buffer, sizeof buffer, width);
-    xmlSetProp (child, CC2XML ("width"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, height);
-    xmlSetProp (child, CC2XML ("height"), C2XML (buffer));
+    int pattern_id;
 
-    p2u = pattern->base.matrix;
-    cairo_matrix_invert (&p2u);
-
-    emit_transform (child, "patternTransform", &p2u);
-
-    xmlSetProp (child, CC2XML ("patternUnits"), CC2XML ("userSpaceOnUse"));
+    pattern_id = document->pattern_id++;
+    emit_composite_pattern (document->xml_node_defs, surface, pattern,
+			    pattern_id, NULL);
+
+    _cairo_output_stream_printf (style,
+				 "%s: url(#pattern%d);",
+				 is_stroke ? "color" : "fill",
+				 pattern_id);
 }
 
 static void
-emit_pattern_stops (xmlNodePtr parent,
+emit_pattern_stops (cairo_output_stream_t *output,
 		    cairo_gradient_pattern_t const *pattern,
 		    double start_offset)
 {
-    xmlNodePtr child;
-    xmlBufferPtr style;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-    cairo_color_t color;
+    double offset;
     int i;
 
     for (i = 0; i < pattern->n_stops; i++) {
-	child = xmlNewChild (parent, NULL, CC2XML ("stop"), NULL);
-	_cairo_dtostr (buffer, sizeof buffer,
-		       start_offset + (1 - start_offset ) *
-		       _cairo_fixed_to_double (pattern->stops[i].x));
-	xmlSetProp (child, CC2XML ("offset"), C2XML (buffer));
-	style = xmlBufferCreate ();
-	_cairo_color_init_rgba (&color,
-				pattern->stops[i].color.red   / 65535.0,
-				pattern->stops[i].color.green / 65535.0,
-				pattern->stops[i].color.blue  / 65535.0,
-				pattern->stops[i].color.alpha / 65535.0);
-	emit_color (&color, style, "stop-color", "stop-opacity");
-	xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
-	xmlBufferFree (style);
+	offset = start_offset + (1 - start_offset ) *
+	    _cairo_fixed_to_double (pattern->stops[i].x);
+	_cairo_output_stream_printf (output,
+				     "<stop offset=\"%f\" style=\""
+				     "stop-color: rgb(%f%%,%f%%,%f%%); "
+				     "stop-opacity: %f;\"/>\n",
+				     offset,
+				     pattern->stops[i].color.red   / 655.35,
+				     pattern->stops[i].color.green / 655.35,
+				     pattern->stops[i].color.blue  / 655.35,
+				     pattern->stops[i].color.alpha / 65535.0);
     }
 }
 
 static void
-emit_pattern_extend (xmlNodePtr node, cairo_extend_t extend)
+emit_pattern_extend (cairo_output_stream_t *output,
+		     cairo_pattern_t       *pattern)
 {
-    char const *value = NULL;
-
-    switch (extend) {
+    switch (pattern->extend) {
 	case CAIRO_EXTEND_REPEAT:
-	    value = "repeat";
+	    _cairo_output_stream_printf (output, "spreadMethod=\"repeat\" ");
 	    break;
 	case CAIRO_EXTEND_REFLECT:
-	    value = "reflect";
+	    _cairo_output_stream_printf (output, "spreadMethod=\"reflect\" ");
 	    break;
 	case CAIRO_EXTEND_NONE:
 	    break;
@@ -1168,94 +1069,58 @@ emit_pattern_extend (xmlNodePtr node, ca
 	    /* FIXME not implemented */
 	    break;
     }
-
-    if (value != NULL)
-	xmlSetProp (node, CC2XML ("spreadMethod"), CC2XML (value));
 }
 
 static void
 emit_linear_pattern (cairo_svg_surface_t    *surface,
 		     cairo_linear_pattern_t *pattern,
-		     xmlBufferPtr	     style,
-		     int		     is_stroke)
+		     cairo_output_stream_t  *style,
+		     cairo_bool_t	     is_stroke)
 {
     cairo_svg_document_t *document = surface->document;
-    xmlNodePtr child;
-    xmlBufferPtr id;
     double x0, y0, x1, y1;
     cairo_matrix_t p2u;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
-    child = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("linearGradient"), NULL);
-
-    id = xmlBufferCreate ();
-    xmlBufferCat (id, CC2XML ("linear"));
-    snprintf (buffer, sizeof buffer, "%d", document->linear_pattern_id);
-    xmlBufferCat (id, C2XML (buffer));
-    xmlSetProp (child, CC2XML ("id"), C2XML (xmlBufferContent (id)));
-    xmlSetProp (child, CC2XML ("gradientUnits"), CC2XML ("userSpaceOnUse"));
-    emit_pattern_extend (child, pattern->base.base.extend);
-
-    xmlBufferCat (style, CC2XML (is_stroke ? "color: url(#" : "fill: url(#"));
-    xmlBufferCat (style, xmlBufferContent (id));
-    xmlBufferCat (style, CC2XML (");"));
-
-    xmlBufferFree (id);
-
-    document->linear_pattern_id++;
-
-    emit_pattern_stops (child ,&pattern->base, 0.0);
 
     x0 = _cairo_fixed_to_double (pattern->gradient.p1.x);
     y0 = _cairo_fixed_to_double (pattern->gradient.p1.y);
     x1 = _cairo_fixed_to_double (pattern->gradient.p2.x);
     y1 = _cairo_fixed_to_double (pattern->gradient.p2.y);
 
-    _cairo_dtostr (buffer, sizeof buffer, x0);
-    xmlSetProp (child, CC2XML ("x1"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, y0);
-    xmlSetProp (child, CC2XML ("y1"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, x1);
-    xmlSetProp (child, CC2XML ("x2"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, y1);
-    xmlSetProp (child, CC2XML ("y2"), C2XML (buffer));
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<linearGradient id=\"linear%d\" "
+				 "gradientUnits=\"userSpaceOnUse\" "
+				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
+				 document->linear_pattern_id,
+				 x0, y0, x1, y1);
 
+    emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
     p2u = pattern->base.base.matrix;
     cairo_matrix_invert (&p2u);
+    emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
+
+    emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0);
+
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "</linearGradient>\n");
 
-    emit_transform (child, "gradientTransform", &p2u);
+    _cairo_output_stream_printf (style,
+				 "%s: url(#linear%d);",
+				 is_stroke ? "color" : "fill",
+				 document->linear_pattern_id);
+
+    document->linear_pattern_id++;
 }
 
 static void
-emit_radial_pattern (cairo_svg_surface_t *surface,
+emit_radial_pattern (cairo_svg_surface_t    *surface,
 		     cairo_radial_pattern_t *pattern,
-		     xmlBufferPtr style, int is_stroke)
+		     cairo_output_stream_t  *style,
+		     cairo_bool_t            is_stroke)
 {
     cairo_svg_document_t *document = surface->document;
     cairo_matrix_t p2u;
-    xmlNodePtr child;
-    xmlBufferPtr id;
     double x0, y0, x1, y1, r0, r1;
     double fx, fy;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
-    child = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("radialGradient"), NULL);
-
-    id = xmlBufferCreate ();
-    xmlBufferCat (id, CC2XML ("radial"));
-    snprintf (buffer, sizeof buffer, "%d", document->radial_pattern_id);
-    xmlBufferCat (id, C2XML (buffer));
-    xmlSetProp (child, CC2XML ("id"), C2XML (xmlBufferContent (id)));
-    xmlSetProp (child, CC2XML ("gradientUnits"), CC2XML ("userSpaceOnUse"));
-    emit_pattern_extend (child, pattern->base.base.extend);
-
-    xmlBufferCat (style, CC2XML (is_stroke ? "color: url(#" : "fill: url(#"));
-    xmlBufferCat (style, xmlBufferContent (id));
-    xmlBufferCat (style, CC2XML (");"));
-
-    xmlBufferFree (id);
-
-    document->radial_pattern_id++;
 
     x0 = _cairo_fixed_to_double (pattern->gradient.inner.x);
     y0 = _cairo_fixed_to_double (pattern->gradient.inner.y);
@@ -1272,44 +1137,52 @@ emit_radial_pattern (cairo_svg_surface_t
     fx = (r1 * x0 - r0 * x1) / (r1 - r0);
     fy = (r1 * y0 - r0 * y1) / (r1 - r0);
 
-    emit_pattern_stops (child, &pattern->base, r0 / r1);
-
-    _cairo_dtostr (buffer, sizeof buffer, x1);
-    xmlSetProp (child, CC2XML ("cx"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, y1);
-    xmlSetProp (child, CC2XML ("cy"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, fx);
-    xmlSetProp (child, CC2XML ("fx"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, fy);
-    xmlSetProp (child, CC2XML ("fy"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, r1);
-    xmlSetProp (child, CC2XML ("r"), C2XML (buffer));
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<radialGradient id=\"radial%d\" "
+				 "gradientUnits=\"userSpaceOnUse\" "
+				 "cx=\"%f\" cy=\"%f\" "
+				 "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
+				 document->radial_pattern_id,
+				 x1, y1,
+				 fx, fy, r1);
 
+    emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
     p2u = pattern->base.base.matrix;
     cairo_matrix_invert (&p2u);
+    emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
+
+    emit_pattern_stops (document->xml_node_defs, &pattern->base, r0 / r1);
+
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "</radialGradient>\n");
 
-    emit_transform (child, "gradientTransform", &p2u);
+    _cairo_output_stream_printf (style,
+				 "%s: url(#radial%d);",
+				 is_stroke ? "color" : "fill",
+				 document->radial_pattern_id);
+
+    document->radial_pattern_id++;
 }
 
 static void
 emit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern,
-	      xmlBufferPtr style, int is_stroke)
+	      cairo_output_stream_t *output, cairo_bool_t is_stroke)
 {
     switch (pattern->type) {
     case CAIRO_PATTERN_TYPE_SOLID:
-	emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, style, is_stroke);
+	emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, output, is_stroke);
 	break;
 
     case CAIRO_PATTERN_TYPE_SURFACE:
-	emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, style, is_stroke);
+	emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, output, is_stroke);
 	break;
 
     case CAIRO_PATTERN_TYPE_LINEAR:
-	emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, style, is_stroke);
+	emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, output, is_stroke);
 	break;
 
     case CAIRO_PATTERN_TYPE_RADIAL:
-	emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, style, is_stroke);
+	emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, output, is_stroke);
 	break;
     }
 }
@@ -1324,42 +1197,25 @@ _cairo_svg_surface_fill (void			*abstrac
 			 cairo_antialias_t	 antialias)
 {
     cairo_svg_surface_t *surface = abstract_surface;
-    cairo_svg_document_t *document = surface->document;
     cairo_status_t status;
-    svg_path_info_t info;
-    xmlNodePtr child;
-    xmlBufferPtr style;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _analyze_operation (surface, op, source);
 
     assert (_operation_supported (surface, op, source));
 
-    info.document = document;
-    info.path = xmlBufferCreate ();
-    info.ctm_inverse = NULL;
-
-    style = xmlBufferCreate ();
-    emit_pattern (surface, source, style, 0);
-    xmlBufferCat (style, CC2XML (" stroke: none;"));
-    xmlBufferCat (style, CC2XML (" fill-rule: "));
-    xmlBufferCat (style, fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? CC2XML("evenodd;") : CC2XML ("nonzero;"));
-
-    status = _cairo_path_fixed_interpret (path,
-					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_svg_path_move_to,
-					  _cairo_svg_path_line_to,
-					  _cairo_svg_path_curve_to,
-					  _cairo_svg_path_close_path,
-					  &info);
+    _cairo_output_stream_printf (surface->xml_node,
+ 				 "<path style=\"stroke: none; "
+ 				 "fill-rule: %s; ",
+ 				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
+ 				 "evenodd" : "nonzero");
+    emit_operator (surface->xml_node, surface, op);
+    emit_pattern (surface, source, surface->xml_node, FALSE);
+    _cairo_output_stream_printf (surface->xml_node, "\" ");
 
-    child = xmlNewChild (surface->xml_node, NULL, CC2XML ("path"), NULL);
-    xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
-    xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
-    emit_operator (child, surface, op);
+    status = emit_path (surface->xml_node, path, NULL);
 
-    xmlBufferFree (info.path);
-    xmlBufferFree (style);
+    _cairo_output_stream_printf (surface->xml_node, "/>\n");
 
     return status;
 }
@@ -1383,40 +1239,37 @@ _cairo_svg_surface_get_extents (void		  
     return CAIRO_STATUS_SUCCESS;
 }
 
-static xmlNodePtr
-emit_paint (xmlNodePtr		 node,
-	    cairo_svg_surface_t	*surface,
-	    cairo_operator_t	 op,
-	    cairo_pattern_t	*source)
-{
-    xmlNodePtr child;
-    xmlBufferPtr style;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
+static cairo_status_t
+emit_paint (cairo_output_stream_t *output,
+	    cairo_svg_surface_t   *surface,
+	    cairo_operator_t	   op,
+	    cairo_pattern_t	  *source,
+	    const char		  *extra_attributes)
+{
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	source->extend == CAIRO_EXTEND_NONE)
-	return emit_composite_pattern (node,
+	return emit_composite_pattern (output,
 				       surface,
 				       (cairo_surface_pattern_t *) source,
-				       NULL, NULL, FALSE);
+				       invalid_pattern_id,
+				       extra_attributes);
+
+    _cairo_output_stream_printf (output,
+				 "<rect x=\"0\" y=\"0\" "
+				 "width=\"%f\" height=\"%f\" "
+				 "style=\"",
+				 surface->width, surface->height);
+    emit_operator (output, surface, op);
+    emit_pattern (surface, source, output, FALSE);
+    _cairo_output_stream_printf (output, " stroke: none;\"");
+
+    if (extra_attributes)
+	_cairo_output_stream_printf (output, " %s", extra_attributes);
 
-    style = xmlBufferCreate ();
-    emit_pattern (surface, source, style, 0);
-    xmlBufferCat (style, CC2XML (" stroke: none;"));
-
-    child = xmlNewChild (node, NULL, CC2XML ("rect"), NULL);
-    xmlSetProp (child, CC2XML ("x"), CC2XML ("0"));
-    xmlSetProp (child, CC2XML ("y"), CC2XML ("0"));
-    _cairo_dtostr (buffer, sizeof buffer, surface->width);
-    xmlSetProp (child, CC2XML ("width"), C2XML (buffer));
-    _cairo_dtostr (buffer, sizeof buffer, surface->height);
-    xmlSetProp (child, CC2XML ("height"), C2XML (buffer));
-    xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
-    emit_operator (child, surface, op);
+    _cairo_output_stream_printf (output, "/>\n");
 
-    xmlBufferFree (style);
 
-    return child;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -1450,31 +1303,24 @@ _cairo_svg_surface_paint (void		    *abs
     if (surface->clip_level == 0 &&
 	(op == CAIRO_OPERATOR_CLEAR ||
 	 op == CAIRO_OPERATOR_SOURCE)) {
-	xmlNodePtr child = surface->xml_root_node->children;
-
-	while (child != NULL) {
-	    xmlUnlinkNode (child);
-	    xmlFreeNode (child);
-	    child = surface->xml_root_node->children;
-	}
+	_cairo_output_stream_destroy (surface->xml_node);
+	surface->xml_node = _cairo_memory_stream_create ();
 
 	if (op == CAIRO_OPERATOR_CLEAR) {
 	    if (surface->content == CAIRO_CONTENT_COLOR) {
-		xmlNodePtr rect;
-		char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
-
-		rect = xmlNewChild (surface->xml_node, NULL, CC2XML ("rect"), NULL);
-		_cairo_dtostr (buffer, sizeof buffer, surface->width);
-		xmlSetProp (rect, CC2XML ("width"), C2XML (buffer));
-		_cairo_dtostr (buffer, sizeof buffer, surface->height);
-		xmlSetProp (rect, CC2XML ("height"), C2XML (buffer));
-		xmlSetProp (rect, CC2XML ("style"), CC2XML ("opacity:1; stroke:none; fill:rgb(0,0,0);"));
+		_cairo_output_stream_printf (surface->xml_node,
+					     "<rect "
+					     "width=\"%f\" height=\"%f\" "
+					     "style=\"opacity: 1; "
+					     "stroke: none; "
+					     "fill: rgb(0,0,0);\"/>\n",
+					     surface->width, surface->height);
 	    }
 	    return CAIRO_STATUS_SUCCESS;
 	}
     }
 
-    emit_paint (surface->xml_node, surface, op, source);
+    emit_paint (surface->xml_node, surface, op, source, NULL);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1487,8 +1333,8 @@ _cairo_svg_surface_mask (void		    *abst
 {
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_svg_document_t *document = surface->document;
-    xmlNodePtr child, mask_node;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+    cairo_output_stream_t *mask_stream;
+    char buffer[64];
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _analyze_operation (surface, op, source);
@@ -1497,25 +1343,23 @@ _cairo_svg_surface_mask (void		    *abst
 
     emit_alpha_filter (document);
 
-    mask_node = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("mask"), NULL);
-    snprintf (buffer, sizeof buffer, "mask%d", document->mask_id);
-    xmlSetProp (mask_node, CC2XML ("id"), C2XML (buffer));
-    child = xmlNewChild (mask_node, NULL, CC2XML ("g"), NULL);
-    xmlSetProp (child, CC2XML ("filter"), CC2XML ("url(#alpha)"));
-    emit_paint (child, surface, op, mask);
-
-    /* mask node need to be located after surface it references,
-     * but also needs to be linked to xml tree for xlink namespace.
-     * So we unlink readd it here. */
-    xmlUnlinkNode (mask_node);
-    xmlAddChild (document->xml_node_defs, mask_node);
-
-    child = emit_paint (surface->xml_node, surface, op, source);
-
-    if (child) {
-	snprintf (buffer, sizeof buffer, "url(#mask%d)", document->mask_id);
-	xmlSetProp (child, CC2XML ("mask"), C2XML (buffer));
-    }
+    /* emit_paint() will output a pattern definition to
+     * document->xml_node_defs so we need to write the mask element to
+     * a temporary stream and then copy that to xml_node_defs. */
+    mask_stream = _cairo_memory_stream_create ();
+    _cairo_output_stream_printf (mask_stream,
+				 "<mask id=\"mask%d\">\n"
+				 "  <g filter=\"url(#alpha)\">\n",
+				 document->mask_id);
+    emit_paint (mask_stream, surface, op, mask, NULL);
+    _cairo_output_stream_printf (mask_stream,
+				 "  </g>\n"
+				 "</mask>\n");
+    _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
+
+    snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d);\"",
+	      document->mask_id);
+    emit_paint (surface->xml_node, surface, op, source, buffer);
 
     document->mask_id++;
 
@@ -1534,92 +1378,79 @@ _cairo_svg_surface_stroke (void			*abstr
 			   cairo_antialias_t	 antialias)
 {
     cairo_svg_surface_t *surface = abstract_dst;
-    cairo_svg_document_t *document = surface->document;
     cairo_status_t status;
-    xmlBufferPtr style;
-    xmlNodePtr child;
-    svg_path_info_t info;
+    const char *line_cap, *line_join;
     unsigned int i;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _analyze_operation (surface, op, source);
 
     assert (_operation_supported (surface, op, source));
 
-    info.document = document;
-    info.path = xmlBufferCreate ();
-    info.ctm_inverse = ctm_inverse;
-
-    style = xmlBufferCreate ();
-    emit_pattern (surface, source, style, 1);
-    xmlBufferCat (style, CC2XML ("fill: none; stroke-width: "));
-    _cairo_dtostr (buffer, sizeof buffer, stroke_style->line_width);
-    xmlBufferCat (style, C2XML (buffer));
-    xmlBufferCat (style, CC2XML (";"));
-
     switch (stroke_style->line_cap) {
-	    case CAIRO_LINE_CAP_BUTT:
-		    xmlBufferCat (style, CC2XML ("stroke-linecap: butt;"));
-		    break;
-	    case CAIRO_LINE_CAP_ROUND:
-		    xmlBufferCat (style, CC2XML ("stroke-linecap: round;"));
-		    break;
-	    case CAIRO_LINE_CAP_SQUARE:
-		    xmlBufferCat (style, CC2XML ("stroke-linecap: square;"));
-		    break;
+    case CAIRO_LINE_CAP_BUTT:
+ 	line_cap = "butt";
+ 	break;
+    case CAIRO_LINE_CAP_ROUND:
+ 	line_cap = "round";
+ 	break;
+    case CAIRO_LINE_CAP_SQUARE:
+ 	line_cap = "square";
+ 	break;
+    default:
+ 	ASSERT_NOT_REACHED;
     }
 
     switch (stroke_style->line_join) {
-	    case CAIRO_LINE_JOIN_MITER:
-		    xmlBufferCat (style, CC2XML ("stroke-linejoin: miter;"));
-		    break;
-	    case CAIRO_LINE_JOIN_ROUND:
-		    xmlBufferCat (style, CC2XML ("stroke-linejoin: round;"));
-		    break;
-	    case CAIRO_LINE_JOIN_BEVEL:
-		    xmlBufferCat (style, CC2XML ("stroke-linejoin: bevel;"));
-		    break;
-    }
+    case CAIRO_LINE_JOIN_MITER:
+ 	line_join = "miter";
+ 	break;
+    case CAIRO_LINE_JOIN_ROUND:
+ 	line_join = "round";
+ 	break;
+    case CAIRO_LINE_JOIN_BEVEL:
+ 	line_join = "bevel";
+ 	break;
+    default:
+ 	ASSERT_NOT_REACHED;
+    }
+
+    _cairo_output_stream_printf (surface->xml_node,
+ 				 "<path style=\"fill: none; "
+ 				 "stroke-width: %f; "
+ 				 "stroke-linecap: %s; "
+ 				 "stroke-linejoin: %s; ",
+				 stroke_style->line_width,
+ 				 line_cap,
+ 				 line_join);
+
+     emit_pattern (surface, source, surface->xml_node, TRUE);
+     emit_operator (surface->xml_node, surface, op);
 
     if (stroke_style->num_dashes > 0) {
-	xmlBufferCat (style, CC2XML (" stroke-dasharray: "));
+ 	_cairo_output_stream_printf (surface->xml_node, "stroke-dasharray: ");
 	for (i = 0; i < stroke_style->num_dashes; i++) {
-	    if (i != 0)
-		xmlBufferCat (style, CC2XML (","));
-	    _cairo_dtostr (buffer, sizeof buffer, stroke_style->dash[i]);
-	    xmlBufferCat (style, C2XML (buffer));
+ 	    _cairo_output_stream_printf (surface->xml_node, "%f",
+ 					 stroke_style->dash[i]);
+ 	    if (i + 1 < stroke_style->num_dashes)
+ 		_cairo_output_stream_printf (surface->xml_node, ",");
+ 	    else
+ 		_cairo_output_stream_printf (surface->xml_node, "; ");
 	}
-	xmlBufferCat (style, CC2XML (";"));
 	if (stroke_style->dash_offset != 0.0) {
-	    xmlBufferCat (style, CC2XML (" stroke-dashoffset: "));
-	    _cairo_dtostr (buffer, sizeof buffer, stroke_style->dash_offset);
-	    xmlBufferCat (style, C2XML (buffer));
-	    xmlBufferCat (style, CC2XML (";"));
+ 	    _cairo_output_stream_printf (surface->xml_node,
+ 					 "stroke-dashoffset: %f; ",
+ 					 stroke_style->dash_offset);
 	}
     }
 
-    xmlBufferCat (style, CC2XML (" stroke-miterlimit: "));
-    _cairo_dtostr (buffer, sizeof buffer, stroke_style->miter_limit);
-    xmlBufferCat (style, C2XML (buffer));
-    xmlBufferCat (style, CC2XML (";"));
+    _cairo_output_stream_printf (surface->xml_node,
+ 				 "stroke-miterlimit: %f;\" ",
+ 				 stroke_style->miter_limit);
 
-    status = _cairo_path_fixed_interpret (path,
-					  CAIRO_DIRECTION_FORWARD,
-					  _cairo_svg_path_move_to,
-					  _cairo_svg_path_line_to,
-					  _cairo_svg_path_curve_to,
-					  _cairo_svg_path_close_path,
-					  &info);
+    status = emit_path (surface->xml_node, path, ctm_inverse);
 
-    child = xmlNewChild (surface->xml_node, NULL, CC2XML ("path"), NULL);
-    emit_transform (child, "transform", ctm);
-    xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
-    xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
-    emit_operator (child, surface, op);
-
-    xmlBufferFree (info.path);
-    xmlBufferFree (style);
+    emit_transform (surface->xml_node, " transform", "/>\n", ctm);
 
     return status;
 }
@@ -1636,10 +1467,6 @@ _cairo_svg_surface_show_glyphs (void			*
     cairo_svg_document_t *document = surface->document;
     cairo_path_fixed_t path;
     cairo_status_t status;
-    xmlNodePtr glyph_node;
-    xmlNodePtr child;
-    xmlBufferPtr style;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
     unsigned int font_id, subset_id, subset_glyph_index;
     int i;
 
@@ -1657,11 +1484,9 @@ _cairo_svg_surface_show_glyphs (void			*
     if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
 	goto FALLBACK;
 
-    child = xmlNewChild (surface->xml_node, NULL, CC2XML ("g"), NULL);
-    style = xmlBufferCreate ();
-    emit_pattern (surface, pattern, style, 0);
-    xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
-    xmlBufferFree (style);
+    _cairo_output_stream_printf (surface->xml_node, "<g style=\"");
+    emit_pattern (surface, pattern, surface->xml_node, FALSE);
+    _cairo_output_stream_printf (surface->xml_node, "\">\n");
 
     for (i = 0; i < num_glyphs; i++) {
 	status = _cairo_scaled_font_subsets_map_glyph (document->font_subsets,
@@ -1673,16 +1498,15 @@ _cairo_svg_surface_show_glyphs (void			*
 	    goto FALLBACK;
 	}
 
-	glyph_node = xmlNewChild (child, NULL, CC2XML ("use"), NULL);
-	snprintf (buffer, sizeof buffer, "#glyph%d-%d",
-		  font_id, subset_glyph_index);
-	xmlSetProp (glyph_node, CC2XML ("xlink:href"), C2XML (buffer));
-	_cairo_dtostr (buffer, sizeof buffer, glyphs[i].x);
-	xmlSetProp (glyph_node, CC2XML ("x"), C2XML (buffer));
-	_cairo_dtostr (buffer, sizeof buffer, glyphs[i].y);
-	xmlSetProp (glyph_node, CC2XML ("y"), C2XML (buffer));
+	_cairo_output_stream_printf (surface->xml_node,
+				     "  <use xlink:href=\"#glyph%d-%d\" "
+				     "x=\"%f\" y=\"%f\"/>\n",
+				     font_id, subset_glyph_index,
+				     glyphs[i].x, glyphs[i].y);
     }
 
+    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+
     return CAIRO_STATUS_SUCCESS;
 
 FALLBACK:
@@ -1712,47 +1536,34 @@ _cairo_svg_surface_intersect_clip_path (
     cairo_svg_surface_t *surface = dst;
     cairo_svg_document_t *document = surface->document;
     cairo_status_t status;
-    xmlNodePtr group, clip, clip_path;
-    svg_path_info_t info;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+    int i;
 
     if (path == NULL) {
-	surface->xml_node = surface->xml_root_node;
+ 	for (i = 0; i < surface->clip_level; i++)
+ 	    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+
 	surface->clip_level = 0;
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    if (path != NULL) {
-	info.document = document;
-	info.path = xmlBufferCreate ();
-	info.ctm_inverse = NULL;
-
-	group = xmlNewChild (surface->xml_node, NULL, CC2XML ("g"), NULL);
-	clip = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("clipPath"), NULL);
-	snprintf (buffer, sizeof buffer, "clip%d", document->clip_id);
-	xmlSetProp (clip, CC2XML ("id"), C2XML (buffer));
-
-	clip_path = xmlNewChild (clip, NULL, CC2XML ("path"), NULL);
-	status = _cairo_path_fixed_interpret (path,
-					      CAIRO_DIRECTION_FORWARD,
-					      _cairo_svg_path_move_to,
-					      _cairo_svg_path_line_to,
-					      _cairo_svg_path_curve_to,
-					      _cairo_svg_path_close_path,
-					      &info);
-	xmlSetProp (clip_path, CC2XML ("d"), xmlBufferContent (info.path));
-	xmlBufferFree (info.path);
-
-	snprintf (buffer, sizeof buffer, "url(#clip%d)", document->clip_id);
-	xmlSetProp (group, CC2XML ("clip-path"), C2XML (buffer));
-	xmlSetProp (group, CC2XML ("clip-rule"),
-		    fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
-		    CC2XML ("evenodd") : CC2XML ("nonzero"));
-
-	document->clip_id++;
-	surface->xml_node = group;
-	surface->clip_level++;
-    }
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<clipPath id=\"clip%d\">\n"
+ 				 "  <path ",
+ 				 document->clip_id);
+    status = emit_path (document->xml_node_defs, path, NULL);
+    _cairo_output_stream_printf (document->xml_node_defs,
+ 				 "/>\n"
+ 				 "</clipPath>\n");
+
+    _cairo_output_stream_printf (surface->xml_node,
+				 "<g clip-path=\"url(#clip%d)\" "
+				 "clip-rule=\"%s\">\n",
+				 document->clip_id,
+				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
+				 "evenodd" : "nonzero");
+
+    document->clip_id++;
+    surface->clip_level++;
 
     return status;
 }
@@ -1804,10 +1615,6 @@ _cairo_svg_document_create (cairo_output
 			    cairo_svg_version_t		 version)
 {
     cairo_svg_document_t *document;
-    xmlDocPtr doc;
-    xmlNodePtr node;
-    xmlBufferPtr xml_buffer;
-    char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
 
     document = malloc (sizeof (cairo_svg_document_t));
     if (document == NULL) {
@@ -1838,48 +1645,13 @@ _cairo_svg_document_create (cairo_output
     document->clip_id = 0;
     document->mask_id = 0;
 
-    doc = xmlNewDoc (CC2XML ("1.0"));
-    node = xmlNewNode (NULL, CC2XML ("svg"));
-
-    xmlDocSetRootElement (doc, node);
-
-    document->xml_doc = doc;
-    document->xml_node_main = node;
-    document->xml_node_defs = xmlNewChild (node, NULL, CC2XML ("defs"), NULL);
-
-    xml_buffer = xmlBufferCreate ();
-
-    _cairo_dtostr (buffer, sizeof buffer, width);
-    xmlBufferCat (xml_buffer, C2XML (buffer));
-    xmlBufferCat (xml_buffer, CC2XML ("pt"));
-    xmlSetProp (node, CC2XML ("width"), C2XML (xmlBufferContent (xml_buffer)));
-    xmlBufferEmpty (xml_buffer);
-
-    _cairo_dtostr (buffer, sizeof buffer, height);
-    xmlBufferCat (xml_buffer, C2XML (buffer));
-    xmlBufferCat (xml_buffer, CC2XML ("pt"));
-    xmlSetProp (node, CC2XML ("height"), C2XML (xmlBufferContent (xml_buffer)));
-    xmlBufferEmpty (xml_buffer);
-
-    xmlBufferCat (xml_buffer, CC2XML ("0 0 "));
-    _cairo_dtostr (buffer, sizeof buffer, width);
-    xmlBufferCat (xml_buffer, C2XML (buffer));
-    xmlBufferCat (xml_buffer, CC2XML (" "));
-    _cairo_dtostr (buffer, sizeof buffer, height);
-    xmlBufferCat (xml_buffer, C2XML (buffer));
-    xmlSetProp (node, CC2XML ("viewBox"), C2XML (xmlBufferContent (xml_buffer)));
-
-    xmlBufferFree (xml_buffer);
-
-    xmlNewNs (node, CC2XML ("http://www.w3.org/2000/svg"), NULL);
-    xmlNewNs (node, CC2XML ("http://www.w3.org/1999/xlink"), CC2XML ("xlink"));
-
-    document->xml_node_glyphs = xmlNewChild (document->xml_node_defs, NULL,
-					     CC2XML ("g"), NULL);
+    document->xml_node_defs = _cairo_memory_stream_create ();
+    document->xml_node_glyphs = _cairo_memory_stream_create ();
 
     document->alpha_filter = FALSE;
 
-    _cairo_array_init (&document->meta_snapshots, sizeof (cairo_meta_snapshot_t));
+    _cairo_array_init (&document->meta_snapshots,
+		       sizeof (cairo_meta_snapshot_t));
 
     document->svg_version = version;
 
@@ -1906,47 +1678,56 @@ _cairo_svg_document_destroy (cairo_svg_d
     free (document);
 }
 
-static int
-_cairo_svg_document_write (cairo_output_stream_t *output_stream,
-			   const char * buffer,
-			   int len)
-{
-    cairo_status_t status;
-
-    _cairo_output_stream_write (output_stream, buffer, len);
-    status = _cairo_output_stream_get_status (output_stream);
-    if (status) {
-	_cairo_error (status);
-	return -1;
-    }
-
-    return len;
-}
-
 static cairo_status_t
 _cairo_svg_document_finish (cairo_svg_document_t *document)
 {
     cairo_status_t status;
     cairo_output_stream_t *output = document->output_stream;
     cairo_meta_snapshot_t *snapshot;
-    xmlOutputBufferPtr xml_output_buffer;
+    cairo_svg_surface_t *surface;
     unsigned int i;
 
     if (document->finished)
 	return CAIRO_STATUS_SUCCESS;
 
+    _cairo_output_stream_printf (output,
+				 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+				 "<svg xmlns=\"http://www.w3.org/2000/svg\" "
+				 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
+				 "width=\"%fpt\" height=\"%fpt\" "
+				 "viewBox=\"0 0 %f %f\" version=\"%s\">\n",
+				 document->width, document->height,
+				 document->width, document->height,
+				 _cairo_svg_internal_version_strings [document->svg_version]);
+
     _cairo_svg_document_emit_font_subsets (document);
+    if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
+	_cairo_memory_stream_length (document->xml_node_defs) > 0) {
+	_cairo_output_stream_printf (output, "<defs>\n");
+	if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
+	    _cairo_output_stream_printf (output, "<g>\n");
+	    _cairo_memory_stream_copy (document->xml_node_glyphs, output);
+	    _cairo_output_stream_printf (output, "</g>\n");
+	}
+	_cairo_memory_stream_copy (document->xml_node_defs, output);
+	_cairo_output_stream_printf (output, "</defs>\n");
+    }
+
+    surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
+    _cairo_output_stream_printf (output,
+				 "<g id=\"surface%d\" "
+				 "clip-path=\"url(#clip%d)\">\n",
+				 surface->id,
+				 surface->base_clip);
+    _cairo_memory_stream_copy (surface->xml_node, output);
 
-    xmlSetProp (document->xml_node_main, CC2XML ("version"),
-	CC2XML (_cairo_svg_internal_version_strings [document->svg_version]));
+    for (i = 0; i < surface->clip_level; i++)
+	_cairo_output_stream_printf (output, "</g>\n");
 
-    xml_output_buffer = xmlOutputBufferCreateIO ((xmlOutputWriteCallback) _cairo_svg_document_write,
-						 (xmlOutputCloseCallback) NULL,
-						 (void *) document->output_stream,
-						 NULL);
-    xmlSaveFormatFileTo (xml_output_buffer, document->xml_doc, "UTF-8", 1);
+    _cairo_output_stream_printf (output, "</g>\n</svg>\n");
 
-    xmlFreeDoc (document->xml_doc);
+    _cairo_output_stream_destroy (document->xml_node_glyphs);
+    _cairo_output_stream_destroy (document->xml_node_defs);
 
     status = _cairo_output_stream_get_status (output);
     _cairo_output_stream_destroy (output);
diff-tree 17d41d1f71a5d5af489bc395e3bb3cf414aeda57 (from 8581447e7b26f34c7be43fef7dfa5458f2278556)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Tue Jun 13 17:24:36 2006 -0400

    Only run fallback-resolution test case when all of PDF, PS and SVG are enabled.

diff --git a/test/Makefile.am b/test/Makefile.am
index f6a86e7..26fce87 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -21,7 +21,6 @@ dash-offset-negative		\
 dash-zero-length		\
 device-offset			\
 extend-reflect			\
-fallback-resolution		\
 fill-and-stroke			\
 fill-and-stroke-alpha		\
 fill-and-stroke-alpha-add	\
@@ -108,6 +107,14 @@ if CAIRO_HAS_MULTI_PAGE_SURFACES
 TESTS += multi-page
 endif
 
+if CAIRO_HAS_SVG_SURFACE
+if CAIRO_HAS_PDF_SURFACE
+if CAIRO_HAS_PS_SURFACE
+TESTS += fallback-resolution
+endif
+endif
+endif
+
 # XXX: Here are some existing tests that are currently disabled for
 # one reason or another.
 # 
diff-tree 8581447e7b26f34c7be43fef7dfa5458f2278556 (from d43321066081eacca2e0c86258c68bae49036087)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Mon Jun 12 03:15:33 2006 -0400

    Add an in-memory output-stream implementation.

diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 2ef7add..9ff9393 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -446,3 +446,62 @@ _cairo_output_stream_create_for_filename
 
     return &stream->base;
 }
+
+
+typedef struct _memory_stream {
+    cairo_output_stream_t	base;
+    cairo_array_t		array;
+} memory_stream_t;
+
+static cairo_status_t
+memory_write (cairo_output_stream_t *base,
+	      const unsigned char *data, unsigned int length)
+{
+    memory_stream_t *stream = (memory_stream_t *) base;
+
+    return _cairo_array_append_multiple (&stream->array, data, length);
+}
+
+static cairo_status_t
+memory_close (cairo_output_stream_t *base)
+{
+    memory_stream_t *stream = (memory_stream_t *) base;
+
+    _cairo_array_fini (&stream->array);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_output_stream_t *
+_cairo_memory_stream_create (void)
+{
+    memory_stream_t *stream;
+
+    stream = malloc (sizeof *stream);
+    if (stream == NULL)
+	return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+    _cairo_output_stream_init (&stream->base, memory_write, memory_close);
+    _cairo_array_init (&stream->array, 1);
+
+    return &stream->base;
+}
+
+void
+_cairo_memory_stream_copy (cairo_output_stream_t *base,
+			   cairo_output_stream_t *dest)
+{
+    memory_stream_t *stream = (memory_stream_t *) base;
+
+    _cairo_output_stream_write (dest, 
+				_cairo_array_index (&stream->array, 0),
+				_cairo_array_num_elements (&stream->array));
+}
+
+int
+_cairo_memory_stream_length (cairo_output_stream_t *base)
+{
+    memory_stream_t *stream = (memory_stream_t *) base;
+
+    return _cairo_array_num_elements (&stream->array);
+}
diff-tree d43321066081eacca2e0c86258c68bae49036087 (from 45cbe055d9cf4ac2cf2fbcd21b020c8f869a0380)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Mon Jun 12 03:10:40 2006 -0400

    Convert the word wrap stream, the base85 stream and the ps string stream.

diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c
index 2861a42..7163d00 100644
--- a/src/cairo-base85-stream.c
+++ b/src/cairo-base85-stream.c
@@ -38,6 +38,7 @@
 #include "cairo-output-stream-private.h"
 
 typedef struct _cairo_base85_stream {
+    cairo_output_stream_t base;
     cairo_output_stream_t *output;
     unsigned char four_tuple[4];
     int pending;
@@ -64,11 +65,11 @@ _expand_four_tuple_to_five (unsigned cha
 }
 
 static cairo_status_t
-_cairo_base85_stream_write (void		*closure,
-			    const unsigned char	*data,
-			    unsigned int	 length)
+_cairo_base85_stream_write (cairo_output_stream_t *base,
+			    const unsigned char	  *data,
+			    unsigned int	   length)
 {
-    cairo_base85_stream_t *stream = closure;
+    cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
     const unsigned char *ptr = data;
     unsigned char five_tuple[5];
     cairo_bool_t is_zero;
@@ -90,10 +91,9 @@ _cairo_base85_stream_write (void		*closu
 }
 
 static cairo_status_t
-_cairo_base85_stream_close (void *closure)
+_cairo_base85_stream_close (cairo_output_stream_t *base)
 {
-    cairo_status_t status;
-    cairo_base85_stream_t *stream = closure;
+    cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
     unsigned char five_tuple[5];
 
     if (stream->pending) {
@@ -105,11 +105,7 @@ _cairo_base85_stream_close (void *closur
     /* Mark end of base85 data */
     _cairo_output_stream_printf (stream->output, "~>");
 
-    status = _cairo_output_stream_get_status (stream->output);
-
-    free (stream);
-
-    return status;
+    return _cairo_output_stream_get_status (stream->output);
 }
 
 cairo_output_stream_t *
@@ -121,10 +117,11 @@ _cairo_base85_stream_create (cairo_outpu
     if (stream == NULL)
 	return (cairo_output_stream_t *) &cairo_output_stream_nil;
 
+    _cairo_output_stream_init (&stream->base,
+			       _cairo_base85_stream_write,
+			       _cairo_base85_stream_close);
     stream->output = output;
     stream->pending = 0;
 
-    return _cairo_output_stream_create (_cairo_base85_stream_write,
-					_cairo_base85_stream_close,
-					stream);
+    return &stream->base;
 }
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 53d6468..bed1f9f 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -757,6 +757,7 @@ cairo_ps_surface_dsc_begin_page_setup (c
  * max_column it will not be broken up.
  */
 typedef struct _word_wrap_stream {
+    cairo_output_stream_t base;
     cairo_output_stream_t *output;
     int max_column;
     int column;
@@ -779,11 +780,11 @@ _count_word_up_to (const unsigned char *
 }
 
 static cairo_status_t
-_word_wrap_stream_write (void			*closure,
+_word_wrap_stream_write (cairo_output_stream_t  *base,
 			 const unsigned char	*data,
 			 unsigned int		 length)
 {
-    word_wrap_stream_t *stream = closure;
+    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
     cairo_bool_t newline;
     int word;
 
@@ -824,16 +825,11 @@ _word_wrap_stream_write (void			*closure
 }
 
 static cairo_status_t
-_word_wrap_stream_close (void *closure)
+_word_wrap_stream_close (cairo_output_stream_t *base)
 {
-    cairo_status_t status;
-    word_wrap_stream_t *stream = closure;
-
-    status = _cairo_output_stream_get_status (stream->output);
-
-    free (stream);
+    word_wrap_stream_t *stream = (word_wrap_stream_t *) base;
 
-    return status;
+    return _cairo_output_stream_get_status (stream->output);
 }
 
 static cairo_output_stream_t *
@@ -845,13 +841,15 @@ _word_wrap_stream_create (cairo_output_s
     if (stream == NULL)
 	return (cairo_output_stream_t *) &cairo_output_stream_nil;
 
+    _cairo_output_stream_init (&stream->base,
+			       _word_wrap_stream_write,
+			       _word_wrap_stream_close);
     stream->output = output;
     stream->max_column = max_column;
     stream->column = 0;
     stream->last_write_was_space = FALSE;
 
-    return _cairo_output_stream_create (_word_wrap_stream_write,
-					_word_wrap_stream_close, stream);
+    return &stream->base;
 }
 
 static cairo_surface_t *
@@ -1099,17 +1097,18 @@ _analyze_operation (cairo_ps_surface_t *
 #define STRING_ARRAY_MAX_COLUMN	     72
 
 typedef struct _string_array_stream {
+    cairo_output_stream_t base;
     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_write (cairo_output_stream_t *base,
+			    const unsigned char   *data,
+			    unsigned int	   length)
 {
-    string_array_stream_t *stream = closure;
+    string_array_stream_t *stream = (string_array_stream_t *) base;
     unsigned char c;
     const unsigned char backslash = '\\';
 
@@ -1152,17 +1151,15 @@ _string_array_stream_write (void		*closu
 }
 
 static cairo_status_t
-_string_array_stream_close (void *closure)
+_string_array_stream_close (cairo_output_stream_t *base)
 {
     cairo_status_t status;
-    string_array_stream_t *stream = closure;
+    string_array_stream_t *stream = (string_array_stream_t *) base;
 
     _cairo_output_stream_printf (stream->output, ")\n");
 
     status = _cairo_output_stream_get_status (stream->output);
 
-    free (stream);
-
     return status;
 }
 
@@ -1189,13 +1186,14 @@ _string_array_stream_create (cairo_outpu
     if (stream == NULL)
 	return (cairo_output_stream_t *) &cairo_output_stream_nil;
 
+    _cairo_output_stream_init (&stream->base,
+			       _string_array_stream_write,
+			       _string_array_stream_close);
     stream->output = output;
     stream->column = 0;
     stream->string_size = 0;
 
-    return _cairo_output_stream_create (_string_array_stream_write,
-					_string_array_stream_close,
-					stream);
+    return &stream->base;
 }
 
 /* PS Output - this section handles output of the parts of the meta
diff-tree 45cbe055d9cf4ac2cf2fbcd21b020c8f869a0380 (from 3575c942f81d54c88fd48aee2352ecd29406e711)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Mon Jun 12 03:08:51 2006 -0400

    Convert the stdio output stream to use the new output stream interface.

diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index c71b89f..2ef7add 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -365,39 +365,46 @@ _cairo_output_stream_get_status (cairo_o
 /* Maybe this should be a configure time option, so embedded targets
  * don't have to pull in stdio. */
 
+
+typedef struct _stdio_stream {
+    cairo_output_stream_t	 base;
+    FILE			*file;
+} stdio_stream_t;
+
 static cairo_status_t
-stdio_write (void *closure, const unsigned char *data, unsigned int length)
+stdio_write (cairo_output_stream_t *base,
+	     const unsigned char *data, unsigned int length)
 {
-    FILE *file = closure;
+    stdio_stream_t *stream = (stdio_stream_t *) base;
 
-    if (fwrite (data, 1, length, file) != length)
+    if (fwrite (data, 1, length, stream->file) != length)
 	return CAIRO_STATUS_WRITE_ERROR;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-stdio_flush (void *closure)
+stdio_flush (cairo_output_stream_t *base)
 {
-    FILE *file = closure;
+    stdio_stream_t *stream = (stdio_stream_t *) base;
 
-    fflush (file);
+    fflush (stream->file);
 
-    if (ferror (file))
+    if (ferror (stream->file))
 	return CAIRO_STATUS_WRITE_ERROR;
     else
 	return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-stdio_close (void *closure)
+stdio_close (cairo_output_stream_t *base)
 {
     cairo_status_t status;
-    FILE *file = closure;
+    stdio_stream_t *stream = (stdio_stream_t *) base;
 
-    status = stdio_flush (closure);
+    status = stdio_flush (base);
 
-    fclose (file);
+    fclose (stream->file);
 
     return status;
 }
@@ -405,20 +412,37 @@ stdio_close (void *closure)
 cairo_output_stream_t *
 _cairo_output_stream_create_for_file (FILE *file)
 {
+    stdio_stream_t *stream;
+
     if (file == NULL)
 	return (cairo_output_stream_t *) &cairo_output_stream_nil_write_error;
 
-    return _cairo_output_stream_create (stdio_write, stdio_flush, file);
+    stream = malloc (sizeof *stream);
+    if (stream == NULL)
+	return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+    _cairo_output_stream_init (&stream->base, stdio_write, stdio_flush);
+    stream->file = file;
+
+    return &stream->base;
 }
 
 cairo_output_stream_t *
 _cairo_output_stream_create_for_filename (const char *filename)
 {
+    stdio_stream_t *stream;
     FILE *file;
 
     file = fopen (filename, "wb");
     if (file == NULL)
 	return (cairo_output_stream_t *) &cairo_output_stream_nil_write_error;
 
-    return _cairo_output_stream_create (stdio_write, stdio_close, file);
+    stream = malloc (sizeof *stream);
+    if (stream == NULL)
+	return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+    _cairo_output_stream_init (&stream->base, stdio_write, stdio_close);
+    stream->file = file;
+
+    return &stream->base;
 }
diff-tree 3575c942f81d54c88fd48aee2352ecd29406e711 (from 79928101352a84af1884e993fd06bf6cd44f2af3)
Author: Kristian Høgsberg <krh at redhat.com>
Date:   Mon Jun 12 03:07:19 2006 -0400

    Make cairo_output_stream_t an embeddable type.
    
    Most internal cairo types are transparent within cairo and have init and fini
    functions to intialize and finialize them in place.  This way they can be
    easily be embedded in other structs or derived from.  Initially, the
    cairo_output_stream_t type was proposed as a publically visible type and
    thus kept opaque.  However, now it's only used internally and derived from
    in a number of places so let's make it an embeddable type for consistency
    and ease of use.
    
    The patch keeps _cairo_output_stream_create() and _cairo_output_stream_close()
    around for (internal) backwards compatibility by deriving a
    cairo_output_stream_with_closure_t stream type.
    
    The patch also moves all cairo_output_stream_t functions out of cairoint.h
    and into new file cairo-output-stream-private.h, thus chipping away at the
    monolithic cairoint.h.

diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c
index d42700d..2861a42 100644
--- a/src/cairo-base85-stream.c
+++ b/src/cairo-base85-stream.c
@@ -35,6 +35,7 @@
  */
 
 #include "cairoint.h"
+#include "cairo-output-stream-private.h"
 
 typedef struct _cairo_base85_stream {
     cairo_output_stream_t *output;
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 5ef36e5..c71b89f 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -1,4 +1,4 @@
-/* cairo_output_stream.c: Output stream abstraction
+/* cairo-output-stream.c: Output stream abstraction
  *
  * Copyright © 2005 Red Hat, Inc
  *
@@ -38,24 +38,35 @@
 #include <locale.h>
 #include <ctype.h>
 #include "cairoint.h"
+#include "cairo-output-stream-private.h"
 
 #ifdef _MSC_VER
 #define snprintf _snprintf
 #endif /* _MSC_VER */
 
-struct _cairo_output_stream {
-    cairo_write_func_t		write_func;
-    cairo_close_func_t		close_func;
-    void			*closure;
-    unsigned long		position;
-    cairo_status_t		status;
-    cairo_bool_t		closed;
-};
+
+cairo_private void
+_cairo_output_stream_init (cairo_output_stream_t            *stream,
+			   cairo_output_stream_write_func_t  write_func,
+			   cairo_output_stream_close_func_t  close_func)
+{
+    stream->write_func = write_func;
+    stream->close_func = close_func;
+    stream->position = 0;
+    stream->status = CAIRO_STATUS_SUCCESS;
+    stream->closed = FALSE;
+}
+
+cairo_private void
+_cairo_output_stream_fini (cairo_output_stream_t *stream)
+{
+    _cairo_output_stream_close (stream);
+}
+
 
 const cairo_output_stream_t cairo_output_stream_nil = {
     NULL, /* write_func */
     NULL, /* close_func */
-    NULL, /* closure */
     0,    /* position */
     CAIRO_STATUS_NO_MEMORY,
     FALSE /* closed */
@@ -64,31 +75,56 @@ const cairo_output_stream_t cairo_output
 static const cairo_output_stream_t cairo_output_stream_nil_write_error = {
     NULL, /* write_func */
     NULL, /* close_func */
-    NULL, /* closure */
     0,    /* position */
     CAIRO_STATUS_WRITE_ERROR,
     FALSE /* closed */
 };
 
+typedef struct _cairo_output_stream_with_closure {
+    cairo_output_stream_t	 base;
+    cairo_write_func_t		 write_func;
+    cairo_close_func_t		 close_func;
+    void			*closure;
+} cairo_output_stream_with_closure_t;
+
+
+static cairo_status_t
+closure_write (cairo_output_stream_t *stream,
+	       const unsigned char *data, unsigned int length)
+{
+    cairo_output_stream_with_closure_t *stream_with_closure =
+	(cairo_output_stream_with_closure_t *) stream;
+
+    return stream_with_closure->write_func (stream_with_closure->closure,
+					    data, length);
+}
+
+static cairo_status_t
+closure_close (cairo_output_stream_t *stream)
+{
+    cairo_output_stream_with_closure_t *stream_with_closure =
+	(cairo_output_stream_with_closure_t *) stream;
+
+    return stream_with_closure->close_func (stream_with_closure->closure);
+}
+
 cairo_output_stream_t *
 _cairo_output_stream_create (cairo_write_func_t		write_func,
 			     cairo_close_func_t		close_func,
 			     void			*closure)
 {
-    cairo_output_stream_t *stream;
+    cairo_output_stream_with_closure_t *stream;
 
-    stream = malloc (sizeof (cairo_output_stream_t));
+    stream = malloc (sizeof (cairo_output_stream_with_closure_t));
     if (stream == NULL)
 	return (cairo_output_stream_t *) &cairo_output_stream_nil;
 
+    _cairo_output_stream_init (&stream->base, closure_write, closure_close);
     stream->write_func = write_func;
     stream->close_func = close_func;
     stream->closure = closure;
-    stream->position = 0;
-    stream->status = CAIRO_STATUS_SUCCESS;
-    stream->closed = FALSE;
 
-    return stream;
+    return &stream->base;
 }
 
 void
@@ -106,7 +142,7 @@ _cairo_output_stream_close (cairo_output
     }
 
     if (stream->close_func) {
-	status = stream->close_func (stream->closure);
+	status = stream->close_func (stream);
 	if (status)
 	    stream->status = status;
     }
@@ -120,7 +156,7 @@ _cairo_output_stream_destroy (cairo_outp
     if (stream == NULL)
 	return;
 
-    _cairo_output_stream_close (stream);
+    _cairo_output_stream_fini (stream);
     free (stream);
 }
 
@@ -134,7 +170,7 @@ _cairo_output_stream_write (cairo_output
     if (stream->status)
 	return;
 
-    stream->status = stream->write_func (stream->closure, data, length);
+    stream->status = stream->write_func (stream, data, length);
     stream->position += length;
 }
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index c0586b9..cca02a6 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -43,6 +43,7 @@
 #include "cairo-ft-private.h"
 #include "cairo-paginated-surface-private.h"
 #include "cairo-path-fixed-private.h"
+#include "cairo-output-stream-private.h"
 
 #include <time.h>
 #include <zlib.h>
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index a621670..53d6468 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -44,6 +44,7 @@
 #include "cairo-paginated-surface-private.h"
 #include "cairo-meta-surface-private.h"
 #include "cairo-ft-private.h"
+#include "cairo-output-stream-private.h"
 
 #include <time.h>
 #include <zlib.h>
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 6d43119..893ef89 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -46,6 +46,7 @@
 #include "cairo-meta-surface-private.h"
 #include "cairo-paginated-surface-private.h"
 #include "cairo-scaled-font-subsets-private.h"
+#include "cairo-output-stream-private.h"
 
 #include <libxml/tree.h>
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 78062a7..91e4502 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2191,90 +2191,6 @@ _cairo_utf8_to_utf16 (const unsigned cha
 		      uint16_t		 **result,
 		      int		  *items_written);
 
-/* cairo_output_stream.c */
-
-typedef struct _cairo_output_stream cairo_output_stream_t;
-
-extern const cairo_private cairo_output_stream_t cairo_output_stream_nil;
-
-/* We already have the following declared in cairo.h:
-
-typedef cairo_status_t (*cairo_write_func_t) (void		  *closure,
-					      const unsigned char *data,
-					      unsigned int	   length);
-*/
-typedef cairo_status_t (*cairo_close_func_t) (void *closure);
-
-/* This function never returns NULL. If an error occurs (NO_MEMORY)
- * while trying to create the output stream this function returns a
- * valid pointer to a nil output stream.
- *
- * Note that even with a nil surface, the close_func callback will be
- * called by a call to _cairo_output_stream_close or
- * _cairo_output_stream_destroy.
- */
-cairo_private cairo_output_stream_t *
-_cairo_output_stream_create (cairo_write_func_t		write_func,
-			     cairo_close_func_t		close_func,
-			     void			*closure);
-
-cairo_private void
-_cairo_output_stream_close (cairo_output_stream_t *stream);
-
-cairo_private void
-_cairo_output_stream_destroy (cairo_output_stream_t *stream);
-
-cairo_private void
-_cairo_output_stream_write (cairo_output_stream_t *stream,
-			    const void *data, size_t length);
-
-cairo_private void
-_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
-				       const char *data,
-				       size_t length);
-
-cairo_private unsigned char *
-_cairo_lzw_compress (unsigned char *data, unsigned long *data_size_in_out);
-
-cairo_private void
-_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
-			      const char *fmt, va_list ap);
-
-cairo_private void
-_cairo_output_stream_printf (cairo_output_stream_t *stream,
-			     const char *fmt, ...) CAIRO_PRINTF_FORMAT(2, 3);
-
-cairo_private long
-_cairo_output_stream_get_position (cairo_output_stream_t *status);
-
-cairo_private cairo_status_t
-_cairo_output_stream_get_status (cairo_output_stream_t *stream);
-
-/* This function never returns NULL. If an error occurs (NO_MEMORY or
- * WRITE_ERROR) while trying to create the output stream this function
- * returns a valid pointer to a nil output stream.
- *
- * NOTE: Even if a nil surface is returned, the caller should still
- * call _cairo_output_stream_destroy (or _cairo_output_stream_close at
- * least) in order to ensure that everything is properly cleaned up.
- */
-cairo_private cairo_output_stream_t *
-_cairo_output_stream_create_for_filename (const char *filename);
-
-/* This function never returns NULL. If an error occurs (NO_MEMORY or
- * WRITE_ERROR) while trying to create the output stream this function
- * returns a valid pointer to a nil output stream.
- *
- * The caller still "owns" file and is responsible for calling fclose
- * on it when finished. The stream will not do this itself.
- */
-cairo_private cairo_output_stream_t *
-_cairo_output_stream_create_for_file (FILE *file);
-
-/* cairo_base85_stream.c */
-cairo_output_stream_t *
-_cairo_base85_stream_create (cairo_output_stream_t *output);
-
 cairo_private void
 _cairo_error (cairo_status_t status);
 


More information about the cairo-commit mailing list