summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkx <kx@radix-linux.su>2026-10-17 16:39:23 +0300
committerkx <kx@radix-linux.su>2026-10-17 16:39:23 +0300
commitec1891d58b9514b621725620453cec0e31e18389 (patch)
tree6721f92c0afae3d933343b4a573ac8e5389827c6 /src
parent73d23259a690cd29c0ac74a4de963e23ecfebfac (diff)
downloadsvgc-trunk.tar.xz
Version 1.1.0HEAD1.1.0trunk
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am16
-rw-r--r--src/_svgc_version.c75
-rw-r--r--src/svgc-dlist.c535
-rw-r--r--src/svgc-dlist.h90
-rw-r--r--src/svgc.c2461
-rw-r--r--src/svgc.h620
6 files changed, 3797 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..4347204
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,16 @@
+
+lib_LTLIBRARIES = libsvgc.la
+
+libsvgc_la_SOURCES = svgc-dlist.c \
+ svgc-dlist.h \
+ svgc.c \
+ svgc.h \
+ _svgc_version.c \
+ $(top_srcdir)/version.c \
+ $(top_srcdir)/version.h
+
+libsvgc_la_CFLAGS = -I$(top_srcdir)
+
+libsvgc_la_LDFLAGS = -version-info $(SVGC_LT_VERSION_INFO)
+
+include_HEADERS = svgc.h svgc-dlist.h
diff --git a/src/_svgc_version.c b/src/_svgc_version.c
new file mode 100644
index 0000000..091f7ca
--- /dev/null
+++ b/src/_svgc_version.c
@@ -0,0 +1,75 @@
+
+/***************************************************************
+ _SVGC_VERSION.C
+
+ This file containt VERSION operation functions & data
+ definitions.
+
+ PART OF : SVGC - Simple SVG generator .
+
+ COMPILE : -I. .
+
+ NOTE : NONE .
+
+ Copyright (C) 2000 - 2026 by Andrey V.Kosteltsev.
+ All Rights Reserved.
+ ***************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+
+#define _VERSION_C_AS_HEADER_
+#include <version.c>
+#undef _VERSION_C_AS_HEADER_
+
+
+int
+_svgc_get_major_version()
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ tmp_version = (char *)_svgc_version.v_short;
+ if( sscanf( tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3 )
+ {
+ return( -1 );
+ }
+
+ return( major );
+}
+
+int
+_svgc_get_minor_version()
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ tmp_version = (char *)_svgc_version.v_short;
+ if( sscanf( tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3 )
+ {
+ return( -1 );
+ }
+
+ return( minor );
+}
+
+int
+_svgc_get_micro_version()
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ tmp_version = (char *)_svgc_version.v_short;
+ if( sscanf( tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3 )
+ {
+ return( -1 );
+ }
+
+ return( micro );
+}
diff --git a/src/svgc-dlist.c b/src/svgc-dlist.c
new file mode 100644
index 0000000..0b2fcd2
--- /dev/null
+++ b/src/svgc-dlist.c
@@ -0,0 +1,535 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* exit() */
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <svgc-dlist.h>
+
+struct svgc_dlist *create_svgc_dlist( void )
+{
+ struct svgc_dlist *ret = (struct svgc_dlist *)0;
+
+ ret = (struct svgc_dlist *)malloc( sizeof( struct svgc_dlist ) );
+ if( !ret )
+ {
+ return( (struct svgc_dlist *)0 );
+ }
+
+ ret->root_up = (struct svgc_dlist_node *)0;
+ ret->root_down = (struct svgc_dlist_node *)0;
+ ret->ptr = (struct svgc_dlist_node *)0;
+
+ return( ret );
+
+}
+
+
+void free_svgc_dlist( struct svgc_dlist * plist, FREE_SVGC_DLIST_NODE_DATA free_data )
+{
+ struct svgc_dlist_node *p;
+
+ if( plist != (struct svgc_dlist *)0 )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->ptr = (struct svgc_dlist_node *)0;
+ return;
+ }
+
+ for( p = plist->root_up; p != (struct svgc_dlist_node *)0; p = p->down )
+ {
+ if( p->up )
+ {
+ if( p->up->id ) free( p->up->id );
+ if( free_data ) free_data( p->up->data );
+ free( p->up );
+ }
+ }
+ if( plist->root_down->id ) free( plist->root_down->id );
+ if( free_data ) free_data( plist->root_down->data );
+ free( plist->root_down );
+
+ plist->root_up = (struct svgc_dlist_node *)0;
+ plist->root_down = (struct svgc_dlist_node *)0;
+ plist->ptr = (struct svgc_dlist_node *)0;
+
+ free( plist );
+ }
+}
+
+/* add svgc_dlist_node up */
+struct svgc_dlist_node *add_to_svgc_dlist_up( struct svgc_dlist * plist, char * id, void * data )
+{
+ struct svgc_dlist_node *ret = (struct svgc_dlist_node *)0;
+ char *s = (char *)0;
+
+ if( !plist ) return( (struct svgc_dlist_node *)0 );
+
+ ret = (struct svgc_dlist_node *)malloc( sizeof( struct svgc_dlist_node ) );
+ if( !ret )
+ {
+ return( (struct svgc_dlist_node *)0 );
+ }
+
+ ret->id = (char *)0;
+ ret->data = (void *)0;
+
+ if( id && id[0] )
+ {
+ s = (char *)malloc( strlen( id ) + 1 );
+ if( !s )
+ {
+ free( ret );
+ return( (struct svgc_dlist_node *)0 );
+ }
+ strcpy( s, id );
+ ret->id = s;
+ }
+
+ if( data ) ret->data = data;
+
+ /* add to list */
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->root_up = plist->root_down = plist->ptr = ret;
+ ret->up = (struct svgc_dlist_node *)0;
+ ret->down = (struct svgc_dlist_node *)0;
+ }
+ else
+ {
+ plist->root_up->up = ret;
+ ret->up = (struct svgc_dlist_node *)0;
+ ret->down = plist->root_up;
+ plist->root_up = ret;
+ }
+
+ return( ret );
+}
+
+/* add svgc_dlist_node down */
+struct svgc_dlist_node *add_to_svgc_dlist_down( struct svgc_dlist * plist, char * id, void * data )
+{
+ struct svgc_dlist_node *ret = (struct svgc_dlist_node *)0;
+ char *s = (char *)0;
+
+ if( !plist ) return( (struct svgc_dlist_node *)0 );
+
+ ret = (struct svgc_dlist_node *)malloc( sizeof( struct svgc_dlist_node ) );
+ if( !ret )
+ {
+ return( (struct svgc_dlist_node *)0 );
+ }
+
+ ret->id = (char *)0;
+ ret->data = (void *)0;
+
+ if( id && id[0] )
+ {
+ s = (char *)malloc( strlen( id ) + 1 );
+ if( !s )
+ {
+ free( ret );
+ return( (struct svgc_dlist_node *)0 );
+ }
+ strcpy( s, id );
+ ret->id = s;
+ }
+
+ if( data ) ret->data = data;
+
+ /* add to list */
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->root_up = plist->root_down = plist->ptr = ret;
+ ret->up = (struct svgc_dlist_node *)0;
+ ret->down = (struct svgc_dlist_node *)0;
+ }
+ else
+ {
+ plist->root_down->down = ret;
+ ret->up = plist->root_down;
+ ret->down = (struct svgc_dlist_node *)0;
+ plist->root_down = ret;
+ plist->ptr = ret;
+ }
+
+ return( ret );
+}
+
+
+struct svgc_dlist_node *insert_into_svgc_dlist_up( struct svgc_dlist * plist, struct svgc_dlist_node * p )
+{
+ if( plist && p )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->root_up = plist->root_down = plist->ptr = p;
+ p->up = (struct svgc_dlist_node *)0;
+ p->down = (struct svgc_dlist_node *)0;
+ }
+ else
+ {
+ plist->root_up->up = p;
+ p->up = (struct svgc_dlist_node *)0;
+ p->down = plist->root_up;
+ plist->root_up = p;
+ }
+ return( p );
+ }
+ else
+ {
+ return( (struct svgc_dlist_node *)0 );
+ }
+}
+
+struct svgc_dlist_node *insert_into_svgc_dlist_down( struct svgc_dlist * plist, struct svgc_dlist_node * p )
+{
+ if( plist && p )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->root_up = plist->root_down = plist->ptr = p;
+ p->up = (struct svgc_dlist_node *)0;
+ p->down = (struct svgc_dlist_node *)0;
+ }
+ else
+ {
+ plist->root_down->down = p;
+ p->up = plist->root_down;
+ p->down = (struct svgc_dlist_node *)0;
+ plist->root_down = p;
+ plist->ptr = p;
+ }
+ return( p );
+ }
+ else
+ {
+ return( (struct svgc_dlist_node *)0 );
+ }
+}
+
+struct svgc_dlist_node *
+insert_into_svgc_dlist_after( struct svgc_dlist * plist,
+ struct svgc_dlist_node * point, struct svgc_dlist_node * p )
+{
+ if( plist && point && p )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->root_up = plist->root_down = plist->ptr = p;
+ p->up = (struct svgc_dlist_node *)0;
+ p->down = (struct svgc_dlist_node *)0;
+ }
+ else
+ {
+ point->down->up = p;
+ p->down = point->down;
+ point->down = p;
+ p->up = point;
+ }
+ return( p );
+ }
+ else
+ {
+ return( (struct svgc_dlist_node *)0 );
+ }
+}
+
+
+/*
+ lookup svgc_dlist_node, since up for down ( down ).
+ */
+struct svgc_dlist_node *lookup_svgc_dlist_node_down( struct svgc_dlist * plist, char * id )
+{
+ struct svgc_dlist_node *p;
+
+ if( !plist && !id && !id[0] ) return( (struct svgc_dlist_node *)0 );
+
+ if( plist != (struct svgc_dlist *)0 )
+ {
+ for( p = plist->root_up; p != (struct svgc_dlist_node *)0; p = p->down )
+ {
+ if( strcmp( p->id, id ) == 0 ) return( p );
+ }
+ }
+ return( (struct svgc_dlist_node *)0 );
+}
+
+/*
+ lookup svgc_dlist_node, since down for up ( down ).
+ */
+struct svgc_dlist_node *lookup_svgc_dlist_node_up( struct svgc_dlist * plist, char * id )
+{
+ struct svgc_dlist_node *p;
+
+ if( !plist && !id && !id[0] ) return( (struct svgc_dlist_node *)0 );
+
+ if( plist != (struct svgc_dlist *)0 )
+ {
+ for( p = plist->root_down; p != (struct svgc_dlist_node *)0; p = p->up )
+ {
+ if( strcmp( p->id, id ) == 0 ) return( p );
+ }
+ }
+ return( (struct svgc_dlist_node *)0 );
+}
+
+
+
+/* detach svgc_dlist_node */
+struct svgc_dlist_node *detach_svgc_dlist_node( struct svgc_dlist * plist, struct svgc_dlist_node * p )
+{
+ if( plist && p )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ /* EMPTY svgc_dlist */
+ return( (struct svgc_dlist_node *)0 );
+ }
+ else
+ {
+ if( p->up ) p->up->down = p->down;
+ if( p->down ) p->down->up = p->up;
+
+
+ if( p == plist->root_up ) plist->root_up = p->down;
+ if( p == plist->root_down ) plist->root_down = p->up;
+ if( p == plist->ptr ) plist->ptr = p->down;
+
+ return( p );
+ }
+ }
+ else
+ {
+ return( (struct svgc_dlist_node *)0 );
+ }
+}
+
+/* detach svgc_dlist_node by id */
+struct svgc_dlist_node *detach_svgc_dlist_node_by_id( struct svgc_dlist * plist, char * id )
+{
+ struct svgc_dlist_node *p = (struct svgc_dlist_node *)0;
+
+ p = lookup_svgc_dlist_node_down( plist, id );
+
+ if( plist && p )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ /* EMPTY svgc_dlist */
+ return( (struct svgc_dlist_node *)0 );
+ }
+ else
+ {
+ if( p->up ) p->up->down = p->down;
+ if( p->down ) p->down->up = p->up;
+
+
+ if( p == plist->root_up ) plist->root_up = p->down;
+ if( p == plist->root_down ) plist->root_down = p->up;
+ if( p == plist->ptr ) plist->ptr = p->down;
+
+ return( p );
+ }
+ }
+ else
+ {
+ return( (struct svgc_dlist_node *)0 );
+ }
+}
+
+/* remove svgc_dlist_node */
+int
+remove_svgc_dlist_node( struct svgc_dlist * plist,
+ struct svgc_dlist_node * p, FREE_SVGC_DLIST_NODE_DATA free_data )
+{
+ if( plist && p )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ /* EMPTY svgc_dlist */
+ return( 0 ); /* FALSE */
+ }
+ else
+ {
+ if( p->up ) p->up->down = p->down;
+ if( p->down ) p->down->up = p->up;
+
+
+ if( p == plist->root_up ) plist->root_up = p->down;
+ if( p == plist->root_down ) plist->root_down = p->up;
+ if( p == plist->ptr ) plist->ptr = p->down;
+
+ if( p->id ) free( p->id );
+ if( free_data ) free_data( p->data );
+ free( p );
+
+ return( 1 ); /* TRUE */
+ }
+ }
+ else
+ {
+ return( 0 ); /* FALSE */
+ }
+}
+
+/* remove svgc_dlist_node by id */
+int remove_svgc_dlist_node_by_id( struct svgc_dlist * plist, char * id, FREE_SVGC_DLIST_NODE_DATA free_data )
+{
+ struct svgc_dlist_node *p = (struct svgc_dlist_node *)0;
+
+ p = lookup_svgc_dlist_node_down( plist, id );
+
+ if( plist && p )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ /* EMPTY svgc_dlist */
+ return( 0 ); /* FALSE */
+ }
+ else
+ {
+ if( p->up ) p->up->down = p->down;
+ if( p->down ) p->down->up = p->up;
+
+
+ if( p == plist->root_up ) plist->root_up = p->down;
+ if( p == plist->root_down ) plist->root_down = p->up;
+ if( p == plist->ptr ) plist->ptr = p->down;
+
+ if( p->id ) free( p->id );
+ if( free_data ) free_data( p->data );
+ free( p );
+
+ return( 1 ); /* TRUE */
+ }
+ }
+ else
+ {
+ return( 0 ); /* FALSE */
+ }
+}
+
+
+/* move svgc_dlist_node: detach from SLIST, and insert_into_svgc_dlist_down() to TLIST */
+struct svgc_dlist_node *
+move_svgc_dlist_node( struct svgc_dlist * tlist, struct svgc_dlist * slist,
+ struct svgc_dlist_node * p )
+{
+ if( !slist || !p ) return( (struct svgc_dlist_node *)0 );
+
+ if( slist->root_up == (struct svgc_dlist_node *)0 &&
+ slist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ /* EMPTY partition_list */
+ return( (struct svgc_dlist_node *)0 );
+ }
+ else
+ {
+ if( p->up ) p->up->down = p->down;
+ if( p->down ) p->down->up = p->up;
+
+
+ if( p == slist->root_up ) slist->root_up = p->down;
+ if( p == slist->root_down ) slist->root_down = p->up;
+ if( p == slist->ptr ) slist->ptr = p->down;
+
+ insert_into_svgc_dlist_down( tlist, p );
+
+ return( p );
+ }
+}
+
+
+
+void set_svgc_dlist_ptr_up( struct svgc_dlist * plist )
+{
+ if( !plist ) return;
+ plist->ptr = plist->root_up;
+}
+void set_svgc_dlist_ptr_down( struct svgc_dlist * plist )
+{
+ if( !plist ) return;
+ plist->ptr = plist->root_down;
+}
+
+void for_each_svgc_dlist_node_data( struct svgc_dlist * plist, FOR_EACH_SVGC_DLIST_NODE_DATA func )
+{
+ struct svgc_dlist_node *p;
+
+ if( plist != (struct svgc_dlist *)0 )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->ptr = (struct svgc_dlist_node *)0;
+ return;
+ }
+
+ for( p = plist->root_up; p != (struct svgc_dlist_node *)0; p = p->down )
+ {
+ if( p->up )
+ {
+ if( func ) func( p->up->data );
+ }
+ }
+ if( func ) func( plist->root_down->data );
+ }
+}
+
+void printf_svgc_dlist( struct svgc_dlist * plist, PRINT_SVGC_DLIST_NODE_DATA func )
+{
+ struct svgc_dlist_node *p;
+
+ fprintf( stderr, "\nD-LIST:\n"
+ "======\n\n" );
+
+ if( plist != (struct svgc_dlist *)0 )
+ {
+ if( plist->root_up == (struct svgc_dlist_node *)0 &&
+ plist->root_down == (struct svgc_dlist_node *)0 )
+ {
+ plist->ptr = (struct svgc_dlist_node *)0;
+ return;
+ }
+
+ for( p = plist->root_up; p != (struct svgc_dlist_node *)0; p = p->down )
+ {
+ if( p->up )
+ {
+ if( p->up->id )
+ fprintf( stderr, " id = '%s':\n", p->up->id );
+ else
+ fprintf( stderr, " id = '':\n" );
+ if( func ) func( p->up->data );
+ }
+ }
+ if( plist->root_down->id )
+ fprintf( stderr, " id = '%s':\n", plist->root_down->id );
+ else
+ fprintf( stderr, " id = '':\n" );
+ if( func ) func( plist->root_down->data );
+ }
+}
diff --git a/src/svgc-dlist.h b/src/svgc-dlist.h
new file mode 100644
index 0000000..676c98a
--- /dev/null
+++ b/src/svgc-dlist.h
@@ -0,0 +1,90 @@
+
+/***************************************************************
+ SVGC-DLIST.H
+
+ This file containt declarations of SVG double linked
+ list functions.
+ ***************************************************************/
+
+#ifndef __SVGC_DLIST_H__
+#define __SVGC_DLIST_H__
+
+#if defined( __cplusplus )
+extern "C"
+{
+#endif
+
+/* the structure of a double linked list entry */
+typedef struct svgc_dlist_node svgc_dlist_node;
+struct svgc_dlist_node
+{
+ struct svgc_dlist_node *up;
+ struct svgc_dlist_node *down;
+
+ char *id;
+ void *data;
+};
+
+/* the structure of a double linked list instance */
+typedef struct svgc_dlist svgc_dlist;
+struct svgc_dlist
+{
+ struct svgc_dlist_node *root_up;
+ struct svgc_dlist_node *root_down;
+ struct svgc_dlist_node *ptr;
+};
+
+typedef void ( *FREE_SVGC_DLIST_NODE_DATA )( void * );
+typedef void ( *FOR_EACH_SVGC_DLIST_NODE_DATA )( void * );
+typedef void ( *PRINT_SVGC_DLIST_NODE_DATA )( void * );
+
+
+extern struct svgc_dlist *create_svgc_dlist( void );
+extern void free_svgc_dlist( struct svgc_dlist *plist, FREE_SVGC_DLIST_NODE_DATA free_data );
+
+/* add svgc_dlist_node up */
+extern struct svgc_dlist_node *add_to_svgc_dlist_up( struct svgc_dlist *plist, char *id, void *data );
+/* add svgc_dlist_node down */
+extern struct svgc_dlist_node *add_to_svgc_dlist_down( struct svgc_dlist *plist, char *id, void *data );
+
+extern struct svgc_dlist_node *insert_into_svgc_dlist_up( struct svgc_dlist *plist, struct svgc_dlist_node *p );
+
+extern struct svgc_dlist_node *insert_into_svgc_dlist_down( struct svgc_dlist *plist, struct svgc_dlist_node *p );
+
+extern struct svgc_dlist_node *insert_into_svgc_dlist_after( struct svgc_dlist *plist, struct svgc_dlist_node *point, struct svgc_dlist_node *p );
+
+/*
+ lookup svgc_dlist_node, since up for down ( down ).
+ */
+extern struct svgc_dlist_node *lookup_svgc_dlist_node_down( struct svgc_dlist *plist, char *id );
+
+/*
+ lookup svgc_dlist_node, since down for up ( down ).
+ */
+extern struct svgc_dlist_node *lookup_svgc_dlist_node_up( struct svgc_dlist *plist, char *id );
+
+/* detach svgc_dlist_node */
+extern struct svgc_dlist_node *detach_svgc_dlist_node( struct svgc_dlist *plist, struct svgc_dlist_node *p );
+/* detach svgc_dlist_node by id */
+extern struct svgc_dlist_node *detach_svgc_dlist_node_by_id( struct svgc_dlist *plist, char *id );
+
+/* remove svgc_dlist_node */
+extern int remove_svgc_dlist_node( struct svgc_dlist *plist, struct svgc_dlist_node *p, FREE_SVGC_DLIST_NODE_DATA free_data );
+/* remove svgc_dlist_node by id */
+int remove_svgc_dlist_node_by_id( struct svgc_dlist *plist, char *id, FREE_SVGC_DLIST_NODE_DATA free_data );
+
+/* move svgc_dlist_node: detach from SLIST, and insert_into_svgc_dlist_down() to TLIST */
+extern struct svgc_dlist_node *move_svgc_dlist_node( struct svgc_dlist *tlist, struct svgc_dlist *slist, struct svgc_dlist_node *p );
+
+
+extern void set_svgc_dlist_ptr_up( struct svgc_dlist *plist );
+extern void set_svgc_dlist_ptr_down( struct svgc_dlist *plist );
+
+extern void for_each_svgc_dlist_node_data( struct svgc_dlist *plist, FOR_EACH_SVGC_DLIST_NODE_DATA func );
+extern void printf_svgc_dlist( struct svgc_dlist *plist, PRINT_SVGC_DLIST_NODE_DATA func );
+
+#if defined( __cplusplus )
+} /* extern "C" */
+#endif
+
+#endif /* __SVGC_DLIST_H__ */
diff --git a/src/svgc.c b/src/svgc.c
new file mode 100644
index 0000000..7c0a209
--- /dev/null
+++ b/src/svgc.c
@@ -0,0 +1,2461 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* exit() */
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+#include <svgc.h>
+
+/* Embedded CSS and ECMAScript definitions use the ordinary SVG node header. */
+struct __svg_embedded_text
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ char *content;
+ size_t length;
+};
+
+int current_id = 3700;
+
+/***************************************************************
+ __svg_str_dup()
+
+ Выделяет память для дубликата строки S и копирует в нее
+ содержимое S.
+
+ Возвращаемое значение:
+ Указатель на созданный дубликат.
+ ***************************************************************/
+char *
+__svg_str_dup( const char * s )
+{
+ int len = 0;
+ void *new = NULL;
+
+ if( s == (char *)NULL ) return( (char *)NULL );
+
+ len = (strlen( s ) + 1) * sizeof( char );
+ new = malloc( len );
+
+ if( new == (void *)NULL ) return( (char *)NULL );
+
+ return( (char *)memcpy( new, (void *)s, len ) );
+
+} /* End of __svg_str_dup() */
+
+
+/***************************************************************
+ POINTS:
+ ***************************************************************/
+void
+__svg_free_point( void * data )
+{
+ struct __svg_point *p = (struct __svg_point *)data;
+
+ if( !p ) return;
+
+ free( p );
+}
+
+void __svg_free_points( struct __svg_points * p )
+{
+ if( !p ) return;
+ if( p->plist )
+ {
+ /* clear svgc_dlist */
+ free_svgc_dlist( p->plist, __svg_free_point );
+ }
+
+ free( p );
+}
+
+struct __svg_points *
+__svg_new_points( void )
+{
+ struct __svg_points *new = (struct __svg_points *)NULL;
+
+ new = (struct __svg_points *)malloc( sizeof(struct __svg_points) );
+ if( new == (struct __svg_points *)NULL ) return( (struct __svg_points *)NULL );
+ memset( (void *)new, 0, sizeof(struct __svg_points) );
+
+ new->plist = create_svgc_dlist();
+ if( !new->plist )
+ {
+ free( new );
+ return( (struct __svg_points *)NULL );
+ }
+ new->count = 0;
+
+ return( (struct __svg_points *)new );
+}
+
+int __svg_add_point( struct __svg_points * ps, double x, double y )
+{
+ struct __svg_point *new = (struct __svg_point *)NULL;
+ struct svgc_dlist_node *np = NULL;
+ char buf[256];
+ int error = -1; /* EINVAL */
+
+ if( !ps || !ps->plist) return( error );
+ error = 0;
+
+ new = (struct __svg_point *)malloc( sizeof(struct __svg_point) );
+ if( new == (struct __svg_point *)NULL ) return( error );
+ memset( (void *)new, 0, sizeof(struct __svg_point) );
+
+ new->x = x;
+ new->y = y;
+ error = ++ps->count;
+ sprintf( buf, "%d", error );
+
+ np = add_to_svgc_dlist_down( ps->plist, buf, (void *)new );
+ if( !np ) error = 0;
+
+ return( error );
+}
+
+/***************************************************************
+ PATH CMDS:
+ ***************************************************************/
+void
+__svg_free_cmd( void * data )
+{
+ struct __svg_cmd *cmd = (struct __svg_cmd *)data;
+
+ if( !cmd ) return;
+ if( !cmd->points )
+ __svg_free_points( cmd->points );
+
+ free( cmd );
+}
+
+void __svg_free_cmds( struct __svg_cmds * cmds )
+{
+ if( !cmds ) return;
+ if( cmds->plist )
+ {
+ /* clear svgc_dlist */
+ free_svgc_dlist( cmds->plist, __svg_free_cmd );
+ }
+
+ free( cmds );
+}
+
+struct __svg_cmd *
+__svg_new_cmd( char cmd, struct __svg_points * ps )
+{
+ struct __svg_cmd *new = NULL;
+
+ if( !ps ) return( new );
+
+ new = (struct __svg_cmd *)malloc( sizeof( struct __svg_cmd ) );
+ if( new == (struct __svg_cmd *)NULL ) return( (struct __svg_cmd *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_cmd ) );
+
+ new->cmd = cmd;
+ new->points = ps;
+
+ return( (struct __svg_cmd *)new );
+}
+
+struct __svg_cmds *
+__svg_new_cmds( void )
+{
+ struct __svg_cmds *new = (struct __svg_cmds *)NULL;
+
+ new = (struct __svg_cmds *)malloc( sizeof(struct __svg_cmds) );
+ if( new == (struct __svg_cmds *)NULL ) return( (struct __svg_cmds *)NULL );
+ memset( (void *)new, 0, sizeof(struct __svg_cmds) );
+
+ new->plist = create_svgc_dlist();
+ if( !new->plist )
+ {
+ free( new );
+ return( (struct __svg_cmds *)NULL );
+ }
+ new->count = 0;
+
+ return( (struct __svg_cmds *)new );
+}
+
+int __svg_add_cmd( struct __svg_cmds * cmds, struct __svg_cmd * cmd )
+{
+ struct svgc_dlist_node *np = NULL;
+ char buf[256];
+ int error = -1; /* EINVAL */
+
+ if( !cmd || !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ error = ++cmds->count;
+ sprintf( buf, "%d", error );
+
+ np = add_to_svgc_dlist_down( cmds->plist, buf, (void *)cmd );
+ if( !np ) error = 0;
+
+ return( error );
+}
+
+/*
+ Start a new sub-path at the given (x,y) coordinate. M (uppercase) indicates
+ that absolute coordinates will follow; m (lowercase) indicates that relative
+ coordinates will follow. If a relative moveto (m) appears as the first
+ element of the path, then it is treated as a pair of absolute coordinates.
+ If a moveto is followed by multiple pairs of coordinates, the subsequent
+ pairs are treated as implicit lineto commands.
+
+ Args: (x y)+
+ */
+int
+__svg_add_moveto_cmd( struct __svg_cmds * cmds, int abs, double x, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'm';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+ error = __svg_add_point( points, x, y );
+ if( error < 1 ) return( error );
+ if( abs ) c = 'M';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Close the current subpath by drawing a straight line from the current point
+ to current subpath's initial point.
+ */
+int
+__svg_add_closepath_cmd( struct __svg_cmds * cmds, int abs )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'z';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+ error = __svg_add_point( points, 0.0, 0.0 );
+ if( error < 1 ) return( error );
+ if( abs ) c = 'Z';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draw a line from the current point to the given (x,y) coordinate which
+ becomes the new current point. L (uppercase) indicates that absolute
+ coordinates will follow; l (lowercase) indicates that relative coordinates
+ will follow. A number of coordinates pairs may be specified to draw
+ a polyline. At the end of the command, the new current point is set to the
+ final set of coordinates provided.
+
+ Args: (x y)+
+ */
+int
+__svg_add_lineto_cmd( struct __svg_cmds * cmds, int abs, double x, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'l';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+ error = __svg_add_point( points, x, y );
+ if( error < 1 ) return( error );
+ if( abs ) c = 'L';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draws a horizontal line from the current point (cpx, cpy) to (x, cpy).
+ H (uppercase) indicates that absolute coordinates will follow; h (lowercase)
+ indicates that relative coordinates will follow. Multiple x values can
+ be provided (although usually this doesn't make sense). At the end of the
+ command, the new current point becomes (x, cpy) for the final value of x.
+
+ Args: (x)+
+ */
+int
+__svg_add_hlineto_cmd( struct __svg_cmds * cmds, int abs, double x )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'h';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+ error = __svg_add_point( points, x, 0.0 );
+ if( error < 1 ) return( error );
+ if( abs ) c = 'H';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draws a vertical line from the current point (cpx, cpy) to (cpx, y).
+ V (uppercase) indicates that absolute coordinates will follow; v (lowercase)
+ indicates that relative coordinates will follow. Multiple y values can be
+ provided (although usually this doesn't make sense). At the end of the
+ command, the new current point becomes (cpx, y) for the final value of y.
+
+ Args: (y)+
+ */
+int
+__svg_add_vlineto_cmd( struct __svg_cmds * cmds, int abs, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'v';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+ error = __svg_add_point( points, 0.0, y );
+ if( error < 1 ) return( error );
+ if( abs ) c = 'V';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draws a cubic Bezier curve from the current point to (x,y) using (x1,y1) as
+ the control point at the beginning of the curve and (x2,y2) as the control
+ point at the end of the curve. C (uppercase) indicates that absolute
+ coordinates will follow; c (lowercase) indicates that relative coordinates
+ will follow. Multiple sets of coordinates may be specified to draw a
+ polybezier. At the end of the command, the new current point becomes the
+ final (x,y) coordinate pair used in the polybezier.
+
+ Args: (x1 y1 x2 y2 x y)+
+ */
+int
+__svg_add_curveto_cmd( struct __svg_cmds * cmds, int abs,
+ double x1, double y1, double x2, double y2, double x, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'c';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+
+ error = __svg_add_point( points, x1, y1 );
+ if( error < 1 ) return( error );
+ error = __svg_add_point( points, x2, y2 );
+ if( error < 1 ) return( error );
+ error = __svg_add_point( points, x, y );
+ if( error < 1 ) return( error );
+
+ if( abs ) c = 'C';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draws a cubic Bezier curve from the current point to (x,y). The first control
+ point is assumed to be the reflection of the second control point on the
+ previous command relative to the current point. (If there is no previous
+ command or if the previous command was not an C, c, S or s, assume the first
+ control point is coincident with the current point.) (x2,y2) is the second
+ control point (i.e., the control point at the end of the curve).
+ S (uppercase) indicates that absolute coordinates will follow; s (lowercase)
+ indicates that relative coordinates will follow. Multiple sets of coordinates
+ may be specified to draw a polybezier. At the end of the command, the new
+ current point becomes the final (x,y) coordinate pair used in the polybщzier.
+
+ Args: (x2 y2 x y)+
+ */
+int
+__svg_add_short_curveto_cmd( struct __svg_cmds * cmds, int abs, double x2, double y2, double x, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 's';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+
+ error = __svg_add_point( points, x2, y2 );
+ if( error < 1 ) return( error );
+ error = __svg_add_point( points, x, y );
+ if( error < 1 ) return( error );
+
+ if( abs ) c = 'S';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draws a quadratic Bezier curve from the current point to (x,y) using (x1,y1)
+ as the control point. Q (uppercase) indicates that absolute coordinates will
+ follow; q (lowercase) indicates that relative coordinates will follow.
+ Multiple sets of coordinates may be specified to draw a polybezier. At the
+ end of the command, the new current point becomes the final (x,y) coordinate
+ pair used in the polybezier.
+
+ Args: (x1 y1 x y)+
+ */
+int
+__svg_add_quadro_curveto_cmd( struct __svg_cmds * cmds, int abs, double x1, double y1, double x, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'q';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+
+ error = __svg_add_point( points, x1, y1 );
+ if( error < 1 ) return( error );
+ error = __svg_add_point( points, x, y );
+ if( error < 1 ) return( error );
+
+ if( abs ) c = 'Q';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draws a quadratic Bezier curve from the current point to (x,y). The control
+ point is assumed to be the reflection of the control point on the previous
+ command relative to the current point. (If there is no previous command or if
+ the previous command was not a Q, q, T or t, assume the control point is
+ coincident with the current point.) T (uppercase) indicates that absolute
+ coordinates will follow; t (lowercase) indicates that relative coordinates
+ will follow. At the end of the command, the new current point becomes the
+ final (x,y) coordinate pair used in the polybezier.
+
+ Args: (x y)+
+ */
+int
+__svg_add_short_quadro_curveto_cmd( struct __svg_cmds * cmds, int abs, double x, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 't';
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+
+ error = __svg_add_point( points, x, y );
+ if( error < 1 ) return( error );
+
+ if( abs ) c = 'T';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+/*
+ Draws an elliptical arc from the current point to (x, y). The size and
+ orientation of the ellipse are defined by two radii (rx, ry) and an
+ x-axis-rotation, which indicates how the ellipse as a whole is rotated
+ relative to the current coordinate system. The center (cx, cy) of the
+ ellipse is calculated automatically to satisfy the constraints imposed
+ by the other parameters. large-arc-flag and sweep-flag contribute to the
+ automatic calculations and help determine how the arc is drawn.
+
+ Args: (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
+ */
+int
+__svg_add_arc_cmd( struct __svg_cmds * cmds, int abs,
+ double rx, double ry, double x_axis_rotation,
+ int large_arc_flag, int sweep_flag, double x, double y )
+{
+ struct __svg_points *points = NULL;
+ struct __svg_cmd *cmd = NULL;
+ char c = 'a';
+ double lf = 0.0, sf = 0.0;
+ int error = -1; /* EINVAL */
+
+ if( !cmds || !cmds->plist) return( error );
+ error = 0;
+
+ points = __svg_new_points();
+ if( !points ) return( error );
+
+ error = __svg_add_point( points, rx, ry );
+ if( error < 1 ) return( error );
+ error = __svg_add_point( points, x_axis_rotation, 0.0 );
+ if( error < 1 ) return( error );
+ if( large_arc_flag ) lf = 1.0;
+ if( sweep_flag ) sf = 1.0;
+ error = __svg_add_point( points, lf, sf );
+ if( error < 1 ) return( error );
+ error = __svg_add_point( points, x, y );
+ if( error < 1 ) return( error );
+
+ if( abs ) c = 'A';
+ cmd = __svg_new_cmd( c, points );
+ error = __svg_add_cmd( cmds, cmd );
+
+ return( error );
+}
+
+
+/***************************************************************
+ STYLE:
+ ***************************************************************/
+
+/***************************************************************
+ Default values:
+ ***************************************************************/
+static struct __svg_rgb
+ default_stroke_rgb = { 0, 0, 0 };
+static const char *default_stroke = STROKE_DEFAULT;
+static double default_stroke_width = 1.0;
+static const char *default_stroke_linecap = LINECAP_DEFAULT;
+static const char *default_stroke_linejoin = LINEJOIN_DEFAULT;
+static const char *default_stroke_dasharray = DASHARRAY_DEFAULT;
+
+static struct __svg_rgb
+ default_fill_rgb = { 255, 255, 255 };
+static const char *default_fill = FILL_DEFAULT;
+
+static struct __svg_rgb
+ default_stop_color_rgb = { 0, 0, 0 };
+static const char *default_stop_color = STOP_COLOR_DEFAULT;
+
+static double default_stop_opacity = STOP_OPACITY_DEFAULT;
+
+/* static buffer for stroke: */
+static char stroke_buf[32];
+
+/* static buffer for fill: */
+static char fill_buf[32];
+
+/* static buffer for stop color: */
+static char stop_color_buf[32];
+
+static const char *default_text_font_family = TEXT_FONT_FAMILY_DEFAULT;
+static int default_text_font_size = TEXT_FONT_SIZE_DEFAULT;
+static struct __svg_rgb
+ default_text_fill_rgb = { 255, 255, 255 };
+static const char *default_text_fill = TEXT_FILL_DEFAULT;
+/* static buffer for text fill: */
+static char text_fill_buf[32];
+static char text_family_buf[128];
+
+
+void __svg_set_scene_default_style( void )
+{
+ default_stroke_rgb.r = 0;
+ default_stroke_rgb.g = 0;
+ default_stroke_rgb.b = 0;
+
+ default_stroke = STROKE_DEFAULT;
+ default_stroke_width = 1.0;
+ default_stroke_linecap = LINECAP_DEFAULT;
+ default_stroke_linejoin = LINEJOIN_DEFAULT;
+ default_stroke_dasharray = DASHARRAY_DEFAULT;
+
+
+ default_fill_rgb.r = 255;
+ default_fill_rgb.g = 255;
+ default_fill_rgb.b = 255;
+
+ default_fill = FILL_DEFAULT;
+
+ default_stop_color_rgb.r = 0;
+ default_stop_color_rgb.g = 0;
+ default_stop_color_rgb.b = 0;
+
+ default_stop_opacity = STOP_OPACITY_DEFAULT;
+
+ default_text_fill_rgb.r = 255;
+ default_text_fill_rgb.g = 255;
+ default_text_fill_rgb.b = 255;
+
+ default_text_fill = TEXT_FILL_DEFAULT;
+ default_text_font_family = TEXT_FONT_FAMILY_DEFAULT;
+ default_text_font_size = TEXT_FONT_SIZE_DEFAULT;
+}
+
+void __svg_set_scene_stroke( const char * stroke )
+{
+ default_stroke = stroke;
+}
+void __svg_set_scene_stroke_rgb( int r, int g, int b )
+{
+ default_stroke_rgb.r = r;
+ default_stroke_rgb.g = g;
+ default_stroke_rgb.b = b;
+
+ sprintf( stroke_buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ default_stroke = stroke_buf;
+}
+void __svg_set_scene_stroke_width( double width )
+{
+ default_stroke_width = width;
+}
+void __svg_set_scene_stroke_linecap( const char * linecap )
+{
+ default_stroke_linecap = linecap;
+}
+void __svg_set_scene_stroke_linejoin( const char * linejoin )
+{
+ default_stroke_linejoin = linejoin;
+}
+void __svg_set_scene_stroke_dasharray( const char * dasharray )
+{
+ default_stroke_dasharray = dasharray;
+}
+
+void __svg_set_scene_fill( const char * fill )
+{
+ default_fill = fill;
+}
+void __svg_set_scene_fill_rgb( int r, int g, int b )
+{
+ default_fill_rgb.r = r;
+ default_fill_rgb.g = g;
+ default_fill_rgb.b = b;
+
+ sprintf( fill_buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ default_fill = fill_buf;
+}
+
+void __svg_set_scene_stop_color( const char * stop_color )
+{
+ default_stop_color = stop_color;
+}
+void __svg_set_scene_stop_color_rgb( int r, int g, int b )
+{
+ default_stop_color_rgb.r = r;
+ default_stop_color_rgb.g = g;
+ default_stop_color_rgb.b = b;
+
+ sprintf( stop_color_buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ default_stop_color = stop_color_buf;
+}
+
+void __svg_set_scene_stop_opacity( double stop_opacity )
+{
+ default_stop_opacity = stop_opacity;
+}
+
+void __svg_set_scene_text_fill( const char * fill )
+{
+ default_text_fill = fill;
+}
+void __svg_set_scene_text_fill_rgb( int r, int g, int b )
+{
+ default_text_fill_rgb.r = r;
+ default_text_fill_rgb.g = g;
+ default_text_fill_rgb.b = b;
+
+ sprintf( text_fill_buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ default_text_fill = text_fill_buf;
+}
+void __svg_set_scene_text_font_family( const char * family )
+{
+ if( !family || !family[0] ||
+ strlen( family ) > (sizeof( text_family_buf ) - 1) )
+ return;
+
+ sprintf( text_family_buf, "%s", family );
+
+ default_text_font_family = text_family_buf;
+}
+void __svg_set_scene_text_font_size( int size )
+{
+ default_text_font_size = size;
+}
+
+void
+__svg_free_stroke( struct __svg_stroke * s )
+{
+ if( !s ) return;
+ if( s->use_stroke ) free( s->use_stroke );
+ if( s->stroke_linecap ) free( s->stroke_linecap );
+ if( s->stroke_linejoin ) free( s->stroke_linejoin );
+ if( s->stroke_dasharray ) free( s->stroke_dasharray );
+ free( s );
+}
+
+struct __svg_stroke *
+__svg_new_stroke( void )
+{
+ struct __svg_stroke *new = NULL;
+
+ new = malloc( sizeof( struct __svg_stroke ) );
+
+ if( new == (struct __svg_stroke *)NULL ) return( (struct __svg_stroke *)NULL );
+
+ new->stroke.r = default_stroke_rgb.r;
+ new->stroke.g = default_stroke_rgb.g;
+ new->stroke.b = default_stroke_rgb.b;
+
+ new->stroke_width = default_stroke_width;
+
+ new->use_stroke = __svg_str_dup( default_stroke );
+ new->stroke_linecap = __svg_str_dup( default_stroke_linecap );
+ new->stroke_linejoin = __svg_str_dup( default_stroke_linejoin );
+ new->stroke_dasharray = __svg_str_dup( default_stroke_dasharray );
+
+ return( (struct __svg_stroke *)new );
+}
+
+void
+__svg_free_fill( struct __svg_fill * f )
+{
+ if( !f ) return;
+ if( f->use_fill ) free( f->use_fill );
+ free( f );
+}
+
+struct __svg_fill *
+__svg_new_fill( void )
+{
+ struct __svg_fill *new = NULL;
+
+ new = malloc( sizeof( struct __svg_fill ) );
+
+ if( new == (struct __svg_fill *)NULL ) return( (struct __svg_fill *)NULL );
+
+ new->fill.r = default_fill_rgb.r;
+ new->fill.g = default_fill_rgb.g;
+ new->fill.b = default_fill_rgb.b;
+
+ new->use_fill = __svg_str_dup( default_fill );
+
+ return( (struct __svg_fill *)new );
+}
+
+
+void
+__svg_free_stop_color( struct __svg_stop_color * sc )
+{
+ if( !sc ) return;
+ if( sc->use_stop_color ) free( sc->use_stop_color );
+ free( sc );
+}
+
+struct __svg_stop_color *
+__svg_new_stop_color( void )
+{
+ struct __svg_stop_color *new = NULL;
+
+ new = malloc( sizeof( struct __svg_stop_color ) );
+
+ if( new == (struct __svg_stop_color *)NULL ) return( (struct __svg_stop_color *)NULL );
+
+ new->stop_color.r = default_stop_color_rgb.r;
+ new->stop_color.g = default_stop_color_rgb.g;
+ new->stop_color.b = default_stop_color_rgb.b;
+
+ new->use_stop_color = __svg_str_dup( default_stop_color );
+
+ return( (struct __svg_stop_color *)new );
+}
+
+
+void
+__svg_free_stop_opacity( struct __svg_stop_opacity * so )
+{
+ if( !so ) return;
+ free( so );
+}
+
+struct __svg_stop_opacity *
+__svg_new_stop_opacity( void )
+{
+ struct __svg_stop_opacity *new = NULL;
+
+ new = malloc( sizeof( struct __svg_stop_opacity ) );
+
+ if( new == (struct __svg_stop_opacity *)NULL ) return( (struct __svg_stop_opacity *)NULL );
+
+ new->stop_opacity = default_stop_opacity;
+
+ return( (struct __svg_stop_opacity *)new );
+}
+
+
+void
+__svg_free_style( struct __svg_style * style )
+{
+ if( !style ) return;
+ if( style->stroke ) __svg_free_stroke ( style->stroke );
+ if( style->fill ) __svg_free_fill ( style->fill );
+ if( style->stop_color ) __svg_free_stop_color ( style->stop_color );
+ if( style->stop_opacity ) __svg_free_stop_opacity ( style->stop_opacity );
+ free( style );
+}
+
+struct __svg_style *
+__svg_new_style( void )
+{
+ struct __svg_style *new = NULL;
+
+ new = malloc( sizeof( struct __svg_style ) );
+
+ if( new == (struct __svg_style *)NULL ) return( (struct __svg_style *)NULL );
+
+ new->stroke = __svg_new_stroke();
+ new->fill = __svg_new_fill();
+ new->stop_color = __svg_new_stop_color();
+ new->stop_opacity = __svg_new_stop_opacity();
+ if( !new->stroke || !new->fill || !new->stop_color || !new->stop_opacity )
+ {
+ __svg_free_style( new );
+ return( (struct __svg_style *)NULL );
+ }
+ return( (struct __svg_style *)new );
+}
+
+
+void
+__svg_free_node( void * data )
+{
+ struct __svg_node *node = (struct __svg_node *)data;
+
+ if( !node ) return;
+ if( node->id ) free( node->id );
+ if( node->style ) __svg_free_style( node->style );
+
+ if( node->type == SVG_SHEET )
+ {
+ if( ((struct __svg_sheet *)node)->defs )
+ {
+ /* clear svgc_dlist */
+ free_svgc_dlist( ((struct __svg_sheet *)node)->defs, __svg_free_node );
+ }
+ }
+
+ if( node->type == SVG_POLYGON )
+ __svg_free_points( ((struct __svg_polygon *)node)->points );
+
+ if( node->type == SVG_POLYLINE )
+ __svg_free_points( ((struct __svg_polyline *)node)->points );
+
+ if( node->type == SVG_PATH )
+ __svg_free_cmds( ((struct __svg_path *)node)->cmds );
+
+ if( node->type == SVG_TEXT )
+ {
+ if( ((struct __svg_text *)node)->text )
+ free( ((struct __svg_text *)node)->text );
+ if( ((struct __svg_text *)node)->font_family )
+ free( ((struct __svg_text *)node)->font_family );
+ if( ((struct __svg_text *)node)->fill )
+ free( ((struct __svg_text *)node)->fill );
+ }
+
+ if( node->type == SVG_IMAGE )
+ {
+ if( ((struct __svg_image *)node)->href )
+ free( ((struct __svg_image *)node)->href );
+ if( ((struct __svg_image *)node)->title )
+ free( ((struct __svg_image *)node)->title );
+ }
+
+ if( node->type == SVG_CSS || node->type == SVG_SCRIPT )
+ {
+ free( ((struct __svg_embedded_text *)node)->content );
+ }
+
+ if( node->type == SVG_L_GRADIENT )
+ {
+ if( ((struct __svg_l_gradient *)node)->units )
+ free( ((struct __svg_l_gradient *)node)->units );
+ if( ((struct __svg_l_gradient *)node)->spread )
+ free( ((struct __svg_l_gradient *)node)->spread );
+ if( ((struct __svg_l_gradient *)node)->stops )
+ {
+ /* clear svgc_dlist */
+ free_svgc_dlist( ((struct __svg_l_gradient *)node)->stops, __svg_free_node );
+ }
+ }
+
+ if( node->type == SVG_R_GRADIENT )
+ {
+ if( ((struct __svg_r_gradient *)node)->units )
+ free( ((struct __svg_r_gradient *)node)->units );
+ if( ((struct __svg_r_gradient *)node)->spread )
+ free( ((struct __svg_r_gradient *)node)->spread );
+ if( ((struct __svg_r_gradient *)node)->stops )
+ {
+ /* clear svgc_dlist */
+ free_svgc_dlist( ((struct __svg_r_gradient *)node)->stops, __svg_free_node );
+ }
+ }
+
+ free( node );
+}
+
+
+struct __svg_node *
+__svg_new_sheet( double width, double height,
+ double left_margin, double right_margin,
+ double top_margin, double bottom_margin )
+{
+ struct __svg_sheet *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_sheet *)malloc( sizeof( struct __svg_sheet ) );
+ if( new == (struct __svg_sheet *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_sheet ) );
+ new->type = SVG_SHEET;
+ sprintf( buf, "svg%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->width = width;
+ new->height = height;
+ new->left_margin = left_margin;
+ new->right_margin = right_margin;
+ new->top_margin = top_margin;
+ new->bottom_margin = bottom_margin;
+
+ new->defs = create_svgc_dlist();
+ if( !new->defs )
+ {
+ if( new->id ) free( new->id );
+ if( new->style ) __svg_free_style( new->style );;
+ free( new );
+ return( (struct __svg_node *)NULL );
+ }
+
+ return( (struct __svg_node *)new );
+}
+
+int
+__svg_sheet_add_definition( void * sheet, struct __svg_node * definition )
+{
+ struct __svg_sheet *ps = (struct __svg_sheet *)sheet;
+ struct svgc_dlist_node *np = NULL;
+ int error = -1; /* EINVAL */
+
+ if( !ps || !ps->defs || !definition ) return( error );
+ error = 0;
+
+ if( !ps->defs ) return( error );
+
+ np = add_to_svgc_dlist_down( ps->defs, definition->id, (void *)definition );
+ if( np ) error = 1;
+
+ return( error );
+}
+
+
+/* Validate UTF-8 and reject code points forbidden by XML 1.0. */
+static int
+__svg_embedded_text_valid_utf8( const unsigned char *text, size_t length )
+{
+ size_t i = 0;
+ unsigned int cp;
+ unsigned int b;
+ int n, j;
+
+ while( i < length )
+ {
+ b = text[i++];
+ if( b < 0x80 )
+ {
+ cp = b;
+ n = 0;
+ }
+ else if( b >= 0xC2 && b <= 0xDF )
+ {
+ cp = b & 0x1F;
+ n = 1;
+ }
+ else if( b >= 0xE0 && b <= 0xEF )
+ {
+ cp = b & 0x0F;
+ n = 2;
+ }
+ else if( b >= 0xF0 && b <= 0xF4 )
+ {
+ cp = b & 0x07;
+ n = 3;
+ }
+ else return( 0 );
+
+ if( length - i < (size_t)n ) return( 0 );
+ for( j = 0; j < n; ++j )
+ {
+ b = text[i++];
+ if( (b & 0xC0) != 0x80 ) return( 0 );
+ cp = (cp << 6) | (b & 0x3F);
+ }
+
+ if( n == 1 && cp < 0x80 ) return( 0 );
+ if( n == 2 && cp < 0x800 ) return( 0 );
+ if( n == 3 && cp < 0x10000 ) return( 0 );
+ if( cp != 0x09 && cp != 0x0A && cp != 0x0D && cp < 0x20 ) return( 0 );
+ if( cp >= 0xD800 && cp <= 0xDFFF ) return( 0 );
+ if( cp == 0xFFFE || cp == 0xFFFF || cp > 0x10FFFF ) return( 0 );
+ }
+ return( 1 );
+}
+
+
+/* Load CSS or ECMAScript source at registration time. The caller owns
+ only the filename; the resulting definition owns a private copy. */
+static int
+__svg_sheet_add_text_file( struct __svg_sheet *sheet, const char *fname,
+ int type, const char *prefix )
+{
+ FILE *fp;
+ struct __svg_embedded_text *embedded;
+ unsigned char *buffer, *new_buffer;
+ size_t length, capacity, nr;
+ char id[64];
+ int result;
+
+ if( !sheet || sheet->type != SVG_SHEET || !sheet->defs ||
+ !fname || !fname[0] ) return( -1 );
+
+ fp = fopen( fname, "rb" );
+ if( !fp ) return( 0 );
+
+ capacity = 4096;
+ buffer = (unsigned char *)malloc( capacity );
+ if( !buffer )
+ {
+ fclose( fp );
+ return( 0 );
+ }
+
+ length = 0;
+ result = 1;
+ for( ;; )
+ {
+ if( length == capacity - 1 )
+ {
+ if( capacity > ((size_t)-1) / 2 )
+ {
+ result = 0;
+ break;
+ }
+ capacity *= 2;
+ new_buffer = (unsigned char *)realloc( buffer, capacity );
+ if( !new_buffer )
+ {
+ result = 0;
+ break;
+ }
+ buffer = new_buffer;
+ }
+ nr = fread( buffer + length, 1, capacity - length - 1, fp );
+ length += nr;
+ if( ferror( fp ) )
+ {
+ result = 0;
+ break;
+ }
+ if( feof( fp ) ) break;
+ }
+ if( fclose( fp ) != 0 ) result = 0;
+
+ if( !result || !__svg_embedded_text_valid_utf8( buffer, length ) )
+ {
+ free( buffer );
+ return( 0 );
+ }
+ buffer[length] = '\0';
+
+ embedded = (struct __svg_embedded_text *)malloc( sizeof( struct __svg_embedded_text ) );
+ if( !embedded )
+ {
+ free( buffer );
+ return( 0 );
+ }
+ memset( embedded, 0, sizeof( struct __svg_embedded_text ) );
+ embedded->type = type;
+ embedded->content = (char *)buffer;
+ embedded->length = length;
+
+ sprintf( id, "%s%04d", prefix, current_id++ );
+ embedded->id = __svg_str_dup( id );
+ if( !embedded->id )
+ {
+ __svg_free_node( embedded );
+ return( 0 );
+ }
+ if( __svg_sheet_add_definition( sheet, (struct __svg_node *)embedded ) != 1 )
+ {
+ __svg_free_node( embedded );
+ return( 0 );
+ }
+ return( 1 );
+}
+
+
+int
+__svg_sheet_add_css_file( struct __svg_sheet *sheet, const char *fname )
+{
+ return( __svg_sheet_add_text_file( sheet, fname, SVG_CSS, "css" ) );
+}
+
+
+int
+__svg_sheet_add_script_file( struct __svg_sheet *sheet, const char *fname )
+{
+ return( __svg_sheet_add_text_file( sheet, fname, SVG_SCRIPT, "js" ) );
+}
+
+
+struct __svg_node *
+__svg_new_line( double x1, double y1, double x2, double y2 )
+{
+ struct __svg_line *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_line *)malloc( sizeof( struct __svg_line ) );
+ if( new == (struct __svg_line *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_line ) );
+ new->type = SVG_LINE;
+ sprintf( buf, "line%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->x1 = x1;
+ new->y1 = y1;
+ new->x2 = x2;
+ new->y2 = y2;
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_rect( double x, double y, double width, double height, double rx, double ry )
+{
+ struct __svg_rect *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_rect *)malloc( sizeof( struct __svg_rect ) );
+ if( new == (struct __svg_rect *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_rect ) );
+ new->type = SVG_RECT;
+ sprintf( buf, "rect%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ if( rx < 0.0 ) rx = 0.0;
+ if( ry < 0.0 ) ry = 0.0;
+
+ new->x = x;
+ new->y = y;
+ new->width = width;
+ new->height = height;
+ new->rx = rx;
+ new->ry = ry;
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_circle( double cx, double cy, double r )
+{
+ struct __svg_circle *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_circle *)malloc( sizeof( struct __svg_circle ) );
+ if( new == (struct __svg_circle *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_circle ) );
+ new->type = SVG_CIRCLE;
+ sprintf( buf, "circle%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->cx = cx;
+ new->cy = cy;
+ new->r = r;
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_ellipse( double cx, double cy, double rx, double ry )
+{
+ struct __svg_ellipse *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_ellipse *)malloc( sizeof( struct __svg_ellipse ) );
+ if( new == (struct __svg_ellipse *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_ellipse ) );
+ new->type = SVG_ELLIPSE;
+ sprintf( buf, "ellipse%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->cx = cx;
+ new->cy = cy;
+ new->rx = rx;
+ new->ry = ry;
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_polygon( struct __svg_points * ps )
+{
+ struct __svg_polygon *new = NULL;
+ char buf[256];
+
+ if( !ps ) return( (struct __svg_node *)new );
+
+ new = (struct __svg_polygon *)malloc( sizeof( struct __svg_polygon ) );
+ if( new == (struct __svg_polygon *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_polygon ) );
+ new->type = SVG_POLYGON;
+ sprintf( buf, "polygon%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->points = ps;
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_polyline( struct __svg_points * ps )
+{
+ struct __svg_polyline *new = NULL;
+ char buf[256];
+
+ if( !ps ) return( (struct __svg_node *)new );
+
+ new = (struct __svg_polyline *)malloc( sizeof( struct __svg_polyline ) );
+ if( new == (struct __svg_polyline *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_polyline ) );
+ new->type = SVG_POLYLINE;
+ sprintf( buf, "polyline%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->points = ps;
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_path( struct __svg_cmds * cmds )
+{
+ struct __svg_path *new = NULL;
+ char buf[256];
+
+ if( !cmds ) return( (struct __svg_node *)new );
+
+ new = (struct __svg_path *)malloc( sizeof( struct __svg_path ) );
+ if( new == (struct __svg_path *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_path ) );
+ new->type = SVG_PATH;
+ sprintf( buf, "path%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->cmds = cmds;
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_text( double x, double y, const char * text, const char * font_family, int font_size )
+{
+ struct __svg_text *new = NULL;
+ char buf[256];
+
+ if( !text || !text[0] ) return( (struct __svg_node *)new );
+
+ new = (struct __svg_text *)malloc( sizeof( struct __svg_text ) );
+ if( new == (struct __svg_text *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_text ) );
+ new->type = SVG_TEXT;
+ sprintf( buf, "text%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->x = x;
+ new->y = y;
+ new->text = __svg_str_dup( text );
+
+ if( !font_family || !font_family[0] )
+ new->font_family = __svg_str_dup( default_text_font_family );
+ else
+ new->font_family = __svg_str_dup( font_family );
+
+ if( !font_size )
+ new->font_size = default_text_font_size;
+ else
+ new->font_size = font_size;
+
+ new->fill = __svg_str_dup( default_text_fill );
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_image( double x, double y, int width, int height, char * href, char * title )
+{
+ struct __svg_image *new = NULL;
+ char buf[256];
+
+ if( !href || !href[0] ) return( (struct __svg_node *)new );
+
+ new = (struct __svg_image *)malloc( sizeof( struct __svg_image ) );
+ if( new == (struct __svg_image *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_image ) );
+ new->type = SVG_IMAGE;
+ sprintf( buf, "image%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ new->x = x;
+ new->y = y;
+ new->width = width;
+ new->height = height;
+
+ new->href = __svg_str_dup( href );
+
+ if( title )
+ new->title = __svg_str_dup( title );
+ else
+ new->title = __svg_str_dup( "image" );
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_l_gradient( const char * units, const char * spread, double x1, double y1, double x2, double y2 )
+{
+ struct __svg_l_gradient *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_l_gradient *)malloc( sizeof( struct __svg_l_gradient ) );
+ if( new == (struct __svg_l_gradient *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_l_gradient ) );
+ new->type = SVG_L_GRADIENT;
+ sprintf( buf, "lg%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ if( !units || !units[0] ) new->units = __svg_str_dup( "objectBoundingBox" );
+ else new->units = __svg_str_dup( units );
+
+ if( !spread || !spread[0] ) new->spread = __svg_str_dup( "pad" );
+ else new->spread = __svg_str_dup( spread );
+
+ new->x1 = x1;
+ new->y1 = y1;
+ new->x2 = x2;
+ new->y2 = y2;
+
+ new->stops = create_svgc_dlist();
+ if( !new->stops )
+ {
+ if( new->id ) free( new->id );
+ if( new->style ) __svg_free_style( new->style );;
+ if( new->units ) free( new->units );
+ free( new );
+ return( (struct __svg_node *)NULL );
+ }
+
+ return( (struct __svg_node *)new );
+}
+
+struct __svg_node *
+__svg_new_r_gradient( const char * units, const char * spread,
+ double cx, double cy, double r, double fx, double fy )
+{
+ struct __svg_r_gradient *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_r_gradient *)malloc( sizeof( struct __svg_r_gradient ) );
+ if( new == (struct __svg_r_gradient *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_r_gradient ) );
+ new->type = SVG_R_GRADIENT;
+ sprintf( buf, "rg%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ if( !units || !units[0] ) new->units = __svg_str_dup( "objectBoundingBox" );
+ else new->units = __svg_str_dup( units );
+
+ if( !spread || !spread[0] ) new->spread = __svg_str_dup( "pad" );
+ else new->spread = __svg_str_dup( spread );
+
+ new->cx = cx;
+ new->cy = cy;
+ new->r = r;
+ new->fx = fx;
+ new->fy = fy;
+
+ new->stops = create_svgc_dlist();
+ if( !new->stops )
+ {
+ if( new->id ) free( new->id );
+ if( new->style ) __svg_free_style( new->style );;
+ if( new->units ) free( new->units );
+ free( new );
+ return( (struct __svg_node *)NULL );
+ }
+
+ return( (struct __svg_node *)new );
+}
+
+int
+__svg_gradient_add_stop( void * gradient, struct __svg_stop * stop )
+{
+ struct __svg_gradient *pg = (struct __svg_gradient *)gradient;
+ struct svgc_dlist_node *np = NULL;
+ int error = -1; /* EINVAL */
+
+ if( !pg || !pg->stops || !stop ) return( error );
+ error = 0;
+
+ if( !pg->stops ) return( error );
+
+ np = add_to_svgc_dlist_down( pg->stops, stop->id, (void *)stop );
+ if( np ) error = 1;
+
+ return( error );
+}
+
+struct __svg_node *
+__svg_new_stop( double offset )
+{
+ struct __svg_stop *new = NULL;
+ char buf[256];
+
+ new = (struct __svg_stop *)malloc( sizeof( struct __svg_stop ) );
+ if( new == (struct __svg_stop *)NULL ) return( (struct __svg_node *)NULL );
+ memset( (void *)new, 0, sizeof( struct __svg_stop ) );
+ new->type = SVG_STOP;
+ sprintf( buf, "stop%04d", current_id++ );
+ new->id = __svg_str_dup( buf );
+ new->style = __svg_new_style();
+
+ if( !new->id || !new->style ) return( (struct __svg_node *)NULL );
+
+ if( offset > 1.0 || offset < 0.0 ) offset = 0.0;
+ new->offset = offset;
+
+ return( (struct __svg_node *)new );
+}
+
+/***************************************************************
+ Style controls:
+ ***************************************************************/
+int __svg_set_stroke( struct __svg_node * node, const char * stroke )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ node->style->stroke->stroke.r = 0;
+ node->style->stroke->stroke.g = 0;
+ node->style->stroke->stroke.b = 0;
+
+ if( node->style->stroke->use_stroke )
+ free( node->style->stroke->use_stroke );
+ node->style->stroke->use_stroke = __svg_str_dup( stroke );
+ if( node->style->stroke->use_stroke ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_stroke_rgb( struct __svg_node * node, int r, int g, int b )
+{
+ char buf[256];
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ node->style->stroke->stroke.r = r;
+ node->style->stroke->stroke.g = g;
+ node->style->stroke->stroke.b = b;
+
+ sprintf( buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ if( node->style->stroke->use_stroke )
+ free( node->style->stroke->use_stroke );
+ node->style->stroke->use_stroke = __svg_str_dup( buf );
+ if( node->style->stroke->use_stroke ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_stroke_width( struct __svg_node * node, double width )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ node->style->stroke->stroke_width = width;
+ return( error );
+}
+
+int __svg_set_stroke_linecap( struct __svg_node * node, const char * linecap )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ if( node->style->stroke->stroke_linecap )
+ free( node->style->stroke->stroke_linecap );
+ node->style->stroke->stroke_linecap = __svg_str_dup( linecap );
+ if( node->style->stroke->stroke_linecap ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_stroke_linejoin( struct __svg_node * node, const char * linejoin )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ if( node->style->stroke->stroke_linejoin )
+ free( node->style->stroke->stroke_linejoin );
+ node->style->stroke->stroke_linejoin = __svg_str_dup( linejoin );
+ if( node->style->stroke->stroke_linejoin ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_stroke_dasharray( struct __svg_node * node, const char * dasharray )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ if( node->style->stroke->stroke_dasharray )
+ free( node->style->stroke->stroke_dasharray );
+ node->style->stroke->stroke_dasharray = __svg_str_dup( dasharray );
+ if( node->style->stroke->stroke_dasharray ) error = 1;
+
+ return( error );
+}
+
+
+int __svg_set_fill( struct __svg_node * node, const char * fill )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ node->style->fill->fill.r = 0;
+ node->style->fill->fill.g = 0;
+ node->style->fill->fill.b = 0;
+
+ if( node->style->fill->use_fill )
+ free( node->style->fill->use_fill );
+ node->style->fill->use_fill = __svg_str_dup( fill );
+ if( node->style->fill->use_fill ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_fill_rgb( struct __svg_node * node, int r, int g, int b )
+{
+ char buf[256];
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ node->style->fill->fill.r = r;
+ node->style->fill->fill.g = g;
+ node->style->fill->fill.b = b;
+
+ sprintf( buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ if( node->style->fill->use_fill )
+ free( node->style->fill->use_fill );
+ node->style->fill->use_fill = __svg_str_dup( buf );
+ if( node->style->fill->use_fill ) error = 1;
+
+ return( error );
+}
+
+
+int __svg_set_stop_color( struct __svg_node * node, const char * stop_color )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ node->style->stop_color->stop_color.r = 0;
+ node->style->stop_color->stop_color.g = 0;
+ node->style->stop_color->stop_color.b = 0;
+
+ if( node->style->stop_color->use_stop_color )
+ free( node->style->stop_color->use_stop_color );
+ node->style->stop_color->use_stop_color = __svg_str_dup( stop_color );
+ if( node->style->stop_color->use_stop_color ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_stop_color_rgb( struct __svg_node * node, int r, int g, int b )
+{
+ char buf[256];
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ node->style->stop_color->stop_color.r = r;
+ node->style->stop_color->stop_color.g = g;
+ node->style->stop_color->stop_color.b = b;
+
+ sprintf( buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ if( node->style->stop_color->use_stop_color )
+ free( node->style->stop_color->use_stop_color );
+ node->style->stop_color->use_stop_color = __svg_str_dup( buf );
+ if( node->style->stop_color->use_stop_color ) error = 1;
+
+ return( error );
+}
+
+
+int __svg_set_stop_opacity( struct __svg_node * node, double stop_opacity )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ if( stop_opacity > 1.0 ||
+ stop_opacity < 0.0 ) stop_opacity = default_stop_opacity;
+ node->style->stop_opacity->stop_opacity = stop_opacity;
+
+ return( error );
+}
+
+
+int __svg_set_text( struct __svg_node * node, const char * text )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node || !text || !text[0] ) return( error );
+ error = 0;
+
+ if( ((__svg_text *)node)->text )
+ free( ((__svg_text *)node)->text );
+ ((__svg_text *)node)->text = __svg_str_dup( text );
+ if( !((__svg_text *)node)->text ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_text_fill( struct __svg_node * node, const char * fill )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node || !fill || !fill[0] ) return( error );
+ error = 0;
+
+ if( ((__svg_text *)node)->fill )
+ free( ((__svg_text *)node)->fill );
+ ((__svg_text *)node)->fill = __svg_str_dup( fill );
+ if( !((__svg_text *)node)->fill ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_text_fill_rgb( struct __svg_node * node, int r, int g, int b )
+{
+ char buf[256];
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ sprintf( buf, "rgb(%03d,%03d,%03d)", r, g, b );
+
+ if( ((__svg_text *)node)->fill )
+ free( ((__svg_text *)node)->fill );
+ ((__svg_text *)node)->fill = __svg_str_dup( buf );
+ if( !((__svg_text *)node)->fill ) error = 1;
+
+ return( error );
+}
+
+int __svg_set_text_font_family( struct __svg_node * node, const char * family )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node || !family || !family[0] ) return( error );
+ error = 0;
+
+ if( ((__svg_text *)node)->font_family )
+ free( ((__svg_text *)node)->font_family );
+ ((__svg_text *)node)->font_family = __svg_str_dup( family );
+ if( !((__svg_text *)node)->font_family ) error = 1;
+
+ return( error );
+}
+
+
+int __svg_set_text_font_size( struct __svg_node * node, int size )
+{
+ int error = -1; /* EINVAL */
+
+ if( !node ) return( error );
+ error = 0;
+
+ ((__svg_text *)node)->font_size = size;
+ error = 1;
+
+ return( error );
+}
+
+
+
+void __svg_free_scene( struct __svg_scene * scene )
+{
+ if( !scene ) return;
+ if( scene->plist )
+ {
+ /* clear svgc_dlist */
+ free_svgc_dlist( scene->plist, __svg_free_node );
+ }
+
+ free( scene );
+}
+
+
+struct __svg_scene *
+__svg_new_scene( struct __svg_sheet * sheet )
+{
+ struct __svg_scene *new = (struct __svg_scene *)NULL;
+
+ new = (struct __svg_scene *)malloc( sizeof(struct __svg_scene) );
+ if( new == (struct __svg_scene *)NULL ) return( (struct __svg_scene *)NULL );
+ memset( (void *)new, 0, sizeof(struct __svg_scene) );
+
+ new->plist = create_svgc_dlist();
+ if( !new->plist )
+ {
+ free( new );
+ return( (struct __svg_scene *)NULL );
+ }
+
+ add_to_svgc_dlist_down( new->plist, sheet->id, (void *)sheet );
+
+ return( (struct __svg_scene *)new );
+}
+
+int
+__svg_scene_add_node( struct __svg_scene * scene, struct __svg_node * node )
+{
+ struct svgc_dlist_node *np = NULL;
+ int error = -1; /* EINVAL */
+
+ if( !scene || !scene->plist || !node ) return( error );
+ error = 0;
+
+ if( !scene->plist ) return( error );
+
+ np = add_to_svgc_dlist_down( scene->plist, node->id, (void *)node );
+ if( np ) error = 1;
+
+ return( error );
+}
+
+
+/* Get node ID: */
+const char *
+__svg_get_node_id( struct __svg_node * node )
+{
+ const char *error = (const char *)NULL;
+
+ if( !node->id || !node->id[0] ) return( error );
+
+ return( (const char *)node->id );
+}
+
+/* Create node URL: */
+char *
+__svg_create_node_url( struct __svg_node * node )
+{
+ int len;
+ char *url = (char *)NULL;
+
+ if( !node->id || !node->id[0] ) return( url );
+
+ len = strlen( node->id ) + 7;
+ url = (char *)malloc( len );
+ if( !url ) return( url );
+
+ sprintf( url, "url(#%s)", node->id );
+
+ return( url );
+}
+
+
+/***************************************************************
+ OUTPUT:
+ ***************************************************************/
+int output_group = 0;
+char *output_file_name;
+FILE *output_file;
+
+void
+__svg_paint_point( void * data )
+{
+ struct __svg_point *p = (struct __svg_point *)data;
+
+ if( !p ) return;
+
+ fprintf( output_file, " %0.3f,%0.3f", p->x, p->y );
+}
+
+void
+__svg_paint_point_x( void * data )
+{
+ struct __svg_point *p = (struct __svg_point *)data;
+
+ if( !p ) return;
+
+ fprintf( output_file, " %0.3f", p->x );
+}
+
+void
+__svg_paint_point_y( void * data )
+{
+ struct __svg_point *p = (struct __svg_point *)data;
+
+ if( !p ) return;
+
+ fprintf( output_file, " %0.3f", p->y );
+}
+
+void
+__svg_paint_point_bool( void * data )
+{
+ struct __svg_point *p = (struct __svg_point *)data;
+
+ if( !p ) return;
+
+ if( p->x < 0.5 ) fprintf( output_file, " 0," );
+ else fprintf( output_file, " 1," );
+ if( p->y < 0.5 ) fprintf( output_file, "0" );
+ else fprintf( output_file, "1" );
+}
+
+
+
+void
+__svg_paint_cmd( void * data )
+{
+ struct __svg_cmd *cmd = (struct __svg_cmd *)data;
+
+ if( !cmd ) return;
+ switch( cmd->cmd )
+ {
+ case 'M':
+ case 'm':
+ fprintf( output_file, "%c", cmd->cmd );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ break;
+
+ case 'L':
+ case 'l':
+ fprintf( output_file, " %c", cmd->cmd );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ break;
+
+ case 'H':
+ case 'h':
+ fprintf( output_file, "%c", cmd->cmd );
+ __svg_paint_point_x( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ break;
+
+ case 'V':
+ case 'v':
+ fprintf( output_file, "%c", cmd->cmd );
+ __svg_paint_point_y( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ break;
+
+ case 'C':
+ case 'c':
+ fprintf( output_file, " %c", cmd->cmd );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "2" )->data );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "3" )->data );
+ break;
+
+ case 'S':
+ case 's':
+ fprintf( output_file, " %c", cmd->cmd );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "2" )->data );
+ break;
+
+ case 'Q':
+ case 'q':
+ fprintf( output_file, " %c", cmd->cmd );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "2" )->data );
+ break;
+
+ case 'T':
+ case 't':
+ fprintf( output_file, " %c", cmd->cmd );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ break;
+
+ case 'A':
+ case 'a':
+ fprintf( output_file, " %c", cmd->cmd );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "1" )->data );
+ __svg_paint_point_x( lookup_svgc_dlist_node_down( cmd->points->plist, "2" )->data );
+ __svg_paint_point_bool( lookup_svgc_dlist_node_down( cmd->points->plist, "3" )->data );
+ __svg_paint_point( lookup_svgc_dlist_node_down( cmd->points->plist, "4" )->data );
+ break;
+
+ case 'Z':
+ case 'z':
+ fprintf( output_file, " %c", cmd->cmd );
+ break;
+ default:
+ break;
+ }
+}
+
+
+void
+__svg_paint_stop( void * data )
+{
+ struct __svg_node *node = (struct __svg_node *)data;
+
+ if( !node ) return;
+
+
+ fprintf( output_file,
+" <stop id=\"%s\" offset=\"%0.3f\" style=\"stop-color:%s;stop-opacity:%0.3f;\" />\n",
+ node->id,
+ ((struct __svg_stop *)node)->offset,
+ node->style->stop_color->use_stop_color,
+ node->style->stop_opacity->stop_opacity );
+}
+
+
+void
+__svg_paint_l_gradient( void * data )
+{
+ struct __svg_node *node = (struct __svg_node *)data;
+
+ if( !node ) return;
+
+ fprintf( output_file,
+" <linearGradient\n"
+" id=\"%s\" gradientUnits=\"%s\" spreadMethod=\"%s\"\n"
+" x1=\"%0.3f\"\n"
+" y1=\"%0.3f\"\n"
+" x2=\"%0.3f\"\n"
+" y2=\"%0.3f\">\n",
+ node->id,
+ ((struct __svg_l_gradient *)node)->units,
+ ((struct __svg_l_gradient *)node)->spread,
+ ((struct __svg_l_gradient *)node)->x1,
+ ((struct __svg_l_gradient *)node)->y1,
+ ((struct __svg_l_gradient *)node)->x2,
+ ((struct __svg_l_gradient *)node)->y2 );
+
+ if( ((struct __svg_l_gradient *)node)->stops )
+ {
+ /* paint svgc_dlist */
+ for_each_svgc_dlist_node_data(
+ ((struct __svg_l_gradient *)node)->stops, __svg_paint_stop );
+ }
+
+ fprintf( output_file,
+" </linearGradient>\n" );
+}
+
+void
+__svg_paint_r_gradient( void * data )
+{
+ struct __svg_node *node = (struct __svg_node *)data;
+
+ if( !node ) return;
+
+ fprintf( output_file,
+" <radialGradient\n"
+" id=\"%s\" gradientUnits=\"%s\" spreadMethod=\"%s\"\n"
+" cx=\"%0.3f\"\n"
+" cy=\"%0.3f\"\n"
+" r=\"%0.3f\"\n"
+" fx=\"%0.3f\"\n"
+" fy=\"%0.3f\">\n",
+ node->id,
+ ((struct __svg_r_gradient *)node)->units,
+ ((struct __svg_r_gradient *)node)->spread,
+ ((struct __svg_r_gradient *)node)->cx,
+ ((struct __svg_r_gradient *)node)->cy,
+ ((struct __svg_r_gradient *)node)->r,
+ ((struct __svg_r_gradient *)node)->fx,
+ ((struct __svg_r_gradient *)node)->fy );
+
+ if( ((struct __svg_r_gradient *)node)->stops )
+ {
+ /* paint svgc_dlist */
+ for_each_svgc_dlist_node_data(
+ ((struct __svg_r_gradient *)node)->stops, __svg_paint_stop );
+ }
+
+ fprintf( output_file,
+" </radialGradient>\n" );
+}
+
+
+/* CDATA terminators are split while retaining the source characters. */
+static void
+__svg_paint_embedded_text( struct __svg_embedded_text *embedded )
+{
+ const char *begin, *point;
+ const char *tag;
+ const char *media_type;
+
+ tag = embedded->type == SVG_CSS ? "style" : "script";
+ media_type = embedded->type == SVG_CSS ? "text/css" : "text/javascript";
+ fprintf( output_file, " <%s type=\"%s\">\n", tag, media_type );
+ fprintf( output_file, " <![CDATA[\n" );
+ begin = embedded->content;
+ while( (point = strstr( begin, "]]>") ) != NULL )
+ {
+ (void)fwrite( begin, 1, (size_t)(point - begin), output_file );
+ fprintf( output_file, "]]]]><![CDATA[>" );
+ begin = point + 3;
+ }
+ (void)fwrite( begin, 1, embedded->length - (size_t)(begin - embedded->content), output_file );
+ if( embedded->length && embedded->content[embedded->length - 1] != '\n' )
+ fputc( '\n', output_file );
+ fprintf( output_file, " ]]>\n" );
+ fprintf( output_file, " </%s>\n", tag );
+}
+
+
+void
+__svg_paint_defs( void * data )
+{
+ struct __svg_node *node = (struct __svg_node *)data;
+
+ if( !node ) return;
+
+ switch( node->type )
+ {
+ default:
+ fprintf( output_file, "<node type=\"unknown\" />\n" );
+ break;
+
+ case SVG_L_GRADIENT:
+ __svg_paint_l_gradient( data );
+ break;
+
+ case SVG_R_GRADIENT:
+ __svg_paint_r_gradient( data );
+ break;
+
+ case SVG_CSS:
+ case SVG_SCRIPT:
+ __svg_paint_embedded_text( (struct __svg_embedded_text *)data );
+ break;
+ }
+}
+
+
+void
+__svg_paint_node( void * data )
+{
+ struct __svg_node *node = (struct __svg_node *)data;
+ char *group;
+
+ if( !node ) return;
+
+ switch( node->type )
+ {
+ default:
+ fprintf( output_file, "<node type=\"unknown\" />\n" );
+ break;
+
+ case SVG_SHEET :
+ if( output_group ) group = " <g id=\"layer0\">\n";
+ else group = "";
+ fprintf( output_file,
+"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
+" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
+"<svg\n"
+" xmlns:svg=\"http://www.w3.org/2000/svg\"\n"
+" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
+" xmlns=\"http://www.w3.org/2000/svg\"\n"
+" version=\"1.1\"\n"
+" width=\"%d\"\n"
+" height=\"%d\">\n"
+" <defs>\n"
+" <sheet id=\"%s\"\n"
+" left_margin=\"%d\"\n"
+" right_margin=\"%d\"\n"
+" top_margin=\"%d\"\n"
+" bottom_margin=\"%d\" />\n",
+ (int)((struct __svg_sheet *)node)->width,
+ (int)((struct __svg_sheet *)node)->height,
+ node->id,
+ (int)((struct __svg_sheet *)node)->left_margin,
+ (int)((struct __svg_sheet *)node)->right_margin,
+ (int)((struct __svg_sheet *)node)->top_margin,
+ (int)((struct __svg_sheet *)node)->bottom_margin );
+
+ if( ((struct __svg_sheet *)node)->defs )
+ {
+ /* paint svgc_dlist */
+ for_each_svgc_dlist_node_data(
+ ((struct __svg_sheet *)node)->defs, __svg_paint_defs );
+ }
+
+ fprintf( output_file,
+" </defs>\n%s",
+ group );
+ break;
+
+ case SVG_LINE :
+ fprintf( output_file,
+" <line\n"
+" id=\"%s\"\n"
+" x1=\"%0.3f\"\n"
+" y1=\"%0.3f\"\n"
+" x2=\"%0.3f\"\n"
+" y2=\"%0.3f\"\n"
+" style=\"stroke:%s;stroke-width:%0.3f;stroke-linecap:%s;stroke-linejoin:%s;stroke-dasharray:%s;\" />\n",
+ node->id,
+ ((struct __svg_line *)node)->x1,
+ ((struct __svg_line *)node)->y1,
+ ((struct __svg_line *)node)->x2,
+ ((struct __svg_line *)node)->y2,
+ node->style->stroke->use_stroke,
+ node->style->stroke->stroke_width,
+ node->style->stroke->stroke_linecap,
+ node->style->stroke->stroke_linejoin,
+ node->style->stroke->stroke_dasharray );
+ break;
+
+ break;
+ case SVG_RECT :
+ fprintf( output_file,
+" <rect\n"
+" id=\"%s\"\n"
+" x=\"%0.3f\"\n"
+" y=\"%0.3f\"\n"
+" width=\"%0.3f\"\n"
+" height=\"%0.3f\"\n"
+" rx=\"%0.3f\"\n"
+" ry=\"%0.3f\"\n"
+" style=\"fill:%s;stroke:%s;stroke-width:%0.3f;stroke-linecap:%s;stroke-linejoin:%s;stroke-dasharray:%s;\" />\n",
+ node->id,
+ ((struct __svg_rect *)node)->x,
+ ((struct __svg_rect *)node)->y,
+ ((struct __svg_rect *)node)->width,
+ ((struct __svg_rect *)node)->height,
+ ((struct __svg_rect *)node)->rx,
+ ((struct __svg_rect *)node)->ry,
+ node->style->fill->use_fill,
+ node->style->stroke->use_stroke,
+ node->style->stroke->stroke_width,
+ node->style->stroke->stroke_linecap,
+ node->style->stroke->stroke_linejoin,
+ node->style->stroke->stroke_dasharray );
+ break;
+ break;
+
+ case SVG_CIRCLE :
+ fprintf( output_file,
+" <circle\n"
+" id=\"%s\"\n"
+" cx=\"%0.3f\"\n"
+" cy=\"%0.3f\"\n"
+" r=\"%0.3f\"\n"
+" style=\"fill:%s;stroke:%s;stroke-width:%0.3f;stroke-linecap:%s;stroke-linejoin:%s;stroke-dasharray:%s;\" />\n",
+ node->id,
+ ((struct __svg_circle *)node)->cx,
+ ((struct __svg_circle *)node)->cy,
+ ((struct __svg_circle *)node)->r,
+ node->style->fill->use_fill,
+ node->style->stroke->use_stroke,
+ node->style->stroke->stroke_width,
+ node->style->stroke->stroke_linecap,
+ node->style->stroke->stroke_linejoin,
+ node->style->stroke->stroke_dasharray );
+ break;
+
+ case SVG_ELLIPSE :
+ fprintf( output_file,
+" <ellipse\n"
+" id=\"%s\"\n"
+" cx=\"%0.3f\"\n"
+" cy=\"%0.3f\"\n"
+" rx=\"%0.3f\"\n"
+" ry=\"%0.3f\"\n"
+" style=\"fill:%s;stroke:%s;stroke-width:%0.3f;stroke-linecap:%s;stroke-linejoin:%s;stroke-dasharray:%s;\" />\n",
+ node->id,
+ ((struct __svg_ellipse *)node)->cx,
+ ((struct __svg_ellipse *)node)->cy,
+ ((struct __svg_ellipse *)node)->rx,
+ ((struct __svg_ellipse *)node)->ry,
+ node->style->fill->use_fill,
+ node->style->stroke->use_stroke,
+ node->style->stroke->stroke_width,
+ node->style->stroke->stroke_linecap,
+ node->style->stroke->stroke_linejoin,
+ node->style->stroke->stroke_dasharray );
+ break;
+
+ case SVG_POLYGON :
+ fprintf( output_file,
+" <polygon\n"
+" id=\"%s\"\n"
+" points=\"",
+ node->id );
+ /* print points */
+ for_each_svgc_dlist_node_data( ((struct __svg_polygon *)node)->points->plist, __svg_paint_point );
+ fprintf( output_file,
+"\"\n"
+" style=\"fill:%s;stroke:%s;stroke-width:%0.3f;stroke-linecap:%s;stroke-linejoin:%s;stroke-dasharray:%s;\" />\n",
+ node->style->fill->use_fill,
+ node->style->stroke->use_stroke,
+ node->style->stroke->stroke_width,
+ node->style->stroke->stroke_linecap,
+ node->style->stroke->stroke_linejoin,
+ node->style->stroke->stroke_dasharray );
+ break;
+
+ case SVG_POLYLINE :
+ fprintf( output_file,
+" <polyline\n"
+" id=\"%s\"\n"
+" points=\"",
+ node->id );
+ /* print points */
+ for_each_svgc_dlist_node_data( ((struct __svg_polygon *)node)->points->plist, __svg_paint_point );
+ fprintf( output_file,
+"\"\n"
+" style=\"fill:%s;stroke:%s;stroke-width:%0.3f;stroke-linecap:%s;stroke-linejoin:%s;stroke-dasharray:%s;\" />\n",
+ node->style->fill->use_fill,
+ node->style->stroke->use_stroke,
+ node->style->stroke->stroke_width,
+ node->style->stroke->stroke_linecap,
+ node->style->stroke->stroke_linejoin,
+ node->style->stroke->stroke_dasharray );
+ break;
+
+ case SVG_PATH :
+ fprintf( output_file,
+" <path\n"
+" id=\"%s\"\n"
+" d=\"",
+ node->id );
+ /* print points */
+ for_each_svgc_dlist_node_data( ((struct __svg_path *)node)->cmds->plist, __svg_paint_cmd );
+ fprintf( output_file,
+"\"\n"
+" style=\"fill:%s;stroke:%s;stroke-width:%0.3f;stroke-linecap:%s;stroke-linejoin:%s;stroke-dasharray:%s;\" />\n",
+ node->style->fill->use_fill,
+ node->style->stroke->use_stroke,
+ node->style->stroke->stroke_width,
+ node->style->stroke->stroke_linecap,
+ node->style->stroke->stroke_linejoin,
+ node->style->stroke->stroke_dasharray );
+ break;
+
+ case SVG_TEXT :
+ fprintf( output_file,
+" <text\n"
+" id=\"%s\"\n"
+" x=\"%0.3f\"\n"
+" y=\"%0.3f\"\n"
+" font-family=\"%s\"\n"
+" font-size=\"%d\"\n"
+" fill=\"%s\" >\n"
+" %s\n"
+" </text>\n",
+ node->id,
+ ((struct __svg_text *)node)->x,
+ ((struct __svg_text *)node)->y,
+ ((struct __svg_text *)node)->font_family,
+ ((struct __svg_text *)node)->font_size,
+ ((struct __svg_text *)node)->fill,
+ ((struct __svg_text *)node)->text );
+ break;
+
+ case SVG_IMAGE :
+ fprintf( output_file,
+" <image\n"
+" id=\"%s\"\n"
+" x=\"%0.3f\"\n"
+" y=\"%0.3f\"\n"
+" width=\"%dpx\"\n"
+" height=\"%dpx\"\n"
+" xlink:href=\"%s\">\n",
+ node->id,
+ ((struct __svg_image *)node)->x,
+ ((struct __svg_image *)node)->y,
+ ((struct __svg_image *)node)->width,
+ ((struct __svg_image *)node)->height,
+ ((struct __svg_image *)node)->href );
+ fprintf( output_file,
+" <title>%s</title>\n",
+ ((struct __svg_image *)node)->title );
+ fprintf( output_file,
+" </image>\n" );
+ break;
+ }
+}
+
+
+void __svg_paint_scene( struct __svg_scene * scene, int group, char * fname )
+{
+ int save_group = output_group;
+
+ if( !scene ) return;
+
+ if( group ) output_group = 1;
+ else output_group = 0;
+
+ if( !fname || !fname[0] )
+ {
+ output_file_name = "stdout";
+ output_file = stdout;
+ }
+ else
+ {
+ output_file_name = fname;
+ /* open file output_file */
+ if( (output_file = fopen( output_file_name, "w+" )) == NULL )
+ {
+ fprintf( stderr, "ERROR: Cannot open file: %s\n", output_file_name );
+ output_group = save_group;
+ exit( 1 );
+ }
+ }
+
+ if( scene->plist )
+ {
+ /* paint svgc_dlist */
+ for_each_svgc_dlist_node_data( scene->plist, __svg_paint_node );
+ }
+
+ if( output_group )
+ fprintf( output_file, " </g>\n" );
+ fprintf( output_file, "</svg>\n" );
+
+ output_group = save_group;
+
+ fclose( output_file );
+}
+
diff --git a/src/svgc.h b/src/svgc.h
new file mode 100644
index 0000000..aea6616
--- /dev/null
+++ b/src/svgc.h
@@ -0,0 +1,620 @@
+
+/***************************************************************
+ SVGC.H
+
+ This file containt declarations of SVG C lib functions.
+ ***************************************************************/
+
+#ifndef __SVGC_H__
+#define __SVGC_H__
+
+#if defined( __cplusplus )
+extern "C"
+{
+#endif
+
+#include <svgc-dlist.h>
+
+typedef struct __svg_point __svg_point;
+struct __svg_point
+{
+ double x, y;
+};
+
+typedef struct __svg_points __svg_points;
+struct __svg_points
+{
+ int count;
+ struct svgc_dlist *plist;
+};
+
+extern void __svg_free_point( void *data );
+extern void __svg_free_points( struct __svg_points *p );
+extern struct __svg_points *__svg_new_points( void );
+extern int __svg_add_point( struct __svg_points *ps, double x, double y );
+
+
+/***************************************************************
+ PATH CMDS:
+ ***************************************************************/
+
+typedef struct __svg_cmd __svg_cmd;
+struct __svg_cmd
+{
+ char cmd;
+ struct __svg_points *points;
+};
+
+typedef struct __svg_cmds __svg_cmds;
+struct __svg_cmds
+{
+ int count;
+ struct svgc_dlist *plist;
+};
+
+extern void __svg_free_cmd( void *data );
+extern void __svg_free_cmds( struct __svg_cmds *cmds );
+extern struct __svg_cmd *__svg_new_cmd( char cmd, struct __svg_points *ps );
+extern struct __svg_cmds *__svg_new_cmds( void );
+extern int __svg_add_cmd( struct __svg_cmds *cmds, struct __svg_cmd *cmd );
+
+#define ABSOLUTE 1
+#define RELATIVE 0
+extern int
+__svg_add_moveto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double x,
+ double y );
+
+extern int
+__svg_add_lineto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double x,
+ double y );
+
+extern int
+__svg_add_hlineto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double x );
+
+extern int
+__svg_add_vlineto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double y );
+
+extern int
+__svg_add_curveto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double x1,
+ double y1,
+ double x2,
+ double y2,
+ double x,
+ double y );
+extern int
+__svg_add_short_curveto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double x2,
+ double y2,
+ double x,
+ double y );
+extern int
+__svg_add_quadro_curveto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double x1,
+ double y1,
+ double x,
+ double y );
+extern int
+__svg_add_short_quadro_curveto_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double x,
+ double y );
+
+extern int
+__svg_add_arc_cmd( struct __svg_cmds *cmds,
+ int abs,
+ double rx,
+ double ry,
+ double x_axis_rotation,
+ int large_arc_flag,
+ int sweep_flag,
+ double x,
+ double y );
+
+extern int
+__svg_add_closepath_cmd( struct __svg_cmds *cmds,
+ int abs );
+
+
+
+/***************************************************************
+ STYLE:
+ ***************************************************************/
+typedef struct __svg_rgb __svg_rgb;
+struct __svg_rgb
+{
+ int r, g, b;
+};
+
+
+#define STROKE_DEFAULT "black"
+
+#define LINECAP_BUTT "butt"
+#define LINECAP_ROUND "round"
+#define LINECAP_SQUARE "square"
+
+#define LINECAP_DEFAULT "round"
+
+
+#define LINEJOIN_MITER "miter"
+#define LINEJOIN_ROUND "round"
+#define LINEJOIN_BEVEL "bevel"
+
+#define LINEJOIN_DEFAULT "round"
+
+
+#define DASHARRAY_DEFAULT "none"
+
+typedef struct __svg_stroke __svg_stroke;
+struct __svg_stroke
+{
+ struct __svg_rgb stroke;
+ char *use_stroke;
+
+ double stroke_width;
+
+ char *stroke_linecap;
+ char *stroke_linejoin;
+ char *stroke_dasharray;
+};
+
+
+#define FILL_DEFAULT "none"
+
+typedef struct __svg_fill __svg_fill;
+struct __svg_fill
+{
+ struct __svg_rgb fill;
+ char *use_fill;
+};
+
+
+#define STOP_COLOR_DEFAULT "black"
+
+typedef struct __svg_stop_color __svg_stop_color;
+struct __svg_stop_color
+{
+ struct __svg_rgb stop_color;
+ char *use_stop_color;
+};
+
+
+#define STOP_OPACITY_DEFAULT 1.0
+
+typedef struct __svg_stop_opacity __svg_stop_opacity;
+struct __svg_stop_opacity
+{
+ double stop_opacity;
+};
+
+
+typedef struct __svg_style __svg_style;
+struct __svg_style
+{
+ struct __svg_stroke *stroke;
+ struct __svg_fill *fill;
+ struct __svg_stop_color *stop_color;
+ struct __svg_stop_opacity *stop_opacity;
+};
+
+
+#define TEXT_FILL_DEFAULT "black"
+#define TEXT_FONT_FAMILY_DEFAULT "Verdana"
+#define TEXT_FONT_SIZE_DEFAULT 12
+
+
+extern char *__svg_str_dup( const char *s );
+
+extern struct __svg_stroke *__svg_new_stroke( void );
+extern void __svg_free_stroke( struct __svg_stroke *s );
+extern struct __svg_fill *__svg_new_fill( void );
+extern void __svg_free_fill( struct __svg_fill *f );
+extern struct __svg_stop_color *__svg_new_stop_color( void );
+extern void __svg_free_stop_color( struct __svg_stop_color *sc );
+extern struct __svg_stop_opacity *__svg_new_stop_opacity( void );
+extern void __svg_free_stop_opacity( struct __svg_stop_opacity *so );
+
+extern struct __svg_style *__svg_new_style( void );
+extern void __svg_free_style( struct __svg_style *style );
+
+
+
+
+/* NODE: */
+
+#define SVG_SHEET 1
+#define SVG_LINE 2
+#define SVG_RECT 3
+#define SVG_CIRCLE 4
+#define SVG_ELLIPSE 5
+#define SVG_POLYGON 6
+#define SVG_POLYLINE 7
+#define SVG_PATH 8
+#define SVG_TEXT 9
+#define SVG_IMAGE 10
+#define SVG_L_GRADIENT 11
+#define SVG_R_GRADIENT 12
+#define SVG_CSS 13
+#define SVG_STOP 14
+#define SVG_SCRIPT 15
+
+typedef struct __svg_node __svg_node;
+struct __svg_node
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+};
+
+/* The MAIN svg nide is SHEET: */
+typedef struct __svg_sheet __svg_sheet;
+struct __svg_sheet
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ struct svgc_dlist *defs;
+
+ double width, height;
+
+ double left_margin;
+ double right_margin;
+ double top_margin;
+ double bottom_margin;
+};
+
+
+/***************************************************************
+ SVG primitives:
+ ***************************************************************/
+typedef struct __svg_line __svg_line;
+struct __svg_line
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ double x1, y1;
+ double x2, y2;
+};
+
+typedef struct __svg_rect __svg_rect;
+struct __svg_rect
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ double x, y;
+ double width, height;
+ double rx, ry;
+};
+
+typedef struct __svg_circle __svg_circle;
+struct __svg_circle
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ double cx, cy, r;
+};
+
+typedef struct __svg_ellipse __svg_ellipse;
+struct __svg_ellipse
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ double cx, cy, rx, ry;
+};
+
+typedef struct __svg_polygon __svg_polygon;
+struct __svg_polygon
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ struct __svg_points *points;
+};
+
+typedef struct __svg_polyline __svg_polyline;
+struct __svg_polyline
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ struct __svg_points *points;
+};
+
+typedef struct __svg_path __svg_path;
+struct __svg_path
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ struct __svg_cmds *cmds;
+};
+
+typedef struct __svg_text __svg_text;
+struct __svg_text
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ double x, y;
+ char *text;
+
+ int font_size;
+ char *font_family;
+ char *fill;
+};
+
+typedef struct __svg_image __svg_image;
+struct __svg_image
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ double x, y;
+ int width, height;
+ char *href;
+ char *title;
+};
+
+/* NOTE: this is common gradient struct */
+typedef struct __svg_gradient __svg_gradient;
+struct __svg_gradient
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ struct svgc_dlist *stops;
+};
+
+/* NOTE: gradients are added into sheet list as defs */
+typedef struct __svg_l_gradient __svg_l_gradient;
+struct __svg_l_gradient
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ struct svgc_dlist *stops;
+
+ char *units;
+ char *spread;
+
+ double x1, y1;
+ double x2, y2;
+};
+
+typedef struct __svg_r_gradient __svg_r_gradient;
+struct __svg_r_gradient
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ struct svgc_dlist *stops;
+
+ char *units;
+ char *spread;
+
+ double cx, cy;
+ double r;
+ double fx, fy;
+};
+
+/* NOTE: only for gradients */
+typedef struct __svg_stop __svg_stop;
+struct __svg_stop
+{
+ int type;
+ char *id;
+ struct __svg_style *style;
+
+ double offset;
+};
+
+
+/***************************************************************
+ SCENE is the list of SVG primitives.
+ ***************************************************************/
+typedef struct __svg_scene __svg_scene;
+struct __svg_scene
+{
+ struct svgc_dlist *plist;
+};
+
+extern void __svg_free_scene( struct __svg_scene *scene );
+extern struct __svg_scene *__svg_new_scene( struct __svg_sheet *sheet );
+
+/***************************************************************
+ FREE and ADD SVG primitives.
+ ***************************************************************/
+extern void __svg_free_node( void *data );
+
+/* SVG sheet should be created before SCENE */
+extern struct __svg_node *__svg_new_sheet( double width,
+ double height,
+ double left_margin,
+ double right_margin,
+ double top_margin,
+ double bottom_margin );
+
+extern int __svg_sheet_add_definition( void *sheet,
+ struct __svg_node *definition );
+
+/* Insert the contents of a UTF-8 CSS file into sheet <defs>.
+ Return 1 on success, 0 on read/allocation/encoding failure, -1 on
+ invalid arguments. Relative url(...) references are resolved by the
+ SVG viewer against the generated SVG file, not against fname. */
+extern int __svg_sheet_add_css_file( struct __svg_sheet *sheet,
+ const char *fname );
+
+/* Insert the contents of a UTF-8 JavaScript file into sheet <defs>.
+ The caller supplies JavaScript source, without XML, script tags or CDATA.
+ Return values and ownership follow __svg_sheet_add_css_file().
+ Script execution depends on the viewer; SVG used as <img> is inert. */
+extern int __svg_sheet_add_script_file( struct __svg_sheet *sheet,
+ const char *fname );
+
+/***************************************************************
+ Creation of SVG primirives:
+ ***************************************************************/
+extern struct __svg_node *__svg_new_line( double x1,
+ double y1,
+ double x2,
+ double y2 );
+
+extern struct __svg_node *__svg_new_rect( double x,
+ double y,
+ double width,
+ double height,
+ double rx,
+ double ry );
+
+extern struct __svg_node *__svg_new_circle( double cx,
+ double cy,
+ double r );
+
+extern struct __svg_node *__svg_new_ellipse( double cx,
+ double cy,
+ double rx,
+ double ry );
+
+extern struct __svg_node *__svg_new_polygon ( struct __svg_points *ps );
+extern struct __svg_node *__svg_new_polyline( struct __svg_points *ps );
+extern struct __svg_node *__svg_new_path( struct __svg_cmds *cmds );
+
+extern struct __svg_node *__svg_new_text( double x,
+ double y,
+ const char *text,
+ const char *font_family,
+ int font_size );
+
+extern struct __svg_node *__svg_new_image( double x,
+ double y,
+ int width,
+ int height,
+ char *href,
+ char *title );
+
+extern struct __svg_node *__svg_new_l_gradient( const char *units, /* objectBoundingBox | userSpaceOnUse */
+ const char *spread, /* pad | reflect | repeat */
+ double x1,
+ double y1,
+ double x2,
+ double y2 );
+
+extern struct __svg_node *__svg_new_r_gradient( const char *units, /* objectBoundingBox | userSpaceOnUse */
+ const char *spread, /* pad | reflect | repeat */
+ double cx,
+ double cy,
+ double r,
+ double fx,
+ double fy );
+
+extern struct __svg_node *__svg_new_stop( double offset );
+
+extern int __svg_gradient_add_stop( void *gradient,
+ struct __svg_stop *stop );
+
+
+/***************************************************************
+ Adding some primitive to SCENE:
+ ***************************************************************/
+extern int
+__svg_scene_add_node( struct __svg_scene *scene, struct __svg_node *node );
+
+
+/***************************************************************
+ Style controls:
+ ***************************************************************/
+extern int __svg_set_stroke( struct __svg_node *node, const char *stroke );
+extern int __svg_set_stroke_rgb( struct __svg_node *node, int r, int g, int b );
+extern int __svg_set_stroke_width( struct __svg_node *node, double width );
+extern int __svg_set_stroke_linecap( struct __svg_node *node, const char *linecap );
+extern int __svg_set_stroke_linejoin( struct __svg_node *node, const char *linejoin );
+extern int __svg_set_stroke_dasharray( struct __svg_node *node, const char *dasharray );
+
+extern int __svg_set_fill( struct __svg_node *node, const char *fill );
+extern int __svg_set_fill_rgb( struct __svg_node *node, int r, int g, int b );
+
+extern int __svg_set_stop_color( struct __svg_node *node, const char *stop_color );
+extern int __svg_set_stop_color_rgb( struct __svg_node *node, int r, int g, int b );
+
+extern int __svg_set_stop_opacity( struct __svg_node *node, double stop_opacity );
+
+extern int __svg_set_text_text( struct __svg_node *node, const char *text );
+extern int __svg_set_text_fill( struct __svg_node *node, const char *fill );
+extern int __svg_set_text_fill_rgb( struct __svg_node *node, int r, int g, int b );
+extern int __svg_set_text_font_family( struct __svg_node *node, const char *family );
+extern int __svg_set_text_font_size( struct __svg_node *node, int size );
+
+
+/* Set Global Default Values: */
+extern void __svg_set_scene_default_style( void );
+extern void __svg_set_scene_stroke( const char *stroke );
+extern void __svg_set_scene_stroke_rgb( int r, int g, int b );
+extern void __svg_set_scene_stroke_width( double width );
+extern void __svg_set_scene_stroke_linecap( const char *linecap );
+extern void __svg_set_scene_stroke_linejoin( const char *linejoin );
+extern void __svg_set_scene_stroke_dasharray( const char *dasharray );
+
+extern void __svg_set_scene_fill( const char *fill );
+extern void __svg_set_scene_fill_rgb( int r, int g, int b );
+
+extern void __svg_set_scene_stop_color( const char *stop_color );
+extern void __svg_set_scene_stop_color_rgb( int r, int g, int b );
+
+extern void __svg_set_scene_stop_opacity( double stop_opacity );
+
+extern void __svg_set_scene_text_fill( const char *fill );
+extern void __svg_set_scene_text_fill_rgb( int r, int g, int b );
+extern void __svg_set_scene_text_font_family( const char *family );
+extern void __svg_set_scene_text_font_size( int size );
+
+
+/* Get node ID: */
+extern const char *__svg_get_node_id( struct __svg_node *node );
+extern char *__svg_create_node_url( struct __svg_node *node );
+
+
+/***************************************************************
+ OUTPUT:
+ ***************************************************************/
+extern void __svg_paint_scene( struct __svg_scene *scene,
+ int group,
+ char *fname );
+
+
+extern int _svgc_get_major_version( void );
+extern int _svgc_get_minor_version( void );
+extern int _svgc_get_micro_version( void );
+
+#if defined( __cplusplus )
+} /* extern "C" */
+#endif
+
+#endif /* __SVGC_H__ */