diff --git a/configure.in b/configure.in index fcb72b921..cbe6a7f0d 100644 --- a/configure.in +++ b/configure.in @@ -545,17 +545,6 @@ CAIRO_BACKEND_ENABLE(svg, SVG, auto, svg, [], [ 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" @@ -572,9 +561,6 @@ AM_CONDITIONAL(CAIRO_CAN_TEST_SVG_SURFACE, test "x$test_svg" = "xyes") 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 --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c index d42700de9..7163d0092 100644 --- a/src/cairo-base85-stream.c +++ b/src/cairo-base85-stream.c @@ -35,8 +35,10 @@ */ #include "cairoint.h" +#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; @@ -63,11 +65,11 @@ _expand_four_tuple_to_five (unsigned char four_tuple[4], } 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; @@ -89,10 +91,9 @@ _cairo_base85_stream_write (void *closure, } 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) { @@ -104,11 +105,7 @@ _cairo_base85_stream_close (void *closure) /* 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 * @@ -120,10 +117,11 @@ _cairo_base85_stream_create (cairo_output_stream_t *output) 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-output-stream-private.h b/src/cairo-output-stream-private.h new file mode 100644 index 000000000..d1eeeeb49 --- /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 + */ + +#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 --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c index 5ef36e5fd..9ff939371 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 #include #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_stream_nil = { 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_stream_t *stream) } 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_output_stream_t *stream) 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_stream_t *stream, if (stream->status) return; - stream->status = stream->write_func (stream->closure, data, length); + stream->status = stream->write_func (stream, data, length); stream->position += length; } @@ -329,39 +365,46 @@ _cairo_output_stream_get_status (cairo_output_stream_t *stream) /* Maybe this should be a configure time option, so embedded targets * don't have to pull in stdio. */ -static cairo_status_t -stdio_write (void *closure, const unsigned char *data, unsigned int length) -{ - FILE *file = closure; - if (fwrite (data, 1, length, file) != length) +typedef struct _stdio_stream { + cairo_output_stream_t base; + FILE *file; +} stdio_stream_t; + +static cairo_status_t +stdio_write (cairo_output_stream_t *base, + const unsigned char *data, unsigned int length) +{ + stdio_stream_t *stream = (stdio_stream_t *) base; + + 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; } @@ -369,20 +412,96 @@ 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; +} + + +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 --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 7382f76b1..d417c5577 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 #include diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 00e046855..729639e52 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 #include @@ -99,6 +100,7 @@ typedef struct cairo_ps_surface { * 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; @@ -121,11 +123,11 @@ _count_word_up_to (const unsigned char *s, int length) } 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; @@ -166,16 +168,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; + word_wrap_stream_t *stream = (word_wrap_stream_t *) base; - status = _cairo_output_stream_get_status (stream->output); - - free (stream); - - return status; + return _cairo_output_stream_get_status (stream->output); } static cairo_output_stream_t * @@ -187,13 +184,15 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column) 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 @@ -1271,17 +1270,18 @@ _analyze_operation (cairo_ps_surface_t *surface, #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 = '\\'; @@ -1324,17 +1324,15 @@ _string_array_stream_write (void *closure, } 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; } @@ -1361,13 +1359,14 @@ _string_array_stream_create (cairo_output_stream_t *output) 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 --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 6d43119fe..9a3bda44f 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -46,17 +46,13 @@ #include "cairo-meta-surface-private.h" #include "cairo-paginated-surface-private.h" #include "cairo-scaled-font-subsets-private.h" - -#include - -#define CC2XML(s) ((const xmlChar *)(s)) -#define C2XML(s) ((xmlChar *)(s)) - -#define CAIRO_SVG_DTOSTR_BUFFER_LEN 30 +#include "cairo-output-stream-private.h" 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, @@ -84,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; @@ -118,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; }; @@ -339,9 +333,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *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) { @@ -360,36 +351,23 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, surface->clip_level = 0; surface->id = document->surface_id++; - clip_id = document->clip_id++; + surface->base_clip = document->clip_id++; - 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)); + _cairo_output_stream_printf (document->xml_node_defs, + "\n" + " \n" + "\n", + surface->base_clip, + width, height); - /* 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, + "\n", + width, height); } surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; @@ -427,8 +405,7 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream, typedef struct { - cairo_svg_document_t *document; - xmlBufferPtr path; + cairo_output_stream_t *output; cairo_matrix_t *ctm_inverse; } svg_path_info_t; @@ -436,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; } @@ -459,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; } @@ -486,8 +446,6 @@ _cairo_svg_path_curve_to (void *closure, 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); @@ -501,25 +459,9 @@ _cairo_svg_path_curve_to (void *closure, 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; } @@ -529,11 +471,36 @@ _cairo_svg_path_close_path (void *closure) { 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, @@ -543,9 +510,6 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document, { 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, @@ -566,29 +530,15 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document, return; } - info.document = document; - info.path = xmlBufferCreate (); - info.ctm_inverse = NULL; + _cairo_output_stream_printf (document->xml_node_glyphs, + "\n" + "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 (document->xml_node_glyphs, scaled_glyph->path, NULL); - 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;")); - - xmlBufferFree (info.path); + _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n\n"); } static void @@ -680,14 +630,12 @@ _cairo_svg_surface_finish (void *abstract_surface) 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); @@ -697,60 +645,39 @@ _cairo_svg_surface_finish (void *abstract_surface) static void emit_alpha_filter (cairo_svg_document_t *document) { - if (!document->alpha_filter) { - xmlNodePtr node; - xmlNodePtr child; + if (document->alpha_filter) + return; - 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; - } + _cairo_output_stream_printf (document->xml_node_defs, + "\n" + " \n" + "\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]; @@ -800,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; } @@ -814,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++) @@ -852,66 +772,65 @@ _cairo_surface_base64_encode (cairo_surface_t *surface, 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_base64_encode (surface, &image_buffer); + status = _cairo_surface_acquire_source_image (pattern->surface, + &image, &image_extra); if (status) - goto BAIL; + return status; - 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))); + p2u = pattern->base.matrix; + cairo_matrix_invert (&p2u); - xmlBufferFree (image_buffer); - - 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, + "width, image->height); + emit_transform (output, " patternTransform", ">\n", &p2u); } - if (width != NULL) - *width = image->width; - if (height != NULL) - *height = image->height; + _cairo_output_stream_printf (output, + " width, image->height); + + if (pattern_id == invalid_pattern_id) + emit_transform (output, " transform", "", &p2u); + + if (extra_attributes) + _cairo_output_stream_printf (output, " %s", extra_attributes); + + _cairo_output_stream_printf (output, " xlink:href=\""); + + status = _cairo_surface_base64_encode (pattern->surface, output); + + _cairo_output_stream_printf (output, "\"/>\n"); + + if (pattern_id != invalid_pattern_id) + _cairo_output_stream_printf (output, "\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; @@ -932,7 +851,6 @@ emit_meta_surface (cairo_svg_document_t *document, 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, @@ -950,78 +868,114 @@ emit_meta_surface (cairo_svg_document_t *document, 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, + "\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, + "\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, "\n"); + + _cairo_output_stream_printf (document->xml_node_defs, "\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, + "width_pixels, + meta_surface->height_pixels); + emit_transform (output, " patternTransform", ">\n", &p2u); } - if (width != NULL) - *width = meta_surface->width_pixels; - if (height != NULL) - *height = meta_surface->height_pixels; + _cairo_output_stream_printf (output, + "\n"); + + if (pattern_id != invalid_pattern_id) + _cairo_output_stream_printf (output, "\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", @@ -1037,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]; + int pattern_id; - child = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("pattern"), NULL); + pattern_id = document->pattern_id++; + emit_composite_pattern (document->xml_node_defs, surface, pattern, + pattern_id, 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)); - - p2u = pattern->base.matrix; - cairo_matrix_invert (&p2u); - - emit_transform (child, "patternTransform", &p2u); - - xmlSetProp (child, CC2XML ("patternUnits"), CC2XML ("userSpaceOnUse")); + _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, + "\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; @@ -1167,94 +1069,58 @@ emit_pattern_extend (xmlNodePtr node, cairo_extend_t extend) /* 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, + "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_transform (child, "gradientTransform", &p2u); + emit_pattern_stops (document->xml_node_defs ,&pattern->base, 0.0); + + _cairo_output_stream_printf (document->xml_node_defs, + "\n"); + + _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); @@ -1271,44 +1137,52 @@ emit_radial_pattern (cairo_svg_surface_t *surface, 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, + "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_transform (child, "gradientTransform", &p2u); + emit_pattern_stops (document->xml_node_defs, &pattern->base, r0 / r1); + + _cairo_output_stream_printf (document->xml_node_defs, + "\n"); + + _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; } } @@ -1323,42 +1197,25 @@ _cairo_svg_surface_fill (void *abstract_surface, 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; + _cairo_output_stream_printf (surface->xml_node, + "xml_node, surface, op); + emit_pattern (surface, source, surface->xml_node, FALSE); + _cairo_output_stream_printf (surface->xml_node, "\" "); - 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 = emit_path (surface->xml_node, 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); - - 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); - - xmlBufferFree (info.path); - xmlBufferFree (style); + _cairo_output_stream_printf (surface->xml_node, "/>\n"); return status; } @@ -1382,40 +1239,37 @@ _cairo_svg_surface_get_extents (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static xmlNodePtr -emit_paint (xmlNodePtr node, - cairo_svg_surface_t *surface, - cairo_operator_t op, - cairo_pattern_t *source) +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) { - xmlNodePtr child; - xmlBufferPtr style; - char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN]; - 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); - style = xmlBufferCreate (); - emit_pattern (surface, source, style, 0); - xmlBufferCat (style, CC2XML (" stroke: none;")); + _cairo_output_stream_printf (output, + "width, surface->height); + emit_operator (output, surface, op); + emit_pattern (surface, source, output, FALSE); + _cairo_output_stream_printf (output, " 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); + if (extra_attributes) + _cairo_output_stream_printf (output, " %s", extra_attributes); - xmlBufferFree (style); + _cairo_output_stream_printf (output, "/>\n"); - return child; + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -1449,31 +1303,24 @@ _cairo_svg_surface_paint (void *abstract_surface, 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, + "\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; } @@ -1486,8 +1333,8 @@ _cairo_svg_surface_mask (void *abstract_surface, { 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); @@ -1496,25 +1343,23 @@ _cairo_svg_surface_mask (void *abstract_surface, 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); + /* 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, + "\n" + " \n", + document->mask_id); + emit_paint (mask_stream, surface, op, mask, NULL); + _cairo_output_stream_printf (mask_stream, + " \n" + "\n"); + _cairo_memory_stream_copy (mask_stream, document->xml_node_defs); - /* 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)); - } + snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d);\"", + document->mask_id); + emit_paint (surface->xml_node, surface, op, source, buffer); document->mask_id++; @@ -1533,92 +1378,79 @@ _cairo_svg_surface_stroke (void *abstract_dst, 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, + "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; } @@ -1635,10 +1467,6 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, 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; @@ -1656,11 +1484,9 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, 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, "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, @@ -1672,16 +1498,15 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, 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, + " \n", + font_id, subset_glyph_index, + glyphs[i].x, glyphs[i].y); } + _cairo_output_stream_printf (surface->xml_node, "\n"); + return CAIRO_STATUS_SUCCESS; FALLBACK: @@ -1711,47 +1536,34 @@ _cairo_svg_surface_intersect_clip_path (void *dst, 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, "\n"); + surface->clip_level = 0; return CAIRO_STATUS_SUCCESS; } - if (path != NULL) { - info.document = document; - info.path = xmlBufferCreate (); - info.ctm_inverse = NULL; + _cairo_output_stream_printf (document->xml_node_defs, + "\n" + " clip_id); + status = emit_path (document->xml_node_defs, path, NULL); + _cairo_output_stream_printf (document->xml_node_defs, + "/>\n" + "\n"); - 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)); + _cairo_output_stream_printf (surface->xml_node, + "\n", + document->clip_id, + fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? + "evenodd" : "nonzero"); - 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++; - } + document->clip_id++; + surface->clip_level++; return status; } @@ -1803,10 +1615,6 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, 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) { @@ -1837,48 +1645,13 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, 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; @@ -1905,47 +1678,56 @@ _cairo_svg_document_destroy (cairo_svg_document_t *document) 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, + "\n" + "\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, "\n"); + if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) { + _cairo_output_stream_printf (output, "\n"); + _cairo_memory_stream_copy (document->xml_node_glyphs, output); + _cairo_output_stream_printf (output, "\n"); + } + _cairo_memory_stream_copy (document->xml_node_defs, output); + _cairo_output_stream_printf (output, "\n"); + } - xmlSetProp (document->xml_node_main, CC2XML ("version"), - CC2XML (_cairo_svg_internal_version_strings [document->svg_version])); + surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner); + _cairo_output_stream_printf (output, + "\n", + surface->id, + surface->base_clip); + _cairo_memory_stream_copy (surface->xml_node, output); - 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); + for (i = 0; i < surface->clip_level; i++) + _cairo_output_stream_printf (output, "\n"); - xmlFreeDoc (document->xml_doc); + _cairo_output_stream_printf (output, "\n\n"); + + _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 --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index 703529cb8..1daa2f477 100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -35,6 +35,7 @@ #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" diff --git a/src/cairoint.h b/src/cairoint.h index c08bd06a0..45173c766 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -2191,90 +2191,6 @@ _cairo_utf8_to_utf16 (const unsigned char *str, 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); diff --git a/test/Makefile.am b/test/Makefile.am index d92014f6a..1d7f2ff7a 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 \ @@ -109,6 +108,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. #