/*------------------------------------------------------------------------------------------------------------------------------------ GNUPLOT - svg.trm This file is included by ../term.c. This terminal driver supports: W3C Scalable Vector Graphics AUTHOR Amedeo Farello afarello@libero.it HEAVILY MODIFIED by Hans-Bernhard Br"oker broeker@physik.rwth-aachen.de DomTerm support Per Bothner ------------------------------------------------------------------------------------------------------------------------------------*/ /* PM3D support by Johannes Zellner , May-16-2002 */ /* set_color fixes by Petr Mikulik , June-10-2002 */ /* ISO-Latin encoding, Font selection fixes, option "fixed|dynamic" by * Wilhelm Braunschober , Feb-21-2002 */ /* * Additional code for gnuplot versions 4.2 and 4.3 * Ethan Merritt * * Tweaked code for compatibility with Sodipodi svg viewer/editor. * Added enhanced text support. * Additional line properties. * Increase resolution by adding a coordinate scale factor. * Support dashed lines, TC_* color model. * Change path markup from style='attribute: foo' to attribute='foo' * * Additional code for gnuplot versions 4.5 * Ethan Merritt * * Wrap each plot in a named group * Set the name using 'set term svg name "foo"' * Background option * Bitmap image support by creating and linking to external png files * Mouse-tracking with coordinate readout. * Version 4.7 (April 2012) hypertext support * * Contributed by * Javascript code to toggle plots on/off * * Revised font sizing Oct 2012 * specify font-size without "pt" units. * * Inline image data in Base64 encoding * Daniel Sebald May 2016 * * Transition to SVG 2.0 * remove DTD * remove option "fontfile" and references to SVG fonts */ /* * Code for gnuplot version 4.5 * Bold -> font-weight:bold * Italic -> font-style:italic * Trying to match well with PNG output. * Rich Seymour */ #include "driver.h" #ifdef TERM_REGISTER register_term(svg) #endif #ifdef TERM_PROTO TERM_PUBLIC void SVG_options __PROTO ((void)); TERM_PUBLIC void SVG_init __PROTO ((void)); TERM_PUBLIC void SVG_graphics __PROTO ((void)); TERM_PUBLIC void SVG_text __PROTO ((void)); TERM_PUBLIC void SVG_linetype __PROTO ((int linetype)); TERM_PUBLIC void SVG_dashtype __PROTO ((int type, t_dashtype *custom_dash_type)); TERM_PUBLIC void SVG_move __PROTO ((unsigned int x, unsigned int y)); TERM_PUBLIC void SVG_vector __PROTO ((unsigned int x, unsigned int y)); TERM_PUBLIC void SVG_put_text __PROTO ((unsigned int x, unsigned int y, const char *str)); TERM_PUBLIC void SVG_reset __PROTO ((void)); TERM_PUBLIC int SVG_justify_text __PROTO ((enum JUSTIFY mode)); TERM_PUBLIC int SVG_text_angle __PROTO ((int ang)); TERM_PUBLIC void SVG_point __PROTO ((unsigned int x, unsigned int y, int pointstyle)); TERM_PUBLIC int SVG_set_font __PROTO ((const char *font)); /* TERM_PUBLIC void SVG_pointsize __PROTO((double pointsize)); */ TERM_PUBLIC void SVG_fillbox __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)); TERM_PUBLIC void SVG_linewidth __PROTO ((double linewidth)); TERM_PUBLIC int SVG_make_palette __PROTO((t_sm_palette *)); TERM_PUBLIC void SVG_previous_palette __PROTO((void)); TERM_PUBLIC void SVG_set_color __PROTO((t_colorspec *)); TERM_PUBLIC void SVG_filled_polygon __PROTO((int, gpiPoint *)); TERM_PUBLIC void SVG_layer __PROTO((t_termlayer syncpoint)); TERM_PUBLIC void ENHsvg_OPEN __PROTO((char *, double, double, TBOOLEAN, TBOOLEAN, int)); TERM_PUBLIC void ENHsvg_FLUSH __PROTO((void)); TERM_PUBLIC void ENHsvg_put_text __PROTO((unsigned int, unsigned int, const char *)); TERM_PUBLIC void ENHsvg_writec __PROTO((int)); TERM_PUBLIC void SVG_path __PROTO((int p)); TERM_PUBLIC void SVG_hypertext __PROTO((int, const char *)); #ifdef WRITE_PNG_IMAGE TERM_PUBLIC void SVG_image __PROTO((unsigned m, unsigned n, coordval *image, gpiPoint *corner, t_imagecolor color_mode)); #endif #define SVG_SCALE 10. /* Coordinates accuracy is 1/SVG_SCALE pixel */ #define PREC 1 /* Decimal places needed for SVG_SCALEd values */ #define Y(y) ((float)((int)term->ymax - (int)y) / SVG_SCALE) #define X(x) ((float)(x) / SVG_SCALE) #define SVG_XMAX (600 * SVG_SCALE) #define SVG_YMAX (480 * SVG_SCALE) #endif /* TERM_PROTO */ #ifndef TERM_PROTO_ONLY #ifdef TERM_BODY static t_sm_palette SVG_palette; static unsigned char SVG_red = 0; static unsigned char SVG_green = 0; static unsigned char SVG_blue = 0; static double SVG_alpha = 0.0; static unsigned char SVG_color_mode = TC_DEFAULT; static char *SVG_linecolor = NULL; static char *SVG_name = NULL; static char *SVG_scriptdir = NULL; static TBOOLEAN SVG_mouseable = FALSE; static TBOOLEAN SVG_standalone = FALSE; static TBOOLEAN SVG_domterm = FALSE; static TBOOLEAN SVG_emit_doctype = TRUE; static TBOOLEAN SVG_groupFilledIsOpen = FALSE; /* open pm3d group flag*/ static TBOOLEAN SVG_inTextBox = FALSE; struct SVG_PEN { double width; char color[8]; }; static unsigned int SVG_xSize = SVG_XMAX; /* plot horizontal size */ static unsigned int SVG_ySize = SVG_YMAX; /* plot vertical size*/ static TBOOLEAN SVG_fixed_size = TRUE; /* make SVG viewer size fixed */ static unsigned int SVG_xLast = UINT_MAX; /* current pen horizontal position*/ static unsigned int SVG_yLast = UINT_MAX; /* current pen vertical position*/ static int SVG_LineType = LT_NODRAW; /* current line type*/ static double SVG_LineWidth = 1.0; /* current line width*/ static double SVG_linewidth_factor = 1.0; /* Multiplier for linewidths */ static double SVG_dashlength = 1.0; /* Multiplier for dash patterns */ static t_linecap SVG_linecap = BUTT; /* linejoin and linecap */ static int SVG_TextAngle = 0; /* current text orientation*/ static enum JUSTIFY SVG_TextJust = LEFT; /* current text justification*/ /* default text font family: */ static char *SVG_fontNameDef = NULL; static char *SVG_fontStyleDef = NULL; /* default font style */ static char *SVG_fontWeightDef = NULL; /* default font weight */ static double SVG_fontSizeDef = 12; /* default text size*/ /* current text font family: */ static char *SVG_fontNameCur = NULL; static char *SVG_fontStyleCur = NULL; /* current font style */ static char *SVG_fontWeightCur = NULL; /* current font weight */ static double SVG_fontSizeCur = 12; /* current text size*/ static double SVG_fontscale = 1.0; /* multiplier for nominal font size */ static TBOOLEAN SVG_groupIsOpen = FALSE; /* open group flag*/ static TBOOLEAN SVG_pathIsOpen = FALSE; /* open path flag*/ static unsigned int SVG_path_count = 0; /* size of current path*/ static struct SVG_PEN SVG_pens[16]; /* pen descriptors*/ static int SVG_fillPattern = -1; /* active fill pattern (-1 == undefined) */ static unsigned int SVG_fillPatternIndex = 0; static int SVG_background = -1; static int SVG_imageno = 0; static int SVG_plotno = 0; static TBOOLEAN SVG_gridline = FALSE; static TBOOLEAN SVG_hasgrid = FALSE; static double SVG_fontAscent = 0; /* estimated current font ascent*/ static double SVG_fontDescent = 0; /* estimated current font descent*/ static double SVG_fontLeading = 0; /* estimated current font leading*/ static double SVG_fontAvWidth = 0; /* estimated current font char average width*/ static short SVG_Pen_RealID __PROTO ((int)); static void SVG_PathOpen __PROTO ((void)); static void SVG_PathClose __PROTO ((void)); static void SVG_AddSpaceOrNewline __PROTO ((void)); static void SVG_GroupOpen __PROTO ((void)); static void SVG_GroupClose __PROTO ((void)); static void SVG_SetFont __PROTO ((const char *name, double size)); static void SVG_GroupFilledOpen __PROTO ((void)); static void SVG_GroupFilledClose __PROTO ((void)); static void SVG_StyleColor __PROTO((const char*)); static void SVG_StyleFillColor __PROTO((void)); static void SVG_local_reset __PROTO((void)); static void SVG_DefineFillPattern __PROTO((int fillpat)); static void SVG_MoveForced __PROTO((unsigned int x, unsigned int y)); static void SVG_write_preamble __PROTO ((void)); /* Stuff for enhanced text mode */ static int ENHsvg_string_state = 0; static double ENHsvg_x_offset = 0; static TBOOLEAN ENHsvg_preserve_spaces = FALSE; /* Support for dashed lines */ #define SVG_dashtypes 5 static char *SVG_defaultdashpattern[SVG_dashtypes] = { "", " 5,8", " 2,4", " 8,4,2,4", " 9,4,1,4,1,4" }; static char *SVG_axis_dashpattern = "2,4"; static int SVG_dasharray[SVG_dashtypes][7] = { { 0,0,0,0,0,0,0}, {5,8, 0,0,0,0,0}, {2,4, 0,0,0,0,0}, {8,4,2,4, 0,0,0}, {9,4,1,4,1,4, 0} }; static char *SVG_dashpattern = NULL; static char SVG_custom_dash_pattern[64]; /* Support for embedded hypertext */ static char *SVG_hypertext_text = NULL; /*------------------------------------------------------------------------------------------------------------------------------------ SVG_Pen_RealID ------------------------------------------------------------------------------------------------------------------------------------*/ static short SVG_Pen_RealID (int inPenCode) { if (inPenCode >= 13) inPenCode %= 13; /* normalize pen code*/ inPenCode += 3; if (inPenCode < 0) inPenCode = 0; /* LT_BACKGROUND should use background color */ return (inPenCode); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_GroupOpen ------------------------------------------------------------------------------------------------------------------------------------*/ static void SVG_GroupOpen () { SVG_GroupFilledClose(); if (!SVG_groupIsOpen) { fprintf (gpoutfile, "\n"); SVG_groupIsOpen = TRUE; } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_GroupClose ------------------------------------------------------------------------------------------------------------------------------------*/ static void SVG_GroupClose () { SVG_GroupFilledClose(); if (SVG_groupIsOpen) { fputs ("\n", gpoutfile); SVG_groupIsOpen = FALSE; SVG_fillPattern = -1; } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_PathOpen ------------------------------------------------------------------------------------------------------------------------------------*/ static void SVG_PathOpen () { if (!SVG_pathIsOpen) { SVG_GroupFilledClose(); fputs ("\t"); SVG_path_count = 0; SVG_pathIsOpen = FALSE; } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_AddSpaceOrNewline ------------------------------------------------------------------------------------------------------------------------------------*/ static void SVG_AddSpaceOrNewline () { if (SVG_path_count % 8 == 0) /* avoid excessive line length*/ fputs ("\n\t\t", gpoutfile); else fputs (" ", gpoutfile); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_SetFont ------------------------------------------------------------------------------------------------------------------------------------*/ static void SVG_SetFont (const char *name, double size) { if (name != SVG_fontNameCur) { free(SVG_fontNameCur); SVG_fontNameCur = gp_strdup(name); } SVG_fontSizeCur = size; /* since we cannot interrogate SVG about text properties and according * to SVG 1.0 W3C Candidate Recommendation 2 August 2000 the * "line-height" of the 'text' element is defined to be equal to the * 'font-size' (!), we have to to define font properties in a less * than optimal way */ SVG_fontAscent = (SVG_fontSizeCur * 0.90 * SVG_SCALE); SVG_fontDescent = (SVG_fontSizeCur * 0.25 * SVG_SCALE); SVG_fontLeading = (SVG_fontSizeCur * 0.35 * SVG_SCALE); SVG_fontAvWidth = (SVG_fontSizeCur * 0.70 * SVG_SCALE); term->h_char = SVG_fontAvWidth; term->v_char = (SVG_fontAscent + SVG_fontDescent + SVG_fontLeading); } static void SVG_GroupFilledOpen() { if (!SVG_groupFilledIsOpen) { SVG_PathClose(); fputs("\t\n", gpoutfile); SVG_groupFilledIsOpen = TRUE; } } static void SVG_GroupFilledClose() { if (SVG_groupFilledIsOpen) { fputs("\t\n", gpoutfile); SVG_groupFilledIsOpen = FALSE; } } static void SVG_StyleColor(const char* paint) { if (SVG_color_mode == TC_RGB) fprintf(gpoutfile, "%s = 'rgb(%3d, %3d, %3d)'", paint, SVG_red, SVG_green, SVG_blue); else if (SVG_color_mode == TC_LT) fprintf(gpoutfile, "%s = '%s'", paint, SVG_linecolor); else fprintf(gpoutfile, "%s = 'currentColor'", paint); } static void SVG_StyleFillColor() { SVG_StyleColor("fill"); } static void SVG_DefineFillPattern(int fillpat) { char *path; char *style="stroke"; fillpat %= 8; if (fillpat != SVG_fillPattern) { SVG_fillPattern = fillpat; SVG_PathClose(); SVG_fillPatternIndex++; fprintf(gpoutfile, "\t\n" "\t\t\n", SVG_fillPatternIndex); switch (fillpat) { default: case 0: path=""; break; case 1: path="M0,0 L8,8 M0,8 L8,0"; break; case 2: path="M0,0 L8,8 M0,8 L8,0 M0,4 L4,8 L8,4 L4,0 L0,4"; break; case 3: path="M0,0 L0,8 L8,8 L8,0 L0,0"; style="fill"; break; case 4: path="M-4,0 L8,12 M0,-4 L12,8"; break; case 5: path="M-4,8 L8,-4 M0,12 L12,0"; break; case 6: path="M-2,8 L4,-4 M0,12 L8,-4 M4,12 L10,0"; break; case 7: path="M-2,0 L4,12 M0,-4 L8,12 M4,-4 L10,8"; break; } if (*path) { char *figure = "fill:none;"; if (!strcmp(style,"fill")) figure = "stroke:none;"; if (SVG_color_mode == TC_RGB) fprintf(gpoutfile,"\t\t\t\n", figure, style, SVG_red, SVG_green, SVG_blue, path); else if (SVG_color_mode == TC_LT) fprintf(gpoutfile, "\t\t\t\n", figure, style, SVG_linecolor, path); else fprintf(gpoutfile, "\t\t\t\n", figure, style, path); } fputs("\t\t\n" "\t\n", gpoutfile); } } static void SVG_MoveForced(unsigned int x, unsigned int y) { if (SVG_path_count > 512) SVG_PathClose(); SVG_PathOpen (); fprintf (gpoutfile, "M%.*f,%.*f", PREC, X(x), PREC, Y(y)); SVG_path_count++; SVG_AddSpaceOrNewline (); SVG_xLast = x; SVG_yLast = y; } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_options ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_options () { /* Annoying hack to handle the case of 'set termoption' after */ /* we have already initialized the terminal settings. */ if (!almost_equals(c_token-1, "termopt$ion")) SVG_local_reset(); if (strcmp(term->name, "domterm") == 0) { SVG_emit_doctype = FALSE; SVG_domterm = TRUE; } else { SVG_emit_doctype = TRUE; SVG_domterm = FALSE; } /* Minimal initialization in case we error out of options parsing */ SVG_set_font(""); while (!END_OF_COMMAND) { if (almost_equals(c_token, "s$ize")) { double value; c_token++; if (END_OF_COMMAND) int_error(c_token,"expecting x size"); value = real_expression(); if (value < 2) int_error(c_token,"x size out of range"); SVG_xSize = value * SVG_SCALE; if (equals(c_token,",")) c_token++; if (END_OF_COMMAND) int_error(c_token,"expecting y size"); value = real_expression(); if (value < 2) int_error(c_token,"y size out of range"); SVG_ySize = value * SVG_SCALE; continue; } if (equals(c_token, "mouse") || almost_equals(c_token, "mous$ing")) { c_token++; SVG_mouseable = TRUE; continue; } if (almost_equals(c_token, "stand$alone")) { c_token++; SVG_standalone = TRUE; continue; } if (equals(c_token, "name")) { c_token++; SVG_name = try_to_get_string(); if (!SVG_name) int_error(c_token,"expecting a plot name"); if (SVG_name[strspn(SVG_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_1234567890")]) int_error(c_token-1,"name must contain only alphanumerics or _"); continue; } if (equals(c_token, "jsdir")) { c_token++; SVG_scriptdir = try_to_get_string(); continue; } if (almost_equals(c_token, "d$ynamic")) { c_token++; SVG_fixed_size = FALSE; continue; } if (almost_equals(c_token, "fi$xed")){ c_token++; SVG_fixed_size = TRUE; continue; } if (almost_equals(c_token, "enh$anced")) { c_token++; term->put_text = ENHsvg_put_text; term->flags |= TERM_ENHANCED_TEXT; continue; } if (almost_equals(c_token, "noenh$anced")) { c_token++; term->put_text = SVG_put_text; term->flags &= ~TERM_ENHANCED_TEXT; continue; } if (almost_equals(c_token, "fn$ame") || almost_equals(c_token, "font")) { char *s, *comma; c_token++; if (!(s = try_to_get_string())) int_error(c_token,"expecting font name"); comma = strrchr(s,','); if (comma && (1 == sscanf(comma + 1, "%lf", &SVG_fontSizeDef))) *comma = '\0'; if (*s) { char *bold, *italic; if (!((bold = strstr(s," bold")))) bold = strstr(s," Bold"); if (!((italic = strstr(s," italic")))) italic = strstr(s," Italic"); free(SVG_fontNameDef); SVG_fontNameDef = s; if (italic) { SVG_fontStyleDef = "italic"; SVG_fontNameDef[strlen(s) - strlen(italic)] = NUL; } else { SVG_fontStyleDef = "normal"; } if (bold) { SVG_fontWeightDef="bold"; SVG_fontNameDef[strlen(s) - strlen(bold)] = NUL; } else { SVG_fontWeightDef = "normal"; } } else free(s); continue; } if (equals(c_token, "fontscale")) { c_token++; SVG_fontscale = real_expression(); if (SVG_fontscale <= 0) SVG_fontscale = 1.0; continue; } if (almost_equals(c_token, "linew$idth") || equals(c_token, "lw")) { c_token++; SVG_linewidth_factor = real_expression(); if (SVG_linewidth_factor <= 0.0) SVG_linewidth_factor = 1.0; continue; } if (almost_equals(c_token, "dashl$ength") || equals(c_token, "dl")) { c_token++; SVG_dashlength = real_expression(); if (SVG_dashlength < 0.5) SVG_dashlength = 1.0; continue; } if (almost_equals (c_token, "round$ed")) { c_token++; SVG_linecap = ROUNDED; continue; } if (equals (c_token, "square")) { c_token++; SVG_linecap = SQUARE; continue; } if (equals (c_token, "butt")) { c_token++; SVG_linecap = BUTT; continue; } /* Not used in version 5 */ if (equals(c_token, "solid") || almost_equals(c_token, "dash$ed")) { c_token++; continue; } if (almost_equals(c_token, "backg$round")) { c_token++; SVG_background = parse_color_name(); continue; } int_error(c_token, "unrecognized terminal option"); } /* I don't think any error checks on font name are possible; just set it */ SVG_set_font(""); /* Save options back into options string in normalized format */ sprintf(term_options, "size %d,%d%s %s font '%s,%g' ", (int)(SVG_xSize/SVG_SCALE), (int)(SVG_ySize/SVG_SCALE), SVG_fixed_size ? " fixed": " dynamic", term->put_text == ENHsvg_put_text ? "enhanced" : "", SVG_fontNameCur, SVG_fontSizeCur); if (SVG_mouseable) { sprintf(term_options + strlen(term_options), "mousing "); } if (SVG_standalone) { sprintf(term_options + strlen(term_options), "standalone "); } if (SVG_name) { sprintf(term_options + strlen(term_options), "name \"%s\" ", SVG_name); } sprintf(term_options + strlen(term_options), SVG_linecap == ROUNDED ? "rounded " : SVG_linecap == SQUARE ? "square " : "butt "); sprintf(term_options + strlen(term_options), "dashlength %.1f ", SVG_dashlength); if (SVG_linewidth_factor != 1.0) { sprintf(term_options + strlen(term_options), "linewidth %3.1f ", SVG_linewidth_factor); } if (SVG_background >= 0) { sprintf(term_options + strlen(term_options), "background \"#%06x\" ", SVG_background); } } static void SVG_local_reset() { SVG_xSize = SVG_XMAX; SVG_ySize = SVG_YMAX; SVG_fixed_size = TRUE; free(SVG_fontNameDef); SVG_fontNameDef = gp_strdup("Arial"); SVG_fontSizeDef = 12; SVG_mouseable = FALSE; SVG_standalone = FALSE; free(SVG_name); SVG_name = NULL; free(SVG_scriptdir); SVG_scriptdir = NULL; SVG_gridline = FALSE; SVG_hasgrid = FALSE; /* Default to enhanced text */ term->put_text = ENHsvg_put_text; term->flags |= TERM_ENHANCED_TEXT; } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_init ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_init () { /* setup pens*/ SVG_pens[0].width = SVG_LineWidth; strcpy (SVG_pens[0].color, "white"); /* should really be background */ SVG_pens[1].width = SVG_LineWidth; strcpy(SVG_pens[1].color, "black"); SVG_pens[2].width = SVG_LineWidth; strcpy(SVG_pens[2].color, "gray"); SVG_pens[3].width = SVG_LineWidth; strcpy(SVG_pens[3].color, "red"); SVG_pens[4].width = SVG_LineWidth; strcpy(SVG_pens[4].color, "green"); SVG_pens[5].width = SVG_LineWidth; strcpy(SVG_pens[5].color, "blue"); SVG_pens[6].width = SVG_LineWidth; strcpy(SVG_pens[6].color, "cyan"); SVG_pens[7].width = SVG_LineWidth; sprintf(SVG_pens[7].color, "#%2.2X%2.2X%2.2X", 21, 117, 69); /* pine green*/ SVG_pens[8].width = SVG_LineWidth; sprintf (SVG_pens[8].color, "#%2.2X%2.2X%2.2X", 0, 0, 148); /* navy*/ SVG_pens[9].width = SVG_LineWidth; sprintf (SVG_pens[9].color, "#%2.2X%2.2X%2.2X", 255, 153, 0); /* orange*/ SVG_pens[10].width = SVG_LineWidth; sprintf (SVG_pens[10].color, "#%2.2X%2.2X%2.2X", 0, 153, 161); /* green blue*/ SVG_pens[11].width = SVG_LineWidth; sprintf (SVG_pens[11].color, "#%2.2X%2.2X%2.2X", 214, 214, 69); /* olive*/ SVG_pens[12].width = SVG_LineWidth; sprintf (SVG_pens[12].color, "#%2.2X%2.2X%2.2X", 163, 145, 255); /* cornflower*/ SVG_pens[13].width = SVG_LineWidth; sprintf (SVG_pens[13].color, "#%2.2X%2.2X%2.2X", 255, 204, 0); /* gold*/ SVG_pens[14].width = SVG_LineWidth; sprintf (SVG_pens[14].color, "#%2.2X%2.2X%2.2X", 214, 0, 120); /* mulberry*/ SVG_pens[15].width = SVG_LineWidth; sprintf (SVG_pens[15].color, "#%2.2X%2.2X%2.2X", 171, 214, 0); /* green yellow*/ if (SVG_background >= 0) sprintf(SVG_pens[0].color, "#%2.2X%2.2X%2.2X", (SVG_background >> 16)&0xff, (SVG_background >> 8)&0xff, (SVG_background)&0xff); SVG_LineType = LT_NODRAW; /* set xmax, ymax*/ term->xmax = SVG_xSize; term->ymax = SVG_ySize; /* set current font, including h_char and v_char */ SVG_SetFont (SVG_fontNameCur, SVG_fontSizeCur); /* set h_tic, v_tic*/ term->h_tic = term->v_char / 2; term->v_tic = term->v_char / 2; } /* write file header*/ static void SVG_write_preamble () { int len; double stroke_width; char *svg_encoding = ""; switch (encoding) { case S_ENC_ISO8859_1: svg_encoding = "encoding=\"iso-8859-1\" "; break; case S_ENC_ISO8859_2: svg_encoding = "encoding=\"iso-8859-2\" "; break; case S_ENC_ISO8859_9: svg_encoding = "encoding=\"iso-8859-9\" "; break; case S_ENC_ISO8859_15: svg_encoding = "encoding=\"iso-8859-15\" "; break; case S_ENC_CP850: svg_encoding = "encoding=\"ibm-850\" "; break; case S_ENC_CP852: svg_encoding = "encoding=\"ibm-852\" "; break; case S_ENC_CP950: svg_encoding = "encoding=\"cp950\" "; break; case S_ENC_CP1250: svg_encoding = "encoding=\"windows-1250\" "; break; case S_ENC_CP1251: svg_encoding = "encoding=\"windows-1251\" "; break; case S_ENC_CP1252: svg_encoding = "encoding=\"windows-1252\" "; break; case S_ENC_KOI8_R: svg_encoding = "encoding=\"koi8-r\" "; break; case S_ENC_KOI8_U: svg_encoding = "encoding=\"koi8-u\" "; break; case S_ENC_SJIS: svg_encoding = "encoding=\"Shift_JIS\" "; break; case S_ENC_CP437: svg_encoding = ""; break; default: /* UTF-8 */ svg_encoding = "encoding=\"utf-8\" "; break; } if (SVG_domterm) fprintf(gpoutfile, "\033]72;"); if (SVG_emit_doctype) fprintf (gpoutfile, "\n", svg_encoding); fprintf(gpoutfile, "xmax / SVG_SCALE), (unsigned int) (term->ymax / SVG_SCALE)); fprintf (gpoutfile, "\n viewBox=\"0 0 %u %u\"\n", (unsigned int) (term->xmax / SVG_SCALE), (unsigned int) (term->ymax / SVG_SCALE)); fprintf (gpoutfile, " xmlns=\"http://www.w3.org/2000/svg\"\n"); fprintf (gpoutfile, " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"); #if (0) /* This should be required, but Firefox gets it totally wrong */ fprintf (gpoutfile, " xml:space=\"preserve\"\n"); #endif fprintf (gpoutfile, ">\n\n"); /* TODO: It would be nice to print the actual plot title here */ fprintf (gpoutfile, "%s\n", SVG_name ? SVG_name : "Gnuplot"); fprintf (gpoutfile, "Produced by GNUPLOT %s patchlevel %s \n\n", gnuplot_version, gnuplot_patchlevel); /* * FIXME: This code could be shared with canvas.trm * Figure out the full URL to use for xlink:href="gnuplot_svg.js" */ if (SVG_scriptdir == NULL) { #ifdef GNUPLOT_JS_DIR # if defined(_WIN32) SVG_scriptdir = RelativePathToGnuplot(GNUPLOT_JS_DIR); # else /* !_WIN32 */ /* use hardcoded _absolute_ path */ SVG_scriptdir = gp_strdup(GNUPLOT_JS_DIR); # endif #else SVG_scriptdir = gp_strdup(""); #endif /* GNUPLOT_JS_DIR */ } #if !defined(VMS) len = strlen(SVG_scriptdir); # if defined(_WIN32) if (*SVG_scriptdir && SVG_scriptdir[len-1] != '\\' && SVG_scriptdir[len-1] != '/') { SVG_scriptdir = gp_realloc(SVG_scriptdir, len+2, "jsdir"); if (SVG_scriptdir[len-1] == '\\') /* use backslash if used in jsdir, otherwise slash */ strcat(SVG_scriptdir,"\\"); else strcat(SVG_scriptdir,"/"); } # else if (*SVG_scriptdir && SVG_scriptdir[len-1] != '/') { SVG_scriptdir = gp_realloc(SVG_scriptdir, len+2, "jsdir"); strcat(SVG_scriptdir,"/"); } # endif #endif if (SVG_mouseable) { /* Inclusion of gnuplot_svg.js is sufficient to support toggling plots on/off */ if (!SVG_standalone) { fprintf(gpoutfile, "\n\n", gpoutfile); if (SVG_domterm) { fprintf(gpoutfile, "\007"); fflush(gpoutfile); } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_reset ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_reset () { } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_linetype ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_linetype (int linetype) { SVG_color_mode = TC_DEFAULT; if (TRUE || linetype != SVG_LineType) { SVG_PathClose (); SVG_GroupClose (); SVG_LineType = linetype; SVG_GroupOpen (); } if (linetype == LT_AXIS) SVG_dashpattern = SVG_axis_dashpattern; if (linetype == LT_SOLID) SVG_dashpattern = NULL; } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_dashtype ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_dashtype (int type, t_dashtype *custom_dash_type) { int d, j; double empirical_scale = 0.50; /* The dash pattern should depend on the `linewidth` and the terminal options `dashlength` and `linewidth`. */ double dash_scale = SVG_pens[SVG_Pen_RealID (SVG_LineType)].width * SVG_linewidth_factor * SVG_dashlength * empirical_scale; SVG_dashpattern = NULL; /* Assume solid line */ switch(type) { case DASHTYPE_SOLID: break; case DASHTYPE_AXIS: /* Currently handled elsewhere via LT_AXIS */ break; case DASHTYPE_CUSTOM: if (custom_dash_type) { SVG_dashpattern = SVG_custom_dash_pattern; *SVG_dashpattern = '\0'; for (j = 0; j < 8 && custom_dash_type->pattern[j] > 0; j++) { char *p = &SVG_dashpattern[strlen(SVG_dashpattern)]; snprintf(p, 8, "%.1f", custom_dash_type->pattern[j] * dash_scale); if (j < 7 && custom_dash_type->pattern[j+1]) strcat(p,","); } } break; default: /* Fall back to whatever version 4 would have provided */ d = type % SVG_dashtypes; if (d <= 0) break; /* Default dash length and sequence */ if (dash_scale == 1.0) SVG_dashpattern = SVG_defaultdashpattern[d]; /* Dash patterns scaled up by dashlength and linewidth */ else { SVG_dashpattern = SVG_custom_dash_pattern; *SVG_dashpattern = '\0'; j = 0; do { char *p = &SVG_dashpattern[strlen(SVG_dashpattern)]; snprintf(p, 8, "%.1f", SVG_dasharray[d][j] * dash_scale); if (SVG_dasharray[d][++j]) strcat(p,","); } while (SVG_dasharray[d][j] > 0); } break; } } TERM_PUBLIC void SVG_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height) { gpiPoint corner[4]; corner[0].x = x1; corner[0].y = y1; corner[1].x = x1+width; corner[1].y = y1; corner[2].x = x1+width; corner[2].y = y1+height; corner[3].x = x1; corner[3].y = y1+height; corner->style = style; SVG_filled_polygon(4, corner); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_linewidth - verificare ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_linewidth (double linewidth) { if (linewidth != SVG_LineWidth) { short k; SVG_LineWidth = linewidth; for (k = 0; k < 16; k++) SVG_pens[k].width = SVG_LineWidth; SVG_PathClose (); SVG_GroupClose (); SVG_GroupOpen (); } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_move ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_move (unsigned int x, unsigned int y) { if (x != SVG_xLast || y != SVG_yLast) { SVG_MoveForced(x, y); } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_vector ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_vector (unsigned int x, unsigned int y) { if (x != SVG_xLast || y != SVG_yLast) { if (!SVG_pathIsOpen) { /* The SVG 'path' MUST have a 'moveto' as first command. */ SVG_MoveForced(SVG_xLast, SVG_yLast); } fprintf (gpoutfile, "L%.*f,%.*f", PREC, X(x), PREC, Y(y)); SVG_path_count++; SVG_AddSpaceOrNewline (); SVG_xLast = x; SVG_yLast = y; } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_point ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_point (unsigned int x, unsigned int y, int number) { char color_spec[0x40]; if (SVG_color_mode == TC_RGB) { sprintf(color_spec, " color='rgb(%3d, %3d, %3d)'", SVG_red, SVG_green, SVG_blue); if (SVG_alpha != 0.0) sprintf(&color_spec[27], " opacity='%4.2f'", 1.0 - SVG_alpha); } else if (SVG_color_mode == TC_LT) sprintf(color_spec, " color='%s'", SVG_linecolor); else *color_spec = '\0'; SVG_PathClose (); if (SVG_hypertext_text) { fprintf(gpoutfile,"\ \t \n", SVG_hypertext_text); } if (number < 0) { /* do dot */ fprintf (gpoutfile, "\ \t\n", PREC, X(x), PREC, Y(y), color_spec); } else { /* draw a point symbol */ fprintf (gpoutfile, "\ \t", number % 15, PREC, X(x), PREC, Y(y), term_pointsize * term->h_tic / (2 * SVG_SCALE), color_spec); } SVG_xLast = x; SVG_yLast = y; if (SVG_hypertext_text) { fprintf(gpoutfile,"\n"); free(SVG_hypertext_text); SVG_hypertext_text = NULL; } else { fprintf(gpoutfile,"\n"); } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_justify_text ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC int SVG_justify_text (enum JUSTIFY mode) { SVG_TextJust = mode; return (TRUE); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_text_angle ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC int SVG_text_angle (int ang) { /* Can only do pure horizontal or vertical */ SVG_TextAngle = ang; return (TRUE); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_put_text ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_put_text (unsigned int x, unsigned int y, const char *str) { char *alignment; double vertical_offset; int h = x, v = y; SVG_PathClose (); /* horizontal justification*/ switch (SVG_TextJust) { case LEFT: alignment = "start"; break; case CENTRE: alignment = "middle"; break; case RIGHT: default: /* can't happen, just to make gcc happy */ alignment = "end"; break; } /* vertical justification*/ vertical_offset = (SVG_fontAscent - SVG_fontDescent) / 2.; h += vertical_offset * sin(SVG_TextAngle * DEG2RAD); v -= vertical_offset * cos(SVG_TextAngle * DEG2RAD); /* define text position and attributes */ fprintf (gpoutfile, "\t\n"); /* output text (unless the enhanced_text processing is in action) */ if (strstr(str," ")) fputs ("\t\t", gpoutfile); else fputs ("\t\t", gpoutfile); if (!ENHsvg_string_state) { while (*str) { /* Escape SVG reserved characters */ switch (*str) { case '<': fputs("<", gpoutfile); break; case '&': if (str[1] == '#' && str[2] == 'x') fputc(*str, gpoutfile); else fputs("&", gpoutfile); break; default: fputc(*str, gpoutfile); break; } str++; } fputs("\n\t\n", gpoutfile); } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_set_font ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC int SVG_set_font (const char *font) { if (!font || !(*font)) { free(SVG_fontNameCur); SVG_fontNameCur = gp_strdup(SVG_fontNameDef); SVG_fontSizeCur = SVG_fontSizeDef; SVG_fontStyleCur = SVG_fontStyleDef; SVG_fontWeightCur = SVG_fontWeightDef; } else { char *bold, *italic; int sep; if (!((bold = strstr(font," bold")))) bold = strstr(font," Bold"); if (!((italic = strstr(font," italic")))) italic = strstr(font," Italic"); sep = strcspn(font,","); if (sep > 0) { free(SVG_fontNameCur); SVG_fontNameCur = gp_strdup(font); if (italic) { SVG_fontStyleCur="italic"; SVG_fontNameCur[strlen(font) - strlen(italic)] = NUL; } else { SVG_fontStyleCur="normal"; } if (bold) { SVG_fontWeightCur="bold"; SVG_fontNameCur[strlen(font) - strlen(bold)] = NUL; } else { SVG_fontWeightCur="normal"; } SVG_fontNameCur[sep] = NUL; } if (font[sep] == ',') sscanf(font + sep + 1, "%lf", &SVG_fontSizeCur); } /* Set other font properties */ SVG_SetFont(SVG_fontNameCur, SVG_fontSizeCur); return (TRUE); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_make_palette ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC int SVG_make_palette(t_sm_palette *palette) { SVG_GroupFilledClose(); if (palette == NULL) { /* svg can do continuous colors */ return 0; } /* save mapping formulae needed if SMPAL_COLOR_MODE_RGB */ SVG_palette.colorMode = palette->colorMode; SVG_palette.formulaR = palette->formulaR; SVG_palette.formulaG = palette->formulaG; SVG_palette.formulaB = palette->formulaB; SVG_palette.positive = palette->positive; return 0; } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_set_color ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_set_color(t_colorspec *colorspec) { rgb255_color rgb255; SVG_alpha = 0.0; if (colorspec->type == TC_LT) { if (SVG_linecolor != SVG_pens[SVG_Pen_RealID (colorspec->lt)].color) { SVG_linecolor = SVG_pens[SVG_Pen_RealID (colorspec->lt)].color; SVG_PathClose(); } SVG_color_mode = TC_LT; return; } else if (colorspec->type == TC_FRAC) { rgb255maxcolors_from_gray( colorspec->value, &rgb255 ); } else if (colorspec->type == TC_RGB) { rgb255.r = colorspec->lt >> 16 & 0xff; rgb255.g = colorspec->lt >> 8 & 0xff; rgb255.b = colorspec->lt & 0xff; SVG_alpha = (double)(colorspec->lt >> 24 & 0xff) / 255.; } else { return; } SVG_color_mode = TC_RGB; if (rgb255.r != SVG_red || rgb255.g != SVG_green || rgb255.b != SVG_blue) { /* pm3d color has changed. We must start a new path * with a different line color. This is necessary when * using "linetype palette". */ SVG_PathClose(); SVG_red = rgb255.r; SVG_green = rgb255.g; SVG_blue = rgb255.b; } return; } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_previous_palette ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_previous_palette() { SVG_GroupFilledClose(); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_filled_polygon ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_filled_polygon(int points, gpiPoint* corners) { int i; int fillpar = corners->style >> 4; int style = corners->style &= 0xf; if (style == FS_PATTERN || style == FS_TRANSPARENT_PATTERN) { /* make sure the pattern is defined (with the current stroke color) * must be defined AFTER the current group is opened with the color * attribute set, as the patterns use 'currentColor' */ SVG_DefineFillPattern(fillpar); } SVG_GroupFilledOpen(); fputs("\t\t= 0 && fillpar < 100) fprintf(gpoutfile, " fill-opacity = '%f'", fillpar * 0.01); break; case FS_PATTERN: /* pattern fill */ case FS_TRANSPARENT_PATTERN: fprintf(gpoutfile, " fill = 'url(#gpPat%d)'", SVG_fillPatternIndex); break; default: SVG_StyleFillColor(); break; } fputs(" points = '", gpoutfile); for (i = 0; i < points; i++) fprintf(gpoutfile, "%.*f,%.*f%s", PREC, X(corners[i].x), PREC, Y(corners[i].y), i % 16 == 15 ? "\n" : " "); fputs("'/>\n", gpoutfile); } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_layer ------------------------------------------------------------------------------------------------------------------------------------*/ TERM_PUBLIC void SVG_layer(t_termlayer syncpoint) { char *name = NULL; char panel[2] = {'\0','\0'}; /* We must ignore all syncpoints that we don't recognize */ switch (syncpoint) { default: break; case TERM_LAYER_BEFORE_PLOT: SVG_PathClose(); SVG_GroupClose(); ++SVG_plotno; name = (SVG_name) ? SVG_name : "gnuplot"; if (multiplot && multiplot_current_panel() < 26) panel[0] = 'a' + multiplot_current_panel(); fprintf(gpoutfile, "\t%s\n", SVG_hypertext_text); else fprintf(gpoutfile, ">%s_plot_%d%s\n", name,SVG_plotno,panel); free(SVG_hypertext_text); SVG_hypertext_text = NULL; SVG_LineType = LT_UNDEFINED; /* Force a new group on next stroke */ break; case TERM_LAYER_AFTER_PLOT: SVG_PathClose(); SVG_GroupClose(); fprintf(gpoutfile, "\t\n"); SVG_LineType = LT_UNDEFINED; /* Force a new group on next stroke */ break; case TERM_LAYER_BEGIN_GRID: SVG_gridline = TRUE; SVG_hasgrid = TRUE; break; case TERM_LAYER_END_GRID: SVG_gridline = FALSE; break; case TERM_LAYER_BEGIN_KEYSAMPLE: if (SVG_mouseable) { SVG_PathClose(); SVG_GroupFilledClose(); name = (SVG_name) ? SVG_name : "gnuplot"; if (multiplot && multiplot_current_panel() < 26) panel[0] = 'a' + multiplot_current_panel(); fprintf(gpoutfile, "\t\n"); } break; case TERM_LAYER_END_KEYSAMPLE: if (SVG_mouseable) { SVG_PathClose(); SVG_GroupFilledClose(); fprintf(gpoutfile, "\t\n"); } break; case TERM_LAYER_RESET: case TERM_LAYER_RESET_PLOTNO: SVG_plotno = 0; break; } } /*------------------------------------------------------------------------------------------------------------------------------------ SVG_image ------------------------------------------------------------------------------------------------------------------------------------*/ #ifdef WRITE_PNG_IMAGE TERM_PUBLIC void SVG_image (unsigned m, unsigned n, coordval *image, gpiPoint *corner, t_imagecolor color_mode) { SVG_PathClose(); /* Map image onto the terminal's coordinate system. */ fprintf(gpoutfile, "\n"); } else { /* Write the image to a png file */ char *image_file; char *base_name = SVG_name ? SVG_name : "gp"; int wpiresult; image_file = gp_alloc(strlen(base_name)+16, "SVG_image"); sprintf(image_file, "%s_image_%02d.png", base_name, ++SVG_imageno); wpiresult = write_png_image(m, n, image, color_mode, image_file); /* Reference the png image file */ fprintf(gpoutfile, "xlink:href='%s_image_%02d.png'/>\n", base_name, SVG_imageno); free(image_file); if (wpiresult != 0) os_error(NO_CARET, "SVG_image: could not write to PNG reference file."); } } #endif /* Enhanced text mode support starts here */ static double ENHsvg_base = 0.0; static TBOOLEAN ENHsvg_opened_string = FALSE; static int ENHsvg_charcount = 0; TERM_PUBLIC void ENHsvg_OPEN( char *fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint) { /* overprint = 1 means print the base text (leave position in center) * overprint = 2 means print the overlying text * overprint = 3 means save current position * overprint = 4 means restore saved position * EAM FIXME - Unfortunately I can find no way in the svg spec to do this. * The best I can come up with is to count characters from here and then * try to back up over them. */ switch (overprint) { case 2: /* FIXME: If there are multiple overprint characters, * they all get piled on top of one another. */ ENHsvg_FLUSH(); fprintf(gpoutfile, "", 0.5 * ENHsvg_charcount, ENHsvg_base-base); ENHsvg_base = base; ENHsvg_x_offset = 0.0; enhanced_cur_text = enhanced_text; ENHsvg_charcount = 0; ENHsvg_opened_string = TRUE; break; case 3: ENHsvg_charcount = 0; return; case 4: /* Defer setting the offsets until the text arrives */ ENHsvg_x_offset = -0.5 * ENHsvg_charcount; ENHsvg_base -= base; ENHsvg_charcount = 0; return; default: break; } if (!ENHsvg_opened_string) { ENHsvg_opened_string = TRUE; enhanced_cur_text = enhanced_text; /* Start a new textspan fragment */ fputs("", gpoutfile); } } TERM_PUBLIC void ENHsvg_FLUSH() { if (ENHsvg_opened_string) { ENHsvg_opened_string = FALSE; *enhanced_cur_text = '\0'; fprintf(gpoutfile, "%s", enhanced_text); } } TERM_PUBLIC void ENHsvg_put_text(unsigned int x, unsigned int y, const char *str) { /* We need local copies of the starting font properties */ double fontsize = SVG_fontSizeCur; static char *fontname = NULL; free(fontname); fontname = gp_strdup(SVG_fontNameCur); /* We need the full set of tags for text, just as normal. But in */ /* the case of enhanced text ENHsvg_string_state == 1 tells the */ /* SVG_put_text() to return without actually putting the text. */ if (ignore_enhanced_text) { ENHsvg_string_state = 0; SVG_put_text(x, y, str); return; } else { ENHsvg_string_state = 1; SVG_put_text(x, y, str); ENHsvg_string_state = 0; } /* EAM FIXME - This is a total hack, to make up for the fact that all */ /* svg viewers I have tried fail to pick up the xml:space setting from */ /* the environment. So it has to be set all over again for each text */ /* fragment. Without this, all whitespace is collapsed to a single ' '.*/ if (strstr(str," ")) ENHsvg_preserve_spaces = TRUE; /* Set up global variables needed by enhanced_recursion() */ ENHsvg_charcount = 0; enhanced_fontscale = 1.0; strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format)); while (*(str = enhanced_recursion((char *)str, TRUE, fontname, fontsize, 0.0, TRUE, TRUE, 0))) { (term->enhanced_flush)(); enh_err_check(str); if (!*++str) break; /* end of string */ } /* Make sure we leave with the same font properties as on entry */ free(SVG_fontNameCur); SVG_fontNameCur = fontname; fontname = NULL; if (SVG_fontSizeCur != fontsize || ENHsvg_base != 0) { fprintf(gpoutfile, "", fontsize * SVG_fontscale, ENHsvg_base); SVG_fontSizeCur = fontsize; ENHsvg_base = 0; } ENHsvg_preserve_spaces = FALSE; /* Close the text section */ fputs("\n\t\n", gpoutfile); return; } TERM_PUBLIC void ENHsvg_writec(int c) { /* Kludge for phantom box accounting */ ENHsvg_charcount++; /* Escape SVG reserved characters. Are there any besides '<' and '&' ? */ switch (c) { case '<': *enhanced_cur_text++ = '&'; *enhanced_cur_text++ = 'l'; *enhanced_cur_text++ = 't'; *enhanced_cur_text++ = ';'; break; case '&': *enhanced_cur_text++ = '&'; *enhanced_cur_text++ = 'a'; *enhanced_cur_text++ = 'm'; *enhanced_cur_text++ = 'p'; *enhanced_cur_text++ = ';'; break; case '\n': *enhanced_cur_text++ = '\\'; *enhanced_cur_text++ = 'n'; break; case '\376': /* This is an illegal UTF-8 byte; we use it to escape the reserved '&' */ if (encoding == S_ENC_DEFAULT) { *enhanced_cur_text++ = '&'; break; } /* else fall through */ default: *enhanced_cur_text++ = c; break; } /* Split output stream into chunks rather than overflow the buffer */ if ((enhanced_cur_text - enhanced_text) >= sizeof(enhanced_text)-1) ENHsvg_FLUSH(); } TERM_PUBLIC void SVG_path(int p) { switch (p) { case 1: /* Close path */ fputs("Z ", gpoutfile); SVG_PathClose(); break; case 0: break; } } TERM_PUBLIC void SVG_hypertext( int type, const char *text ) { if (type != TERM_HYPERTEXT_TOOLTIP && type != TERM_HYPERTEXT_TITLE) return; free(SVG_hypertext_text); if (text) { char *buffer = gp_alloc(2+5*strlen(text),"escape"); enhanced_cur_text = buffer; do { ENHsvg_writec(*text); } while (*text++); SVG_hypertext_text = gp_strdup(buffer); enhanced_cur_text = NULL; free(buffer); } else { SVG_hypertext_text = NULL; } } #ifdef EAM_BOXED_TEXT TERM_PUBLIC void SVG_boxed_text(unsigned int x, unsigned int y, int option) { switch (option) { case TEXTBOX_INIT: /* Mark group containing next text item */ SVG_inTextBox = TRUE; break; case TEXTBOX_OUTLINE: /* Stroke the outline of the bounding box (FIXME: how???) */ case TEXTBOX_BACKGROUNDFILL: /* Close the group, which will trigger application of the filter */ SVG_inTextBox = FALSE; break; case TEXTBOX_MARGINS: /* Adjust the size of the bounding box */ break; } } #endif #undef Y #undef X #undef PREC #endif /* TERM_BODY */ #ifdef TERM_TABLE TERM_TABLE_START (svg_driver) "svg", "W3C Scalable Vector Graphics", 0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ , 0 /* vtic */ , 0 /* htic */ , SVG_options, SVG_init, SVG_reset, SVG_text, null_scale, SVG_graphics, SVG_move, SVG_vector, SVG_linetype, SVG_put_text, SVG_text_angle, SVG_justify_text, SVG_point, do_arrow, SVG_set_font, do_pointsize, TERM_CAN_DASH | TERM_ALPHA_CHANNEL|TERM_LINEWIDTH, 0 /* suspend */, 0 /* resume */ , SVG_fillbox, SVG_linewidth #ifdef USE_MOUSE , 0, 0, 0, 0, 0 /* no mouse support for svg */ #endif , SVG_make_palette, SVG_previous_palette, SVG_set_color, SVG_filled_polygon #ifdef WRITE_PNG_IMAGE , SVG_image #else , NULL /* image */ #endif , ENHsvg_OPEN, ENHsvg_FLUSH, ENHsvg_writec , SVG_layer /* layer */ , SVG_path /* path */ , SVG_SCALE /* pixel oversampling scale */ , SVG_hypertext /* hypertext support */ #ifdef EAM_BOXED_TEXT , SVG_boxed_text /* boxed text labels */ #endif , NULL /* modify_plots */ , SVG_dashtype /* Version 5 dashtype support */ TERM_TABLE_END (svg_driver) #undef LAST_TERM #define LAST_TERM svg_driver TERM_TABLE_START (domterm_driver) "domterm", "DomTerm terminal emulator with embedded SVG", 0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ , 0 /* vtic */ , 0 /* htic */ , SVG_options, SVG_init, SVG_reset, SVG_text, null_scale, SVG_graphics, SVG_move, SVG_vector, SVG_linetype, SVG_put_text, SVG_text_angle, SVG_justify_text, SVG_point, do_arrow, SVG_set_font, do_pointsize, TERM_CAN_DASH | TERM_ALPHA_CHANNEL|TERM_LINEWIDTH, 0 /* suspend */, 0 /* resume */ , SVG_fillbox, SVG_linewidth #ifdef USE_MOUSE , 0, 0, 0, 0, 0 /* no mouse support for svg */ #endif , SVG_make_palette, SVG_previous_palette, SVG_set_color, SVG_filled_polygon #ifdef WRITE_PNG_IMAGE , SVG_image #else , NULL /* image */ #endif , ENHsvg_OPEN, ENHsvg_FLUSH, ENHsvg_writec , SVG_layer /* layer */ , SVG_path /* path */ , SVG_SCALE /* pixel oversampling scale */ , SVG_hypertext /* hypertext support */ #ifdef EAM_BOXED_TEXT , SVG_boxed_text /* boxed text labels */ #endif , NULL /* modify_plots */ , SVG_dashtype /* Version 5 dashtype support */ TERM_TABLE_END (domterm_driver) #undef LAST_TERM #define LAST_TERM domterm_driver #endif /* TERM_TABLE */ #endif /* TERM_PROTO_ONLY */ #ifdef TERM_HELP START_HELP(svg) "1 svg", "?commands set terminal svg", "?set terminal svg", "?set term svg", "?terminal svg", "?term svg", "?svg", " This terminal produces files in the W3C Scalable Vector Graphics format.", "", " Syntax:", " set terminal svg {size , {|fixed|dynamic}}", " {mouse} {standalone | jsdir }", " {name }", " {font \"{,}\"} {{no}enhanced}", " {fontscale }", " {rounded|butt|square} {solid|dashed} {linewidth }", " {background }", "", " where and are the size of the SVG plot to generate,", " `dynamic` allows a svg-viewer to resize plot, whereas the default", " setting, `fixed`, will request an absolute size.", "", " `linewidth ` increases the width of all lines used in the figure", " by a factor of .", "", " is the name of the default font to use (default Arial) and", " is the font size (in points, default 12). SVG viewing", " programs may substitute other fonts when the file is displayed.", "", " The enhanced text mode syntax is shared with other gnuplot terminal types.", " See `enhanced` for more details.", "", " The `mouse` option tells gnuplot to add support for mouse tracking and for", " toggling individual plots on/off by clicking on the corresponding key entry.", " By default this is done by including a link that points to a script in a", " local directory, usually /usr/local/share/gnuplot//js.", " You can change this by using the `jsdir` option to specify either a", " different local directory or a general URL. The latter is usually", " appropriate if you are embedding the svg into a web page.", " Alternatively, the `standalone` option embeds the mousing code in the svg", " document itself rather than linking to an external resource.", "", " When an SVG file will be used in conjunction with external files,", " e.g. if it is referenced by javascript code in a web page or parent document,", " then a unique name is required to avoid potential conflicting references", " to other SVG plots. Use the `name` option to ensure uniqueness.", "" END_HELP(svg) START_HELP(domterm) "1 domterm", "?set terminal domterm", "?terminal domterm", "?set term domterm", "?term domterm", "?domterm", " The `domterm` terminal device runs on the DomTerm terminal emulator", " including the domterm and qtdomterm programs.", " It supports SVG graphics embedded directly in the terminal output.", " See http://domterm.org .", "", " Please read the help for the `svg` terminal.", "" END_HELP(domterm) #endif /* TERM_HELP */