diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 16 | ||||
| -rw-r--r-- | src/_svgc_version.c | 75 | ||||
| -rw-r--r-- | src/svgc-dlist.c | 535 | ||||
| -rw-r--r-- | src/svgc-dlist.h | 90 | ||||
| -rw-r--r-- | src/svgc.c | 2461 | ||||
| -rw-r--r-- | src/svgc.h | 620 |
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, µ) != 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, µ) != 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, µ) != 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__ */ |
