diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-08-18 14:25:25 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2009-08-29 17:07:34 +0100 |
commit | 425b0e35e2d7d44d99e22169b98fc3ca05763650 (patch) | |
tree | 0ec758a1b0e3eec62c7a0de9c04d2ee3cc33f339 | |
parent | 6e0b3be903a6c3ad948de95f490cff92430429a6 (diff) |
Add xml surface
A very simple surface that produces a hierarchical DAG in a simple XML
format. It is intended to be used whilst debugging, for example with the
automatic regression finding tools of cairo-sphinx, and with test suites
that just want to verify that their code made a particular Cairo call.
-rw-r--r-- | boilerplate/Makefile.win32.features | 10 | ||||
-rw-r--r-- | build/Makefile.win32.features | 1 | ||||
-rw-r--r-- | build/Makefile.win32.features-h | 3 | ||||
-rw-r--r-- | build/configure.ac.features | 1 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/Makefile.sources | 18 | ||||
-rw-r--r-- | src/Makefile.win32.features | 14 | ||||
-rw-r--r-- | src/cairo-base64-stream.c | 143 | ||||
-rw-r--r-- | src/cairo-base85-stream.c | 3 | ||||
-rw-r--r-- | src/cairo-output-stream-private.h | 4 | ||||
-rw-r--r-- | src/cairo-ps-surface.c | 4 | ||||
-rw-r--r-- | src/cairo-script-surface.c | 18 | ||||
-rw-r--r-- | src/cairo-xml-surface.c | 1153 | ||||
-rw-r--r-- | src/cairo-xml.h | 72 | ||||
-rw-r--r-- | src/cairo.h | 4 | ||||
-rw-r--r-- | util/Makefile.am | 11 | ||||
-rw-r--r-- | util/cairo-script/cairo-script-scanner.c | 113 | ||||
-rw-r--r-- | util/trace-to-xml.c | 77 | ||||
-rw-r--r-- | util/xml-to-trace.c | 263 |
19 files changed, 1902 insertions, 14 deletions
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features index e9c87ea4..ad4508ee 100644 --- a/boilerplate/Makefile.win32.features +++ b/boilerplate/Makefile.win32.features @@ -320,6 +320,16 @@ enabled_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers) enabled_cairo_boilerplate_private += $(cairo_boilerplate_tee_private) enabled_cairo_boilerplate_sources += $(cairo_boilerplate_tee_sources) +supported_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers) +all_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers) +all_cairo_boilerplate_private += $(cairo_boilerplate_xml_private) +all_cairo_boilerplate_sources += $(cairo_boilerplate_xml_sources) +ifeq ($(CAIRO_HAS_XML_SURFACE),1) +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers) +enabled_cairo_boilerplate_private += $(cairo_boilerplate_xml_private) +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xml_sources) +endif + supported_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers) all_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers) all_cairo_boilerplate_private += $(cairo_boilerplate_user_private) diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features index 8f0440f0..884e232e 100644 --- a/build/Makefile.win32.features +++ b/build/Makefile.win32.features @@ -28,3 +28,4 @@ CAIRO_HAS_PS_SURFACE=1 CAIRO_HAS_PDF_SURFACE=1 CAIRO_HAS_SVG_SURFACE=1 CAIRO_HAS_TEST_SURFACES=0 +CAIRO_HAS_XML_SURFACE=1 diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h index f647b166..04327900 100644 --- a/build/Makefile.win32.features-h +++ b/build/Makefile.win32.features-h @@ -92,5 +92,8 @@ endif @echo "#define CAIRO_HAS_IMAGE_SURFACE 1" >> src/cairo-features.h @echo "#define CAIRO_HAS_META_SURFACE 1" >> src/cairo-features.h @echo "#define CAIRO_HAS_TEE_SURFACE 1" >> src/cairo-features.h +ifeq ($(CAIRO_HAS_XML_SURFACE),1) + @echo "#define CAIRO_HAS_XML_SURFACE 1" >> src/cairo-features.h +endif @echo "#define CAIRO_HAS_USER_FONT 1" >> src/cairo-features.h @echo "#endif" >> src/cairo-features.h diff --git a/build/configure.ac.features b/build/configure.ac.features index 55f37862..99fe284d 100644 --- a/build/configure.ac.features +++ b/build/configure.ac.features @@ -359,6 +359,7 @@ AC_DEFUN([CAIRO_REPORT], echo " Image: yes (always builtin)" echo " Meta: yes (always builtin)" echo " Tee: yes (always builtin)" + echo " XML: $use_xml" echo " Xlib: $use_xlib" echo " Xlib Xrender: $use_xlib_xrender" echo " Qt: $use_qt" diff --git a/configure.ac b/configure.ac index ec712f7d..af63c297 100644 --- a/configure.ac +++ b/configure.ac @@ -571,6 +571,10 @@ dnl =========================================================================== CAIRO_ENABLE_SURFACE_BACKEND(meta, meta, always) CAIRO_ENABLE_SURFACE_BACKEND(tee, tee, always) +CAIRO_ENABLE_SURFACE_BACKEND(xml, xml, yes, [ + use_xml=$have_libz + xml_NONPKGCONFIG_LIBS=-lz +]) dnl =========================================================================== diff --git a/src/Makefile.sources b/src/Makefile.sources index 603e8878..58eac088 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -99,6 +99,7 @@ cairo_sources = \ cairo-arc.c \ cairo-array.c \ cairo-atomic.c \ + cairo-base64-stream.c \ cairo-base85-stream.c \ cairo-bentley-ottmann.c \ cairo-bentley-ottmann-rectangular.c \ @@ -190,9 +191,14 @@ cairo_ps_headers = cairo-ps.h cairo_ps_private = cairo-ps-surface-private.h cairo_ps_sources = cairo-ps-surface.c +cairo_deflate_stream_sources = cairo-deflate-stream.c + cairo_pdf_headers = cairo-pdf.h cairo_pdf_private = cairo-pdf-surface-private.h -cairo_pdf_sources = cairo-pdf-surface.c cairo-deflate-stream.c +cairo_pdf_sources = cairo-pdf-surface.c +if CAIRO_HAS_PDF_SURFACE +req_cairo_deflate_stream_sources = $(cairo_deflate_stream_sources) +endif cairo_svg_headers = cairo-svg.h cairo_svg_private = cairo-svg-surface-private.h @@ -294,5 +300,15 @@ cairo_gallium_sources = drm/cairo-drm-gallium-surface.c cairo_script_headers = cairo-script.h cairo_script_sources = cairo-script-surface.c +cairo_xml_headers = cairo-xml.h +cairo_xml_sources = cairo-xml-surface.c +if CAIRO_HAS_XML_SURFACE +req_cairo_deflate_stream_sources = $(cairo_deflate_stream_sources) +endif + cairo_vg_headers = cairo-vg.h cairo_vg_sources = cairo-vg-surface.c + +cairo_sources += \ + $(req_cairo_deflate_stream_sources) \ + $(NULL) diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features index 8b17d5c5..5d705bc6 100644 --- a/src/Makefile.win32.features +++ b/src/Makefile.win32.features @@ -430,6 +430,20 @@ enabled_cairo_headers += $(cairo_tee_headers) enabled_cairo_private += $(cairo_tee_private) enabled_cairo_sources += $(cairo_tee_sources) +supported_cairo_headers += $(cairo_xml_headers) +all_cairo_headers += $(cairo_xml_headers) +all_cairo_private += $(cairo_xml_private) +all_cairo_sources += $(cairo_xml_sources) +ifeq ($(CAIRO_HAS_XML_SURFACE),1) +enabled_cairo_headers += $(cairo_xml_headers) +enabled_cairo_private += $(cairo_xml_private) +enabled_cairo_sources += $(cairo_xml_sources) +endif +all_cairo_pkgconf += cairo-xml.pc +ifeq ($(CAIRO_HAS_XML_SURFACE),1) +enabled_cairo_pkgconf += cairo-xml.pc +endif + supported_cairo_headers += $(cairo_user_headers) all_cairo_headers += $(cairo_user_headers) all_cairo_private += $(cairo_user_private) diff --git a/src/cairo-base64-stream.c b/src/cairo-base64-stream.c new file mode 100644 index 00000000..2b211ff0 --- /dev/null +++ b/src/cairo-base64-stream.c @@ -0,0 +1,143 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005-2007 Emmanuel Pacaud <emmanuel.pacaud@free.fr> + * Copyright © 2009 Chris Wilson + * + * 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. + * + * Author(s): + * Kristian Høgsberg <krh@redhat.com> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" +#include "cairo-output-stream-private.h" + +typedef struct _cairo_base64_stream { + cairo_output_stream_t base; + cairo_output_stream_t *output; + unsigned int in_mem; + unsigned int trailing; + unsigned char src[3]; +} cairo_base64_stream_t; + +static char const base64_table[64] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static cairo_status_t +_cairo_base64_stream_write (cairo_output_stream_t *base, + const unsigned char *data, + unsigned int length) +{ + cairo_base64_stream_t * stream = (cairo_base64_stream_t *) base; + unsigned char *src = stream->src; + unsigned int i; + + if (stream->in_mem + length < 3) { + for (i = 0; i < length; i++) { + src[i + stream->in_mem] = *data++; + } + stream->in_mem += length; + return CAIRO_STATUS_SUCCESS; + } + + do { + unsigned char dst[4]; + + for (i = stream->in_mem; i < 3; i++) { + src[i] = *data++; + length--; + } + stream->in_mem = 0; + + dst[0] = base64_table[src[0] >> 2]; + dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4]; + dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6]; + dst[3] = base64_table[src[2] & 0xfc >> 2]; + /* Special case for the last missing bits */ + switch (stream->trailing) { + case 2: + dst[2] = '='; + case 1: + dst[3] = '='; + default: + break; + } + _cairo_output_stream_write (stream->output, dst, 4); + } while (length >= 3); + + for (i = 0; i < length; i++) { + src[i] = *data++; + } + stream->in_mem = length; + + return _cairo_output_stream_get_status (stream->output); +} + +static cairo_status_t +_cairo_base64_stream_close (cairo_output_stream_t *base) +{ + cairo_base64_stream_t *stream = (cairo_base64_stream_t *) base; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (stream->in_mem > 0) { + memset (stream->src + stream->in_mem, 0, 3 - stream->in_mem); + stream->trailing = 3 - stream->in_mem; + stream->in_mem = 3; + status = _cairo_base64_stream_write (base, NULL, 0); + } + + return status; +} + +cairo_output_stream_t * +_cairo_base64_stream_create (cairo_output_stream_t *output) +{ + cairo_base64_stream_t *stream; + + if (output->status) + return _cairo_output_stream_create_in_error (output->status); + + stream = malloc (sizeof (cairo_base64_stream_t)); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, + _cairo_base64_stream_write, + NULL, + _cairo_base64_stream_close); + + stream->output = output; + stream->in_mem = 0; + stream->trailing = 0; + + return &stream->base; +} diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c index 9d42ef48..791e8013 100644 --- a/src/cairo-base85-stream.c +++ b/src/cairo-base85-stream.c @@ -102,9 +102,6 @@ _cairo_base85_stream_close (cairo_output_stream_t *base) _cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1); } - /* Mark end of base85 data */ - _cairo_output_stream_printf (stream->output, "~>"); - return _cairo_output_stream_get_status (stream->output); } diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h index 2b3d584e..5243d218 100644 --- a/src/cairo-output-stream-private.h +++ b/src/cairo-output-stream-private.h @@ -184,6 +184,10 @@ _cairo_null_stream_create (void); cairo_private cairo_output_stream_t * _cairo_base85_stream_create (cairo_output_stream_t *output); +/* cairo-base64-stream.c */ +cairo_private cairo_output_stream_t * +_cairo_base64_stream_create (cairo_output_stream_t *output); + /* cairo-deflate-stream.c */ cairo_private cairo_output_stream_t * _cairo_deflate_stream_create (cairo_output_stream_t *output); diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index d4cfa9eb..da74eb32 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -1919,10 +1919,14 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface, _cairo_output_stream_write (base85_stream, data, length); status = _cairo_output_stream_destroy (base85_stream); + + /* Mark end of base85 data */ + _cairo_output_stream_printf (string_array_stream, "~>"); status2 = _cairo_output_stream_destroy (string_array_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; + return status; } diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index 423e41a4..4a89cf0a 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -1142,7 +1142,7 @@ _emit_png_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, " >> image "); + _cairo_output_stream_puts (surface->ctx->stream, "~> >> image "); return CAIRO_STATUS_SUCCESS; } @@ -1253,7 +1253,7 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; } - _cairo_output_stream_puts (surface->ctx->stream, " >> image "); + _cairo_output_stream_puts (surface->ctx->stream, "~> >> image "); cairo_surface_destroy (&clone->base); } @@ -1291,7 +1291,7 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, " set-mime-data\n"); + _cairo_output_stream_puts (surface->ctx->stream, "~> set-mime-data\n"); } cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2, @@ -1307,7 +1307,7 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, " set-mime-data\n"); + _cairo_output_stream_puts (surface->ctx->stream, "~> set-mime-data\n"); } _cairo_output_stream_puts (surface->ctx->stream, "pattern"); @@ -2499,7 +2499,7 @@ _emit_type42_font (cairo_script_surface_t *surface, font_private = scaled_font->surface_private; _cairo_output_stream_printf (surface->ctx->stream, - " >> font dup /f%lu exch def set-font-face", + "~> >> font dup /f%lu exch def set-font-face", font_private->id); return status; @@ -3003,7 +3003,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } _cairo_output_stream_printf (surface->ctx->stream, - " %f <~", glyphs[n].x - x); + "~> %f <~", glyphs[n].x - x); base85_stream = _cairo_base85_stream_create (surface->ctx->stream); } else { _cairo_output_stream_printf (surface->ctx->stream, @@ -3025,7 +3025,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } _cairo_output_stream_printf (surface->ctx->stream, - " %f %f <~", + "~> %f %f <~", ix, iy); base85_stream = _cairo_base85_stream_create (surface->ctx->stream); } else { @@ -3067,6 +3067,8 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, status2 = _cairo_output_stream_destroy (base85_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; + + _cairo_output_stream_printf (surface->ctx->stream, "~>"); } else { _cairo_output_stream_puts (surface->ctx->stream, " ]"); } @@ -3105,6 +3107,8 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, status = _cairo_output_stream_destroy (base85_stream); if (unlikely (status)) return status; + + _cairo_output_stream_puts (surface->ctx->stream, "~>"); } _cairo_output_stream_printf (surface->ctx->stream, diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c new file mode 100644 index 00000000..ec4d3fda --- /dev/null +++ b/src/cairo-xml-surface.c @@ -0,0 +1,1153 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * 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 Chris Wilson. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +/* This surface is intended to produce a verbose, hierarchical, DAG XML file + * representing a single surface. It is intended to be used by debuggers, + * such as cairo-sphinx, or by application test-suites that what a log of + * operations. + */ + +#include "cairoint.h" + +#include "cairo-xml.h" + +#include "cairo-clip-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-meta-surface-private.h" + +#define static cairo_warn static + +typedef struct _cairo_xml_surface cairo_xml_surface_t; + +struct _cairo_xml { + cairo_status_t status; + + int ref; + + cairo_output_stream_t *stream; + int indent; +}; + +struct _cairo_xml_surface { + cairo_surface_t base; + + cairo_xml_t *xml; + + double width, height; +}; + +slim_hidden_proto (cairo_xml_for_meta_surface); + +static const cairo_xml_t _nil_xml = { + CAIRO_STATUS_NO_MEMORY, + -1 +}; + +static const cairo_surface_backend_t _cairo_xml_surface_backend; + +static const char * +_direction_to_string (cairo_bool_t backward) +{ + static const char *names[] = { + "FORWARD", + "BACKWARD" + }; + assert (backward < ARRAY_LENGTH (names)); + return names[backward]; +} + +static const char * +_operator_to_string (cairo_operator_t op) +{ + static const char *names[] = { + "CLEAR", /* CAIRO_OPERATOR_CLEAR */ + + "SOURCE", /* CAIRO_OPERATOR_SOURCE */ + "OVER", /* CAIRO_OPERATOR_OVER */ + "IN", /* CAIRO_OPERATOR_IN */ + "OUT", /* CAIRO_OPERATOR_OUT */ + "ATOP", /* CAIRO_OPERATOR_ATOP */ + + "DEST", /* CAIRO_OPERATOR_DEST */ + "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */ + "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */ + "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */ + "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */ + + "XOR", /* CAIRO_OPERATOR_XOR */ + "ADD", /* CAIRO_OPERATOR_ADD */ + "SATURATE", /* CAIRO_OPERATOR_SATURATE */ + + "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */ + "SCREEN", /* CAIRO_OPERATOR_SCREEN */ + "OVERLAY", /* CAIRO_OPERATOR_OVERLAY */ + "DARKEN", /* CAIRO_OPERATOR_DARKEN */ + "LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */ + "DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */ + "BURN", /* CAIRO_OPERATOR_COLOR_BURN */ + "HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */ + "SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */ + "DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */ + "EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */ + "HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */ + "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */ + "HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */ + "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */ + }; + assert (op < ARRAY_LENGTH (names)); + return names[op]; +} + +static const char * +_extend_to_string (cairo_extend_t extend) +{ + static const char *names[] = { + "EXTEND_NONE", /* CAIRO_EXTEND_NONE */ + "EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */ + "EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */ + "EXTEND_PAD" /* CAIRO_EXTEND_PAD */ + }; + assert (extend < ARRAY_LENGTH (names)); + return names[extend]; +} + +static const char * +_filter_to_string (cairo_filter_t filter) +{ + static const char *names[] = { + "FILTER_FAST", /* CAIRO_FILTER_FAST */ + "FILTER_GOOD", /* CAIRO_FILTER_GOOD */ + "FILTER_BEST", /* CAIRO_FILTER_BEST */ + "FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */ + "FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */ + "FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */ + }; + assert (filter < ARRAY_LENGTH (names)); + return names[filter]; +} + +static const char * +_fill_rule_to_string (cairo_fill_rule_t rule) +{ + static const char *names[] = { + "WINDING", /* CAIRO_FILL_RULE_WINDING */ + "EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */ + }; + assert (rule < ARRAY_LENGTH (names)); + return names[rule]; +} + +static const char * +_antialias_to_string (cairo_antialias_t antialias) +{ + static const char *names[] = { + "ANTIALIAS_DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */ + "ANTIALIAS_NONE", /* CAIRO_ANTIALIAS_NONE */ + "ANTIALIAS_GRAY", /* CAIRO_ANTIALIAS_GRAY */ + "ANTIALIAS_SUBPIXEL" /* CAIRO_ANTIALIAS_SUBPIXEL */ + }; + assert (antialias < ARRAY_LENGTH (names)); + return names[antialias]; +} + +static const char * +_line_cap_to_string (cairo_line_cap_t line_cap) +{ + static const char *names[] = { + "LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */ + "LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */ + "LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */ + }; + assert (line_cap < ARRAY_LENGTH (names)); + return names[line_cap]; +} + +static const char * +_line_join_to_string (cairo_line_join_t line_join) +{ + static const char *names[] = { + "LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */ + "LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */ + "LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */ + }; + assert (line_join < ARRAY_LENGTH (names)); + return names[line_join]; +} + +static const char * +_content_to_string (cairo_content_t content) +{ + switch (content) { + case CAIRO_CONTENT_ALPHA: return "ALPHA"; + case CAIRO_CONTENT_COLOR: return "COLOR"; + default: + case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA"; + } +} + +static const char * +_format_to_string (cairo_format_t format) +{ + static const char *names[] = { + "ARGB32", /* CAIRO_FORMAT_ARGB32 */ + "RGB24", /* CAIRO_FORMAT_RGB24 */ + "A8", /* CAIRO_FORMAT_A8 */ + "A1" /* CAIRO_FORMAT_A1 */ + }; + assert (format < ARRAY_LENGTH (names)); + return names[format]; +} + +static cairo_xml_t * +_cairo_xml_create_internal (cairo_output_stream_t *stream) +{ + cairo_xml_t *xml; + + xml = malloc (sizeof (cairo_xml_t)); + if (unlikely (xml == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_xml_t *) &_nil_xml; + } + + memset (xml, 0, sizeof (cairo_xml_t)); + xml->status = CAIRO_STATUS_SUCCESS; + xml->ref = 1; + xml->indent = 0; + + xml->stream = stream; + + return xml; +} + +static void +_cairo_xml_indent (cairo_xml_t *xml, int indent) +{ + xml->indent += indent; + assert (xml->indent >= 0); +} + +static void CAIRO_PRINTF_FORMAT (2, 3) +_cairo_xml_printf (cairo_xml_t *xml, const char *fmt, ...) +{ + va_list ap; + char indent[80]; + int len; + + len = MIN (xml->indent, sizeof (indent)); + memset (indent, ' ', len); + _cairo_output_stream_write (xml->stream, indent, len); + + va_start (ap, fmt); + _cairo_output_stream_vprintf (xml->stream, fmt, ap); + va_end (ap); + + _cairo_output_stream_write (xml->stream, "\n", 1); +} + +static void CAIRO_PRINTF_FORMAT (2, 3) +_cairo_xml_printf_start (cairo_xml_t *xml, const char *fmt, ...) +{ + char indent[80]; + int len; + + len = MIN (xml->indent, sizeof (indent)); + memset (indent, ' ', len); + _cairo_output_stream_write (xml->stream, indent, len); + + if (fmt != NULL) { + va_list ap; + + va_start (ap, fmt); + _cairo_output_stream_vprintf (xml->stream, fmt, ap); + va_end (ap); + } +} + +static void CAIRO_PRINTF_FORMAT (2, 3) +_cairo_xml_printf_continue (cairo_xml_t *xml, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + _cairo_output_stream_vprintf (xml->stream, fmt, ap); + va_end (ap); +} + +static void CAIRO_PRINTF_FORMAT (2, 3) +_cairo_xml_printf_end (cairo_xml_t *xml, const char *fmt, ...) +{ + if (fmt != NULL) { + va_list ap; + + va_start (ap, fmt); + _cairo_output_stream_vprintf (xml->stream, fmt, ap); + va_end (ap); + } + + _cairo_output_stream_write (xml->stream, "\n", 1); +} + +static cairo_status_t +_cairo_xml_destroy_internal (cairo_xml_t *xml) +{ + cairo_status_t status; + + assert (xml->ref > 0); + if (--xml->ref) + return _cairo_output_stream_flush (xml->stream); + + status = _cairo_output_stream_destroy (xml->stream); + + free (xml); + + return status; +} + +static cairo_surface_t * +_cairo_xml_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_rectangle_t extents; + + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + + return cairo_meta_surface_create (content, &extents); +} + +static cairo_status_t +_cairo_xml_surface_finish (void *abstract_surface) +{ + cairo_xml_surface_t *surface = abstract_surface; + + return _cairo_xml_destroy_internal (surface->xml); +} + +static cairo_bool_t +_cairo_xml_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_xml_surface_t *surface = abstract_surface; + + if (surface->width < 0 || surface->height < 0) + return FALSE; + + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = surface->width; + rectangle->height = surface->height; + + return TRUE; +} + +static cairo_status_t +_cairo_xml_move_to (void *closure, + const cairo_point_t *p1) +{ + _cairo_xml_printf_continue (closure, " %f %f m", + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_line_to (void *closure, + const cairo_point_t *p1) +{ + _cairo_xml_printf_continue (closure, " %f %f l", + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_curve_to (void *closure, + const cairo_point_t *p1, + const cairo_point_t *p2, + const cairo_point_t *p3) +{ + _cairo_xml_printf_continue (closure, " %f %f %f %f %f %f c", + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y), + _cairo_fixed_to_double (p2->x), + _cairo_fixed_to_double (p2->y), + _cairo_fixed_to_double (p3->x), + _cairo_fixed_to_double (p3->y)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_close_path (void *closure) +{ + _cairo_xml_printf_continue (closure, " h"); + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_xml_emit_path (cairo_xml_t *xml, + cairo_path_fixed_t *path) +{ + cairo_status_t status; + + _cairo_xml_printf_start (xml, "<path>"); + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_xml_move_to, + _cairo_xml_line_to, + _cairo_xml_curve_to, + _cairo_xml_close_path, + xml); + assert (status == CAIRO_STATUS_SUCCESS); + _cairo_xml_printf_start (xml, "</path>"); +} + +static void +_cairo_xml_emit_string (cairo_xml_t *xml, + const char *node, + const char *data) +{ + _cairo_xml_printf (xml, "<%s>%s</%s>", node, data, node); +} + +static void +_cairo_xml_emit_double (cairo_xml_t *xml, + const char *node, + double data) +{ + _cairo_xml_printf (xml, "<%s>%f</%s>", node, data, node); +} + +static cairo_status_t +_cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface, + cairo_clip_path_t *clip_path) +{ + cairo_box_t box; + cairo_status_t status; + + if (clip_path->prev != NULL) { + status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev); + if (unlikely (status)) + return status; + } + + + /* skip the trivial clip covering the surface extents */ + if (surface->width >= 0 && surface->height >= 0 && + _cairo_path_fixed_is_box (&clip_path->path, &box)) + { + if (box.p1.x <= 0 && box.p1.y <= 0 && + box.p2.x - box.p1.x >= _cairo_fixed_from_double (surface->width) && + box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height)) + { + return CAIRO_STATUS_SUCCESS; + } + } + + _cairo_xml_printf_start (surface->xml, "<clip>"); + _cairo_xml_indent (surface->xml, 2); + + _cairo_xml_emit_path (surface->xml, &clip_path->path); + _cairo_xml_emit_double (surface->xml, "tolerance", clip_path->tolerance); + _cairo_xml_emit_string (surface->xml, "antialias", + _antialias_to_string (clip_path->antialias)); + _cairo_xml_emit_string (surface->xml, "fill-rule", + _fill_rule_to_string (clip_path->fill_rule)); + + _cairo_xml_indent (surface->xml, -2); + _cairo_xml_printf_end (surface->xml, "</clip>"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_surface_emit_clip (cairo_xml_surface_t *surface, + cairo_clip_t *clip) +{ + if (clip == NULL) + return CAIRO_STATUS_SUCCESS; + + return _cairo_xml_surface_emit_clip_path (surface, clip->path); +} + +static cairo_status_t +_cairo_xml_emit_solid (cairo_xml_t *xml, + const cairo_solid_pattern_t *solid) +{ + _cairo_xml_printf (xml, "<solid>%f %f %f %f</solid>", + solid->color.red, + solid->color.green, + solid->color.blue, + solid->color.alpha); + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_xml_emit_matrix (cairo_xml_t *xml, + const cairo_matrix_t *matrix) +{ + if (! _cairo_matrix_is_identity (matrix)) { + _cairo_xml_printf (xml, "<matrix>%f %f %f %f %f %f</matrix>", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + } +} + +static void +_cairo_xml_emit_gradient (cairo_xml_t *xml, + const cairo_gradient_pattern_t *gradient) +{ + int i; + + for (i = 0; i < gradient->n_stops; i++) { + _cairo_xml_printf (xml, + "<color-stop>%f %f %f %f %f</color-stop>", + gradient->stops[i].offset, + gradient->stops[i].color.red, + gradient->stops[i].color.green, + gradient->stops[i].color.blue, + gradient->stops[i].color.alpha); + } +} + +static cairo_status_t +_cairo_xml_emit_linear (cairo_xml_t *xml, + const cairo_linear_pattern_t *linear) +{ + _cairo_xml_printf (xml, + "<linear x1='%f' y1='%f' x2='%f' y2='%f'>", + _cairo_fixed_to_double (linear->p1.x), + _cairo_fixed_to_double (linear->p1.y), + _cairo_fixed_to_double (linear->p2.x), + _cairo_fixed_to_double (linear->p2.y)); + _cairo_xml_indent (xml, 2); + _cairo_xml_emit_gradient (xml, &linear->base); + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</linear>"); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_emit_radial (cairo_xml_t *xml, + const cairo_radial_pattern_t *radial) +{ + _cairo_xml_printf (xml, + "<radial x1='%f' y1='%f' r1='%f' x2='%f' y2='%f' r2='%f'>", + _cairo_fixed_to_double (radial->c1.x), + _cairo_fixed_to_double (radial->c1.y), + _cairo_fixed_to_double (radial->r1), + _cairo_fixed_to_double (radial->c2.x), + _cairo_fixed_to_double (radial->c2.y), + _cairo_fixed_to_double (radial->r2)); + _cairo_xml_indent (xml, 2); + _cairo_xml_emit_gradient (xml, &radial->base); + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</radial>"); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_write_func (void *closure, const unsigned char *data, unsigned len) +{ + _cairo_output_stream_write (closure, data, len); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_emit_image (cairo_xml_t *xml, + cairo_image_surface_t *image) +{ + cairo_output_stream_t *stream; + cairo_status_t status; + + _cairo_xml_printf_start (xml, + "<image width='%d' height='%d' format='%s'>", + image->width, image->height, + _format_to_string (image->format)); + + stream = _cairo_base64_stream_create (xml->stream); + status = cairo_surface_write_to_png_stream (&image->base, + _write_func, stream); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_output_stream_destroy (stream); + if (unlikely (status)) + return status; + + _cairo_xml_printf_end (xml, "</image>"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_emit_surface (cairo_xml_t *xml, + const cairo_surface_pattern_t *pattern) +{ + cairo_surface_t *source = pattern->surface; + cairo_status_t status; + + if (_cairo_surface_is_meta (source)) { + status = cairo_xml_for_meta_surface (xml, source); + } else { + cairo_image_surface_t *image; + void *image_extra; + + status = _cairo_surface_acquire_source_image (source, + &image, &image_extra); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_image (xml, image); + + _cairo_surface_release_source_image (source, image, image_extra); + } + + return status; +} + +static cairo_status_t +_cairo_xml_emit_pattern (cairo_xml_t *xml, + const char *source_or_mask, + const cairo_pattern_t *pattern) +{ + cairo_status_t status; + + _cairo_xml_printf (xml, "<%s-pattern>", source_or_mask); + _cairo_xml_indent (xml, 2); + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + status = _cairo_xml_emit_solid (xml, (cairo_solid_pattern_t *) pattern); + break; + case CAIRO_PATTERN_TYPE_LINEAR: + status = _cairo_xml_emit_linear (xml, (cairo_linear_pattern_t *) pattern); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + status = _cairo_xml_emit_radial (xml, (cairo_radial_pattern_t *) pattern); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + status = _cairo_xml_emit_surface (xml, (cairo_surface_pattern_t *) pattern); + break; + default: + ASSERT_NOT_REACHED; + status = CAIRO_INT_STATUS_UNSUPPORTED; + break; + } + + if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) { + _cairo_xml_emit_matrix (xml, &pattern->matrix); + _cairo_xml_printf (xml, + "<extend>%s</extend>", + _extend_to_string (pattern->extend)); + _cairo_xml_printf (xml, + "<filter>%s</filter>", + _filter_to_string (pattern->filter)); + } + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</%s-pattern>", source_or_mask); + + return status; +} + +static cairo_int_status_t +_cairo_xml_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_xml_surface_t *surface = abstract_surface; + cairo_xml_t *xml = surface->xml; + cairo_status_t status; + + _cairo_xml_printf (xml, "<paint>"); + _cairo_xml_indent (xml, 2); + + _cairo_xml_emit_string (xml, "operator", _operator_to_string (op)); + + status = _cairo_xml_surface_emit_clip (surface, clip); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_pattern (xml, "source", source); + if (unlikely (status)) + return status; + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</paint>"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xml_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_xml_surface_t *surface = abstract_surface; + cairo_xml_t *xml = surface->xml; + cairo_status_t status; + + _cairo_xml_printf (xml, "<mask>"); + _cairo_xml_indent (xml, 2); + + _cairo_xml_emit_string (xml, "operator", _operator_to_string (op)); + + status = _cairo_xml_surface_emit_clip (surface, clip); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_pattern (xml, "source", source); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_pattern (xml, "mask", mask); + if (unlikely (status)) + return status; + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</mask>"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xml_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_xml_surface_t *surface = abstract_surface; + cairo_xml_t *xml = surface->xml; + cairo_status_t status; + + _cairo_xml_printf (xml, "<stroke>"); + _cairo_xml_indent (xml, 2); + + _cairo_xml_emit_string (xml, "operator", _operator_to_string (op)); + _cairo_xml_emit_double (xml, "line-width", style->line_width); + _cairo_xml_emit_double (xml, "miter-limit", style->miter_limit); + _cairo_xml_emit_string (xml, "line-cap", _line_cap_to_string (style->line_cap)); + _cairo_xml_emit_string (xml, "line-join", _line_join_to_string (style->line_join)); + + status = _cairo_xml_surface_emit_clip (surface, clip); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_pattern (xml, "source", source); + if (unlikely (status)) + return status; + + if (style->num_dashes) { + int i; + + _cairo_xml_printf_start (xml, "<dash offset='%f'>", + style->dash_offset); + for (i = 0; i < style->num_dashes; i++) + _cairo_xml_printf_continue (xml, "%f ", style->dash[i]); + + _cairo_xml_printf_end (xml, "</dash>"); + } + + _cairo_xml_emit_path (surface->xml, path); + _cairo_xml_emit_double (xml, "tolerance", tolerance); + _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias)); + + _cairo_xml_emit_matrix (xml, ctm); + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</stroke>"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xml_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_xml_surface_t *surface = abstract_surface; + cairo_xml_t *xml = surface->xml; + cairo_status_t status; + + _cairo_xml_printf (xml, "<fill>"); + _cairo_xml_indent (xml, 2); + + _cairo_xml_emit_string (xml, "operator", _operator_to_string (op)); + + status = _cairo_xml_surface_emit_clip (surface, clip); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_pattern (xml, "source", source); + if (unlikely (status)) + return status; + + _cairo_xml_emit_path (surface->xml, path); + _cairo_xml_emit_double (xml, "tolerance", tolerance); + _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias)); + _cairo_xml_emit_string (xml, "fill-rule", _fill_rule_to_string (fill_rule)); + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</fill>"); + + return CAIRO_STATUS_SUCCESS; +} + +#if CAIRO_HAS_FT_FONT +#include "cairo-ft-private.h" +static cairo_status_t +_cairo_xml_emit_type42_font (cairo_xml_t *xml, + cairo_scaled_font_t *scaled_font) +{ + const cairo_scaled_font_backend_t *backend; + cairo_output_stream_t *base64_stream; + cairo_output_stream_t *zlib_stream; + cairo_status_t status, status2; + unsigned long size; + uint32_t len; + uint8_t *buf; + + backend = scaled_font->backend; + if (backend->load_truetype_table == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = 0; + status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size); + if (unlikely (status)) + return status; + + buf = malloc (size); + if (unlikely (buf == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL); + if (unlikely (status)) { + free (buf); + return status; + } + + _cairo_xml_printf_start (xml, "<font type='42' flags='%d' index='0'>", + _cairo_ft_scaled_font_get_load_flags (scaled_font)); + + + base64_stream = _cairo_base64_stream_create (xml->stream); + len = size; + _cairo_output_stream_write (base64_stream, &len, sizeof (len)); + + zlib_stream = _cairo_deflate_stream_create (base64_stream); + + _cairo_output_stream_write (zlib_stream, buf, size); + free (buf); + + status2 = _cairo_output_stream_destroy (zlib_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + status2 = _cairo_output_stream_destroy (base64_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + _cairo_xml_printf_end (xml, "</font>"); + + return status; +} +#else +static cairo_status_t +_cairo_xml_emit_type42_font (cairo_xml_t *xml, + cairo_scaled_font_t *scaled_font) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} +#endif + +static cairo_status_t +_cairo_xml_emit_type3_font (cairo_xml_t *xml, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs) +{ + _cairo_xml_printf_start (xml, "<font type='3'>"); + _cairo_xml_printf_end (xml, "</font>"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xml_emit_scaled_font (cairo_xml_t *xml, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_status_t status; + + _cairo_xml_printf (xml, "<scaled-font>"); + _cairo_xml_indent (xml, 2); + + status = _cairo_xml_emit_type42_font (xml, scaled_font); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _cairo_xml_emit_type3_font (xml, scaled_font, + glyphs, num_glyphs); + } + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "<scaled-font>"); + + return status; +} + +static cairo_int_status_t +_cairo_xml_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *remaining_glyphs) +{ + cairo_xml_surface_t *surface = abstract_surface; + cairo_xml_t *xml = surface->xml; + cairo_status_t status; + int i; + + _cairo_xml_printf (xml, "<glyphs>"); + _cairo_xml_indent (xml, 2); + + _cairo_xml_emit_string (xml, "operator", _operator_to_string (op)); + + status = _cairo_xml_surface_emit_clip (surface, clip); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_pattern (xml, "source", source); + if (unlikely (status)) + return status; + + status = _cairo_xml_emit_scaled_font (xml, scaled_font, glyphs, num_glyphs); + if (unlikely (status)) + return status; + + for (i = 0; i < num_glyphs; i++) { + _cairo_xml_printf (xml, "<glyph index='%lu'>%f %f</glyph>", + glyphs[i].index, + glyphs[i].x, + glyphs[i].y); + } + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</glyphs>"); + + *remaining_glyphs = 0; + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t +_cairo_xml_surface_backend = { + CAIRO_SURFACE_TYPE_XML, + _cairo_xml_surface_create_similar, + _cairo_xml_surface_finish, + NULL, NULL, /* source image */ + NULL, NULL, /* dst image */ + NULL, /* clone_similar */ + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ + NULL, NULL, /* copy/show page */ + _cairo_xml_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* font fini */ + NULL, /* scaled_glyph_fini */ + + /* The 5 high level operations */ + _cairo_xml_surface_paint, + _cairo_xml_surface_mask, + _cairo_xml_surface_stroke, + _cairo_xml_surface_fill, + _cairo_xml_surface_glyphs, + + NULL, /* snapshot */ + + NULL, /* is_similar */ + NULL, /* fill_stroke */ + NULL, /* create_solid_pattern_surface */ + NULL, /* can_repaint_solid_pattern_surface */ + + /* The alternate high-level text operation */ + NULL, NULL, /* has, show_text_glyphs */ +}; + +static cairo_surface_t * +_cairo_xml_surface_create_internal (cairo_xml_t *xml, + cairo_content_t content, + double width, + double height) +{ + cairo_xml_surface_t *surface; + + if (unlikely (xml == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); + + surface = malloc (sizeof (cairo_xml_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_xml_surface_backend, + content); + + surface->xml = xml; + xml->ref++; + + surface->width = width; + surface->height = height; + + return &surface->base; +} + +cairo_xml_t * +cairo_xml_create (const char *filename) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create_for_filename (filename); + if (_cairo_output_stream_get_status (stream)) + return (cairo_xml_t *) &_nil_xml; + + return _cairo_xml_create_internal (stream); +} + +cairo_xml_t * +cairo_xml_create_for_stream (cairo_write_func_t write_func, + void *closure) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write_func, NULL, closure); + if (_cairo_output_stream_get_status (stream)) + return (cairo_xml_t *) &_nil_xml; + + return _cairo_xml_create_internal (stream); +} + +cairo_surface_t * +cairo_xml_surface_create (cairo_xml_t *xml, + cairo_content_t content, + double width, double height) +{ + return _cairo_xml_surface_create_internal (xml, content, width, height); +} + +cairo_status_t +cairo_xml_for_meta_surface (cairo_xml_t *xml, + cairo_surface_t *meta) +{ + cairo_box_t bbox; + cairo_rectangle_int_t extents; + cairo_surface_t *surface; + cairo_status_t status; + + if (unlikely (xml->status)) + return xml->status; + + if (unlikely (meta->status)) + return meta->status; + + if (unlikely (! _cairo_surface_is_meta (meta))) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + status = _cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta, + &bbox, NULL); + if (unlikely (status)) + return status; + + _cairo_box_round_to_rectangle (&bbox, &extents); + surface = _cairo_xml_surface_create_internal (xml, + meta->content, + extents.width, + extents.height); + if (unlikely (surface->status)) + return surface->status; + + _cairo_xml_printf (xml, + "<surface content='%s' width='%d' height='%d'>", + _content_to_string (meta->content), + extents.width, extents.height); + _cairo_xml_indent (xml, 2); + + cairo_surface_set_device_offset (surface, -extents.x, -extents.y); + status = cairo_meta_surface_replay (meta, surface); + cairo_surface_destroy (surface); + + _cairo_xml_indent (xml, -2); + _cairo_xml_printf (xml, "</surface>"); + + return status; +} +slim_hidden_def (cairo_xml_for_meta_surface); + +void +cairo_xml_destroy (cairo_xml_t *xml) +{ + cairo_status_t status_ignored; + + if (xml == NULL || xml->ref < 0) + return; + + status_ignored = _cairo_xml_destroy_internal (xml); +} diff --git a/src/cairo-xml.h b/src/cairo-xml.h new file mode 100644 index 00000000..9bd17351 --- /dev/null +++ b/src/cairo-xml.h @@ -0,0 +1,72 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * 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 Chris Wilson + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#ifndef CAIRO_XML_H +#define CAIRO_XML_H + +#include "cairo.h" + +#if CAIRO_HAS_XML_SURFACE + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_xml cairo_xml_t; + +cairo_public cairo_xml_t * +cairo_xml_create (const char *filename); + +cairo_public cairo_xml_t * +cairo_xml_create_for_stream (cairo_write_func_t write_func, + void *closure); + +cairo_public void +cairo_xml_destroy (cairo_xml_t *context); + +cairo_public cairo_surface_t * +cairo_xml_surface_create (cairo_xml_t *xml, + cairo_content_t content, + double width, double height); + +cairo_public cairo_status_t +cairo_xml_for_meta_surface (cairo_xml_t *context, + cairo_surface_t *meta); + +CAIRO_END_DECLS + +#else /*CAIRO_HAS_XML_SURFACE*/ +# error Cairo was not compiled with support for the XML backend +#endif /*CAIRO_HAS_XML_SURFACE*/ + +#endif /*CAIRO_XML_H*/ diff --git a/src/cairo.h b/src/cairo.h index 55c0fdd9..17d91dcf 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1949,6 +1949,7 @@ cairo_surface_status (cairo_surface_t *surface); * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10 * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10 * @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10 + * @CAIRO_SURFACE_TYPE_XML: The surface is of type XML (for debugging), since 1.10 * * #cairo_surface_type_t is used to describe the type of a given * surface. The surface types are also known as "backends" or "surface @@ -1994,7 +1995,8 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_VG, CAIRO_SURFACE_TYPE_GL, CAIRO_SURFACE_TYPE_DRM, - CAIRO_SURFACE_TYPE_TEE + CAIRO_SURFACE_TYPE_TEE, + CAIRO_SURFACE_TYPE_XML } cairo_surface_type_t; cairo_public cairo_surface_type_t diff --git a/util/Makefile.am b/util/Makefile.am index a7ce7b35..5c110ab2 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -15,9 +15,16 @@ SUBDIRS += cairo-sphinx endif endif -AM_CPPFLAGS = -I$(top_srcdir)/src +AM_CPPFLAGS = -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/util/cairo-script \ + $(CAIRO_CFLAGS) -EXTRA_PROGRAMS += show-traps show-edges show-events +EXTRA_PROGRAMS += show-traps show-edges show-events trace-to-xml xml-to-trace + +trace_to_xml_LDADD = cairo-script/libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) + +xml_to_trace_LDADD = -lexpat show_traps_SOURCES = show-traps.c show_traps_CFLAGS = $(gtk_CFLAGS) diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c index 3f96a30c..99606a93 100644 --- a/util/cairo-script/cairo-script-scanner.c +++ b/util/cairo-script/cairo-script-scanner.c @@ -667,6 +667,92 @@ base85_end (csi_t *ctx, csi_scanner_t *scan, cairo_bool_t deflate) longjmp (scan->jmpbuf, status); } +static void +base64_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + int val; + + /* Convert Base64 character to its 6 bit nibble */ + val = scan->accumulator; + if (c =='/') { + val = (val << 6) | 63; + } else if (c =='+') { + val = (val << 6) | 62; + } else if (c >='A' && c <='Z') { + val = (val << 6) | (c -'A'); + } else if (c >='a' && c <='z') { + val = (val << 6) | (c -'a' + 26); + } else if (c >='0' && c <='9') { + val = (val << 6) | (c -'0' + 52); + } + + buffer_check (ctx, scan, 1); + switch (scan->accumulator_count++) { + case 0: + break; + + case 1: + buffer_add (&scan->buffer, (val >> 4) & 0xFF); + val &= 0xF; + break; + + case 2: + buffer_add (&scan->buffer, (val >> 2) & 0xFF); + val &= 0x3; + break; + + case 3: + buffer_add (&scan->buffer, (val >> 0) & 0xFF); + scan->accumulator_count = 0; + val = 0; + break; + } + + if (c == '=') { + scan->accumulator_count = 0; + scan->accumulator = 0; + } else { + scan->accumulator = val; + } +} + +static void +base64_end (csi_t *ctx, csi_scanner_t *scan) +{ + csi_object_t obj; + cairo_status_t status; + + switch (scan->accumulator_count) { + case 0: + break; + case 2: + base64_add (ctx, scan, (scan->accumulator << 2) & 0x3f); + base64_add (ctx, scan, '='); + break; + case 1: + base64_add (ctx, scan, (scan->accumulator << 4) & 0x3f); + base64_add (ctx, scan, '='); + base64_add (ctx, scan, '='); + break; + } + + status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (status)) + longjmp (scan->jmpbuf, status); + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + status = scan_push (ctx, &obj); + if (_csi_unlikely (status)) + longjmp (scan->jmpbuf, status); +} + static inline void scan_read (csi_scanner_t *scan, csi_file_t *src, void *ptr, int len) { @@ -782,6 +868,8 @@ scan_none: deflate = 1; case '~': goto scan_base85; + case '{': + goto scan_base64; default: csi_file_putc (src, next); goto scan_hex; @@ -1204,6 +1292,31 @@ scan_base85: } } longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + +scan_base64: + buffer_reset (&scan->buffer); + scan->accumulator = 0; + scan->accumulator_count = 0; + while ((c = csi_file_getc (src)) != EOF) { + switch (c) { + case '}': + next = csi_file_getc (src); + switch (next) { + case EOF: + return; + + case '>': + base64_end (ctx, scan); + goto scan_none; + } + longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + + default: + base64_add (ctx, scan, c); + break; + } + } + longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT)); } static csi_status_t diff --git a/util/trace-to-xml.c b/util/trace-to-xml.c new file mode 100644 index 00000000..763a5656 --- /dev/null +++ b/util/trace-to-xml.c @@ -0,0 +1,77 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <cairo-xml.h> +#include <cairo-script-interpreter.h> + +#include <stdio.h> +#include <string.h> + +static cairo_surface_t * +_surface_create (void *_closure, + cairo_content_t content, + double width, double height) +{ + cairo_surface_t **closure = _closure; + cairo_surface_t *surface; + cairo_rectangle_t extents; + + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + surface = cairo_meta_surface_create (content, &extents); + if (*closure == NULL) + *closure = cairo_surface_reference (surface); + + return surface; +} + +static cairo_status_t +stdio_write (void *closure, const unsigned char *data, unsigned len) +{ + if (fwrite (data, len, 1, closure) == 1) + return CAIRO_STATUS_SUCCESS; + else + return CAIRO_STATUS_WRITE_ERROR; +} + +int +main (int argc, char **argv) +{ + cairo_surface_t *surface = NULL; + const cairo_script_interpreter_hooks_t hooks = { + .closure = &surface, + .surface_create = _surface_create, + }; + cairo_script_interpreter_t *csi; + FILE *in = stdin, *out = stdout; + + if (argc >= 2 && strcmp (argv[1], "-")) + in = fopen (argv[1], "r"); + if (argc >= 3 && strcmp (argv[2], "-")) + out = fopen (argv[2], "w"); + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + cairo_script_interpreter_feed_stream (csi, in); + cairo_script_interpreter_finish (csi); + cairo_script_interpreter_destroy (csi); + + if (surface != NULL) { + cairo_xml_t *xml; + + xml = cairo_xml_create_for_stream (stdio_write, out); + cairo_xml_for_meta_surface (xml, surface); + cairo_xml_destroy (xml); + + cairo_surface_destroy (surface); + } + + if (in != stdin) + fclose (in); + if (out != stdout) + fclose (out); + + return 0; +} diff --git a/util/xml-to-trace.c b/util/xml-to-trace.c new file mode 100644 index 00000000..13b7e570 --- /dev/null +++ b/util/xml-to-trace.c @@ -0,0 +1,263 @@ +#include <stdio.h> +#include <string.h> +#include <expat.h> +#include <assert.h> + +struct trace { + FILE *stream; + char tail_buf[80]; + const char *tail; + int surface_depth; +}; + +static void +start_element (void *closure, + const char *element, + const char **attr) +{ + struct trace *trace = closure; + + if (strcmp (element, "surface") == 0) { + const char *content = "COLOR_ALPHA"; + const char *width = NULL; + const char *height = NULL; + + while (*attr) { + if (strcmp (*attr, "content") == 0) { + content = *++attr; + } else if (strcmp (*attr, "width") == 0) { + width = *++attr; + } else if (strcmp (*attr, "height") == 0) { + height = *++attr; + } else { + fprintf (stderr, "unknown surface attribute '%s'\n", *attr); + attr++; + } + attr++; + } + + fprintf (trace->stream, "<< /content //%s", content); + if (width != NULL && height != NULL) { + fprintf (trace->stream, + " /width %s /height %s", + width, height); + } + if (trace->surface_depth++ == 0) + fprintf (trace->stream, " >> surface context\n"); + else + fprintf (trace->stream, " >> surface dup context\n"); + } else if (strcmp (element, "image") == 0) { + const char *format = "ARGB24"; + const char *width = NULL; + const char *height = NULL; + + while (*attr) { + if (strcmp (*attr, "format") == 0) { + format = *++attr; + } else if (strcmp (*attr, "width") == 0) { + width = *++attr; + } else if (strcmp (*attr, "height") == 0) { + height = *++attr; + } else { + fprintf (stderr, "unknown image attribute '%s'\n", *attr); + attr++; + } + attr++; + } + + fprintf (trace->stream, + "<< /format //%s /width %s /height %s /mime-type (image/png) /source <{", + format, width, height); + assert (trace->tail == NULL); + trace->tail = "}> >> image pattern\n"; + } else if (strcmp (element, "solid") == 0) { + trace->tail = " rgba\n"; + } else if (strcmp (element, "linear") == 0) { + const char *x1 = NULL; + const char *x2 = NULL; + const char *y1 = NULL; + const char *y2 = NULL; + + while (*attr) { + if (strcmp (*attr, "x1") == 0) { + x1 = *++attr; + } else if (strcmp (*attr, "x2") == 0) { + x2 = *++attr; + } else if (strcmp (*attr, "y1") == 0) { + y1 = *++attr; + } else if (strcmp (*attr, "y2") == 0) { + y2 = *++attr; + } else { + fprintf (stderr, "unknown linear attribute '%s'\n", *attr); + attr++; + } + attr++; + } + + fprintf (trace->stream, "%s %s %s %s linear\n", x1, y1, x2, y2); + } else if (strcmp (element, "radial") == 0) { + const char *x1 = NULL; + const char *y1 = NULL; + const char *r1 = NULL; + const char *y2 = NULL; + const char *x2 = NULL; + const char *r2 = NULL; + + while (*attr) { + if (strcmp (*attr, "x1") == 0) { + x1 = *++attr; + } else if (strcmp (*attr, "y1") == 0) { + y1 = *++attr; + } else if (strcmp (*attr, "r1") == 0) { + r1 = *++attr; + } else if (strcmp (*attr, "x2") == 0) { + x2 = *++attr; + } else if (strcmp (*attr, "y2") == 0) { + y2 = *++attr; + } else if (strcmp (*attr, "r2") == 0) { + r2 = *++attr; + } else { + fprintf (stderr, "unknown radial attribute '%s'\n", *attr); + attr++; + } + attr++; + } + + fprintf (trace->stream, + "%s %s %s %s %s %s radial\n", + x1, y1, r1, x2, y2, r2); + } else if (strcmp (element, "matrix") == 0) { + fprintf (trace->stream, "[ "); + trace->tail = " ] set-matrix\n"; + } else if (strcmp (element, "extend") == 0) { + trace->tail = " set-extend\n"; + } else if (strcmp (element, "filter") == 0) { + trace->tail = " set-filter\n"; + } else if (strcmp (element, "operator") == 0) { + trace->tail = " set-operator\n"; + } else if (strcmp (element, "tolerance") == 0) { + trace->tail = " set-tolerance\n"; + } else if (strcmp (element, "fill-rule") == 0) { + trace->tail = " set-fill-rule\n"; + } else if (strcmp (element, "line-cap") == 0) { + trace->tail = " set-line-cap\n"; + } else if (strcmp (element, "line-join") == 0) { + trace->tail = " set-line-join\n"; + } else if (strcmp (element, "line-width") == 0) { + trace->tail = " set-line-width\n"; + } else if (strcmp (element, "miter-limit") == 0) { + trace->tail = " set-miter-limit\n"; + } else if (strcmp (element, "antialias") == 0) { + trace->tail = " set-antialias\n"; + } else if (strcmp (element, "color-stop") == 0) { + trace->tail = " add-color-stop\n"; + } else if (strcmp (element, "path") == 0) { + /* need to reset the matrix to identity before the path */ + fprintf (trace->stream, "identity set-matrix "); + trace->tail = "\n"; + } else if (strcmp (element, "dash") == 0) { + const char *offset = "0"; + + while (*attr) { + if (strcmp (*attr, "offset") == 0) { + offset = *++attr; + } + attr++; + } + + fprintf (trace->stream, "["); + sprintf (trace->tail_buf, "] %s set-dash\n", offset); + trace->tail = trace->tail_buf; + } else { + } +} + +static void +cdata (void *closure, + const XML_Char *s, + int len) +{ + struct trace *trace = closure; + + if (trace->tail) + fwrite (s, len, 1, trace->stream); +} + +static void +end_element (void *closure, + const char *element) +{ + struct trace *trace = closure; + + if (trace->tail) { + fprintf (trace->stream, "%s", trace->tail); + trace->tail = NULL; + } + + if (strcmp (element, "paint") == 0) { + fprintf (trace->stream, "paint\n"); + } else if (strcmp (element, "mask") == 0) { + fprintf (trace->stream, "mask\n"); + } else if (strcmp (element, "stroke") == 0) { + fprintf (trace->stream, "stroke\n"); + } else if (strcmp (element, "fill") == 0) { + fprintf (trace->stream, "fill\n"); + } else if (strcmp (element, "glyphs") == 0) { + fprintf (trace->stream, "show-glyphs\n"); + } else if (strcmp (element, "clip") == 0) { + fprintf (trace->stream, "clip\n"); + } else if (strcmp (element, "source-pattern") == 0) { + fprintf (trace->stream, "set-source\n"); + } else if (strcmp (element, "mask-pattern") == 0) { + } else if (strcmp (element, "surface") == 0) { + if (--trace->surface_depth == 0) + fprintf (trace->stream, "pop\n"); + else + fprintf (trace->stream, "pop pattern\n"); + } +} + +int +main (int argc, char **argv) +{ + struct trace trace; + XML_Parser p; + char buf[8192]; + int done = 0; + FILE *in = stdin; + + trace.stream = stdout; + trace.tail = NULL; + trace.surface_depth = 0; + + if (argc >= 2 && strcmp (argv[1], "-")) + in = fopen (argv[1], "r"); + if (argc >= 3 && strcmp (argv[2], "-")) + trace.stream = fopen (argv[2], "w"); + + p = XML_ParserCreate (NULL); + XML_SetUserData (p, &trace); + XML_SetElementHandler (p, start_element, end_element); + XML_SetCharacterDataHandler (p, cdata); + do { + int len; + + len = fread (buf, 1, sizeof (buf), in); + done = feof (stdin); + + if (XML_Parse (p, buf, len, done) == XML_STATUS_ERROR) { + fprintf (stderr, "Parse error at line %ld:\n%s\n", + XML_GetCurrentLineNumber (p), + XML_ErrorString (XML_GetErrorCode (p))); + exit (-1); + } + } while (! done); + XML_ParserFree (p); + + if (in != stdin) + fclose (in); + if (trace.stream != stdout) + fclose (trace.stream); + + return 0; +} |