]> granicus.if.org Git - graphviz/commitdiff
adding unfinished plugins for remaining codegens - not included in binary distros yet
authorellson <devnull@localhost>
Wed, 3 Oct 2007 18:57:37 +0000 (18:57 +0000)
committerellson <devnull@localhost>
Wed, 3 Oct 2007 18:57:37 +0000 (18:57 +0000)
plugin/core/gvrender_core_dia.c [new file with mode: 0644]
plugin/core/gvrender_core_hpgl.c [new file with mode: 0644]
plugin/core/gvrender_core_mif.c [new file with mode: 0644]
plugin/core/gvrender_core_mp.c [new file with mode: 0644]
plugin/core/gvrender_core_pic.c [new file with mode: 0644]
plugin/core/gvrender_core_tk.c [new file with mode: 0644]
plugin/core/gvrender_core_vtx.c [new file with mode: 0644]

diff --git a/plugin/core/gvrender_core_dia.c b/plugin/core/gvrender_core_dia.c
new file mode 100644 (file)
index 0000000..d63fbeb
--- /dev/null
@@ -0,0 +1,916 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+
+typedef enum { FORMAT_DIA, } format_type;
+
+extern char *xml_string(char *str);
+
+/* DIA font modifiers */
+#define REGULAR 0
+#define BOLD   1
+#define ITALIC 2
+
+/* DIA patterns */
+#define P_SOLID        0
+#define P_NONE  15
+#define P_DOTTED 4             /* i wasn't sure about this */
+#define P_DASHED 11            /* or this */
+
+/* DIA bold line constant */
+#define WIDTH_NORMAL 1
+#define WIDTH_BOLD 3
+
+#define DIA_RESOLUTION 1.0
+#define SCALE (DIA_RESOLUTION/15.0)
+
+static double Scale;
+static pointf Offset;
+static int Rot;
+static box PB;
+static int onetime = TRUE;
+
+typedef struct context_t {
+    char *pencolor, *fillcolor, *fontfam, fontopt, font_was_set;
+    char pen, fill, penwidth, style_was_set;
+    double fontsz;
+} context_t;
+
+#define MAXNEST 4
+static context_t cstk[MAXNEST];
+static int SP;
+
+#define SVG_COLORS_P 0
+
+static int dia_comparestr(const void *s1, const void *s2)
+{
+        return strcmp(*(char **) s1, *(char **) s2);
+}
+
+static char *dia_resolve_color(char *name)
+{
+/* color names from http://www.w3.org/TR/SVG/types.html */
+/* NB.  List must be LANG_C sorted */
+    static char *svg_known_colors[] = {
+        "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
+        "beige", "bisque", "black", "blanchedalmond", "blue",
+        "blueviolet", "brown", "burlywood",
+        "cadetblue", "chartreuse", "chocolate", "coral",
+        "cornflowerblue", "cornsilk", "crimson", "cyan",
+        "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
+        "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
+        "darkolivegreen", "darkorange", "darkorchid", "darkred",
+        "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
+        "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
+        "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
+        "firebrick", "floralwhite", "forestgreen", "fuchsia",
+        "gainsboro", "ghostwhite", "gold", "goldenrod", "gray",
+        "green", "greenyellow", "grey",
+        "honeydew", "hotpink", "indianred",
+        "indigo", "ivory", "khaki",
+        "lavender", "lavenderblush", "lawngreen", "lemonchiffon",
+        "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
+        "lightgray", "lightgreen", "lightgrey", "lightpink",
+        "lightsalmon", "lightseagreen", "lightskyblue",
+        "lightslategray", "lightslategrey", "lightsteelblue",
+        "lightyellow", "lime", "limegreen", "linen",
+        "magenta", "maroon", "mediumaquamarine", "mediumblue",
+        "mediumorchid", "mediumpurple", "mediumseagreen",
+        "mediumslateblue", "mediumspringgreen", "mediumturquoise",
+        "mediumvioletred", "midnightblue", "mintcream",
+        "mistyrose", "moccasin",
+        "navajowhite", "navy", "oldlace",
+        "olive", "olivedrab", "orange", "orangered", "orchid",
+        "palegoldenrod", "palegreen", "paleturquoise",
+        "palevioletred", "papayawhip", "peachpuff", "peru", "pink",
+        "plum", "powderblue", "purple",
+        "red", "rosybrown", "royalblue",
+        "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell",
+        "sienna", "silver", "skyblue", "slateblue", "slategray",
+        "slategrey", "snow", "springgreen", "steelblue",
+        "tan", "teal", "thistle", "tomato", "turquoise",
+        "violet",
+        "wheat", "white", "whitesmoke",
+        "yellow", "yellowgreen",
+    };
+
+    static char buf[SMALLBUF];
+    char *tok;
+    gvcolor_t color;
+
+//    tok = canontoken(name);
+tok = name;
+    if (!SVG_COLORS_P || (bsearch(&tok, svg_known_colors,
+                              sizeof(svg_known_colors) / sizeof(char *),
+                              sizeof(char *), dia_comparestr) == NULL)) {
+        /* if tok was not found in known_colors */
+        if (streq(tok, "transparent")) {
+            tok = "none";
+        } else {
+//            colorxlate(name, &color, RGBA_BYTE);
+            sprintf(buf, "#%02x%02x%02x",
+                    color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
+            tok = buf;
+        }
+    }
+    return tok;
+}
+
+
+static void dia_reset(void)
+{
+    onetime = TRUE;
+}
+
+
+static void init_dia(void)
+{
+    SP = 0;
+    cstk[0].pencolor = DEFAULT_COLOR;  /* DIA pencolor */
+    cstk[0].fillcolor = "";    /* DIA fillcolor */
+    cstk[0].fontfam = DEFAULT_FONTNAME;        /* font family name */
+    cstk[0].fontsz = DEFAULT_FONTSIZE; /* font size */
+    cstk[0].fontopt = REGULAR; /* modifier: REGULAR, BOLD or ITALIC */
+    cstk[0].pen = P_SOLID;     /* pen pattern style, default is solid */
+    cstk[0].fill = P_NONE;
+    cstk[0].penwidth = WIDTH_NORMAL;
+}
+
+static pointf dia_pt(pointf p)
+{
+    pointf rv;
+
+    if (Rot == 0) {
+       rv.x = PB.LL.x + p.x * Scale + Offset.x;
+       rv.y = PB.UR.y - 1 - p.y * Scale - Offset.y;
+    } else {
+       rv.x = PB.UR.x - 1 - p.y * Scale - Offset.x;
+       rv.y = PB.UR.y - 1 - p.x * Scale - Offset.y;
+    }
+    return rv;
+}
+
+static void dia_style(GVJ_t * job, context_t * cp)
+{
+    if (cp->pencolor != DEFAULT_COLOR) {
+       gvdevice_fputs(job, "      <dia:attribute name=\"border_color\">\n");
+       gvdevice_printf(job, "        <dia:color val=\"%s\"/>\n",
+                  dia_resolve_color(cp->pencolor));
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+    }
+    if (cp->penwidth != WIDTH_NORMAL) {
+       gvdevice_fputs(job, "      <dia:attribute name=\"line_width\">\n");
+       gvdevice_printf(job, "        <dia:real val=\"%g\"/>\n",
+                  Scale * (cp->penwidth));
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+    }
+    if (cp->pen == P_DASHED) {
+       gvdevice_fputs(job, "      <dia:attribute name=\"line_style\">\n");
+       gvdevice_printf(job, "        <dia:real val=\"%d\"/>\n", 1);
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+#if 0
+    } else if (cp->pen == P_DOTTED) {
+       gvdevice_printf(job, "stroke-dasharray:%s;", sdotarray);
+#endif
+    }
+}
+
+static void dia_stylefill(GVJ_t * job, context_t * cp, int filled)
+{
+    if (filled) {
+       gvdevice_fputs(job, "      <dia:attribute name=\"inner_color\">\n");
+       gvdevice_printf(job, "        <dia:color val=\"%s\"/>\n",
+                  dia_resolve_color(cp->fillcolor));
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+    } else {
+       gvdevice_fputs(job, "      <dia:attribute name=\"show_background\">\n");
+       gvdevice_printf(job, "        <dia:boolean val=\"%s\"/>\n", "true");
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+    }
+}
+
+static void dia_comment(GVJ_t * job, char *str)
+{
+    gvdevice_fputs(job, "<!-- ");
+    gvdevice_fputs(job, xml_string(str));
+    gvdevice_fputs(job, " -->\n");
+}
+
+static void
+dia_begin_job(GVJ_t *job)
+{
+    core_init_compression(job, COMPRESSION_ZLIB);
+    gvdevice_printf(job, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+}
+
+static void dia_end_job(GVJ_t *job)
+{
+    core_fini_compression(job);
+}
+
+static void dia_begin_graph(GVJ_t * job)
+{
+    Rootgraph = g;
+    PB.LL.x = PB.LL.y = 0;
+    PB.UR.x = (bb.UR.x - bb.LL.x + 2 * GD_drawing(g)->margin.x) * SCALE;
+    PB.UR.y = (bb.UR.y - bb.LL.y + 2 * GD_drawing(g)->margin.y) * SCALE;
+    Offset.x = GD_drawing(g)->margin.x * SCALE;
+    Offset.y = GD_drawing(g)->margin.y * SCALE;
+    if (onetime) {
+       init_dia();
+       onetime = FALSE;
+    }
+    dia_fputs
+       ("<dia:diagram xmlns:dia=\"http://www.lysator.liu.se/~alla/dia/\">\n");
+    gvdevice_fputs(job, "  <dia:diagramdata>\n");
+
+    gvdevice_fputs(job, "    <dia:attribute name=\"background\">\n");
+    gvdevice_fputs(job, "      <dia:color val=\"#ffffff\"/>\n");
+    gvdevice_fputs(job, "    </dia:attribute>\n");
+
+    gvdevice_fputs(job, "    <dia:attribute name=\"paper\">\n");
+    gvdevice_fputs(job, "      <dia:composite type=\"paper\">\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"name\">\n");
+    gvdevice_fputs(job, "          <dia:string>#A4#</dia:string>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"tmargin\">\n");
+    gvdevice_fputs(job, "          <dia:real val=\"2.8222\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"bmargin\">\n");
+    gvdevice_fputs(job, "          <dia:real val=\"2.8222\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"lmargin\">\n");
+    gvdevice_fputs(job, "          <dia:real val=\"2.8222\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"rmargin\">\n");
+    gvdevice_fputs(job, "          <dia:real val=\"2.8222\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"is_portrait\">\n");
+    gvdevice_fputs(job, "          <dia:boolean val=\"true\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"scaling\">\n");
+    gvdevice_fputs(job, "          <dia:real val=\"1\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"fitto\">\n");
+    gvdevice_fputs(job, "          <dia:boolean val=\"false\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "      </dia:composite>\n");
+    gvdevice_fputs(job, "    </dia:attribute>\n");
+
+    gvdevice_fputs(job, "    <dia:attribute name=\"grid\">\n");
+    gvdevice_fputs(job, "      <dia:composite type=\"grid\">\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"width_x\">\n");
+    gvdevice_fputs(job, "          <dia:real val=\"1\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"width_y\">\n");
+    gvdevice_fputs(job, "          <dia:real val=\"1\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"visible_x\">\n");
+    gvdevice_fputs(job, "          <dia:int val=\"1\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"visible_y\">\n");
+    gvdevice_fputs(job, "          <dia:int val=\"1\"/>\n");
+    gvdevice_fputs(job, "        </dia:attribute>\n");
+    gvdevice_fputs(job, "      </dia:composite>\n");
+    gvdevice_fputs(job, "    </dia:attribute>\n");
+
+    gvdevice_fputs(job, "    <dia:attribute name=\"guides\">\n");
+    gvdevice_fputs(job, "      <dia:composite type=\"guides\">\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"hguides\"/>\n");
+    gvdevice_fputs(job, "        <dia:attribute name=\"vguides\"/>\n");
+    gvdevice_fputs(job, "      </dia:composite>\n");
+    gvdevice_fputs(job, "    </dia:attribute>\n");
+
+    gvdevice_fputs(job, "  </dia:diagramdata>\n");
+}
+
+static void dia_end_graph(GVJ_t * job)
+{
+    gvdevice_printf(job, "</dia:diagram>\n");
+}
+
+static void
+dia_begin_page(GVJ_t * job)
+{
+    Scale = scale * SCALE;
+    Rot = rot;
+
+    gvdevice_printf(job, "  <dia:layer name=\"Background\" visible=\"true\">\n");
+}
+
+static void dia_end_page(GVJ_t * job)
+{
+    gvdevice_fputs(job, "  </dia:layer>\n");
+}
+
+static void dia_begin_cluster(GVJ_t * job)
+{
+    gvdevice_printf(job, "<dia:group>\n");
+}
+
+static void dia_end_cluster(GVJ_t * job)
+{
+    gvdevice_printf(job, "</dia:group>\n");
+}
+
+static void dia_begin_node(GVJ_t * job)
+{
+    gvdevice_printf(job, "<dia:group>\n");
+}
+
+static void dia_end_node(GVJ_t * job)
+{
+    gvdevice_printf(job, "</dia:group>\n");
+}
+
+static void dia_begin_edge(GVJ_t * job)
+{
+}
+
+static void dia_end_edge(GVJ_t * job)
+{
+}
+
+static void dia_begin_context(void)
+{
+    assert(SP + 1 < MAXNEST);
+    cstk[SP + 1] = cstk[SP];
+    SP++;
+}
+
+static void dia_end_context(void)
+{
+    int psp = SP - 1;
+    assert(SP > 0);
+    /*free(cstk[psp].fontfam); */
+    SP = psp;
+}
+
+static void dia_set_font(char *name, double size)
+{
+    char *p;
+    context_t *cp;
+
+    cp = &(cstk[SP]);
+    cp->font_was_set = TRUE;
+    cp->fontsz = size;
+    p = strdup(name);
+    cp->fontfam = p;
+}
+
+static void dia_set_pencolor(char *name)
+{
+    cstk[SP].pencolor = name;
+}
+
+static void dia_set_fillcolor(char *name)
+{
+    cstk[SP].fillcolor = name;
+}
+
+static void dia_set_style(char **s)
+{
+    char *line, *p;
+    context_t *cp;
+
+    cp = &(cstk[SP]);
+    while ((p = line = *s++)) {
+       if (streq(line, "solid"))
+           cp->pen = P_SOLID;
+       else if (streq(line, "dashed"))
+           cp->pen = P_DASHED;
+       else if (streq(line, "dotted"))
+           cp->pen = P_DOTTED;
+       else if (streq(line, "invis"))
+           cp->pen = P_NONE;
+       else if (streq(line, "bold"))
+           cp->penwidth = WIDTH_BOLD;
+       else if (streq(line, "setlinewidth")) {
+           while (*p)
+               p++;
+           p++;
+           cp->penwidth = atol(p);
+       } else if (streq(line, "filled"))
+           cp->fill = P_SOLID;
+       else if (streq(line, "unfilled"))
+           cp->fill = P_NONE;
+       else {
+           agwarn("dia_set_style: unsupported style %s - ignoring\n",
+                 line);
+       }
+       cp->style_was_set = TRUE;
+    }
+    /* if (cp->style_was_set) dia_style(cp); */
+}
+
+static void dia_textpara(GVJ_t * job, point p, textpara_t * para)
+{
+    int anchor;
+    pointf mp;
+    context_t *cp;
+
+    cp = &(cstk[SP]);
+    switch (para->just) {
+    case 'l':
+       anchor = 0;
+       break;
+    case 'r':
+       anchor = 2;
+       break;
+    default:
+    case 'n':
+       anchor = 1;
+       break;
+    }
+
+    mp = dia_pt(p);
+    gvdevice_printf(job,
+       "    <dia:object type=\"Standard - Text\" version=\"0\" id=\"%s\">\n",
+        "0");
+    gvdevice_fputs(job, "      <dia:attribute name=\"text\">\n");
+    gvdevice_fputs(job, "        <dia:composite type=\"text\">\n");
+    gvdevice_fputs(job, "          <dia:attribute name=\"string\">\n");
+    gvdevice_fputs(job, "            <dia:string>#");
+    gvdevice_fputs(job, xml_string(para->str));
+    gvdevice_fputs(job, "#</dia:string>\n");
+    gvdevice_fputs(job, "          </dia:attribute>\n");
+    gvdevice_fputs(job, "          <dia:attribute name=\"font\">\n");
+    gvdevice_printf(job, "            <dia:font name=\"%s\"/>\n", cp->fontfam);
+    gvdevice_fputs(job, "          </dia:attribute>\n");
+    gvdevice_fputs(job, "          <dia:attribute name=\"height\">\n");
+    gvdevice_printf(job, "            <dia:real val=\"%g\"/>\n",
+              Scale * (cp->fontsz));
+    gvdevice_fputs(job, "          </dia:attribute>\n");
+    gvdevice_fputs(job, "          <dia:attribute name=\"pos\">\n");
+    gvdevice_printf(job, "            <dia:point val=\"%g,%g\"/>\n", mp.x, mp.y);
+    gvdevice_fputs(job, "          </dia:attribute>\n");
+    gvdevice_fputs(job, "          <dia:attribute name=\"color\">\n");
+    gvdevice_printf(job, "            <dia:color val=\"%s\"/>\n",
+              dia_resolve_color(cp->pencolor));
+    gvdevice_fputs(job, "          </dia:attribute>\n");
+    gvdevice_fputs(job, "          <dia:attribute name=\"alignment\">\n");
+    gvdevice_printf(job, "            <dia:enum val=\"%d\"/>\n", anchor);
+    gvdevice_fputs(job, "          </dia:attribute>\n");
+    gvdevice_fputs(job, "        </dia:composite>\n");
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_pos\">\n");
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", mp.x, mp.y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_bb\">\n");
+    gvdevice_printf(job, "        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+              mp.x - (Scale * (para->width) / 2.), mp.y - 0.4,
+              mp.x + (Scale * (para->width) / 2.), mp.y + 0.4);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "    </dia:object>\n");
+}
+
+static void dia_ellipse(GVJ_t * job, pointf *A, int filled)
+{
+    pointf cp, rp;
+    int nodeId;
+
+    switch (Obj) {
+    case NODE:
+       nodeId = Curnode->id;
+       break;
+    default:
+       nodeId = -1;
+       break;
+    }
+
+    if (cstk[SP].pen == P_NONE) {
+       /* its invisible, don't draw */
+       return;
+    }
+    cp = dia_pt(p);
+
+    if (Rot) {
+       int t;
+       t = rx;
+       rx = ry;
+       ry = t;
+    }
+    rp.x = Scale * rx;
+    rp.y = Scale * ry;
+
+    gvdevice_printf(job,
+       "    <dia:object type=\"Standard - Ellipse\" version=\"0\" id=\"%d\">\n",
+        nodeId);
+    gvdevice_fputs(job, "      <dia:attribute name=\"elem_corner\">\n");
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", cp.x - rp.x,
+              cp.y - rp.y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"elem_width\">\n");
+    gvdevice_printf(job, "        <dia:real val=\"%g\"/>\n", rp.x + rp.x);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"elem_height\">\n");
+    gvdevice_printf(job, "        <dia:real val=\"%g\"/>\n", rp.y + rp.y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_pos\">\n");
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", cp.x - rp.x,
+              cp.y - rp.y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_bb\">\n");
+    gvdevice_printf(job, "        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+              cp.x - rp.x - .11, cp.y - rp.y - .11, cp.x + rp.x + .11,
+              cp.y + rp.y + .11);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    dia_style(job, &cstk[SP]);
+    dia_stylefill(job, &cstk[SP], filled);
+    gvdevice_fputs(job, "    </dia:object>\n");
+}
+
+
+int ellipse_connection(pointf cp, pointf p)
+{
+    int conn = 0;
+
+    if (cp.x == p.x) {
+       if (cp.y > p.y)
+           conn = 1;
+       else
+           conn = 6;
+    } else if (cp.y == p.y) {
+       if (cp.x > p.x)
+           conn = 3;
+       else
+           conn = 4;
+    } else if (cp.x < p.x) {
+       if (cp.y < p.y)
+           conn = 7;
+       else
+           conn = 2;
+    } else if (cp.x > p.x) {
+       if (cp.y < p.y)
+           conn = 5;
+       else
+           conn = 0;
+    }
+
+    return conn;
+}
+
+
+int box_connection(node_t * n, pointf p)
+{
+    int i = 0, j, sides, conn = 0, peripheries, z;
+    double xsize, ysize, mindist2 = 0.0, dist2;
+    polygon_t *poly;
+    pointf P, *vertices;
+    static point *A;
+    static int A_size;
+
+    poly = (polygon_t *) ND_shape_info(n);
+    vertices = poly->vertices;
+    sides = poly->sides;
+    peripheries = poly->peripheries;
+
+    if (A_size < sides) {
+       A_size = sides + 5;
+       A = malloc(A_size*sizeof(pointf));
+    }
+
+    xsize = ((ND_lw_i(n) + ND_rw_i(n)) / POINTS(ND_width(n))) * 16.0;
+    ysize = ((ND_ht_i(n)) / POINTS(ND_height(n))) * 16.0;
+
+    for (j = 0; j < peripheries; j++) {
+       for (i = 0; i < sides; i++) {
+           P = vertices[i + j * sides];
+/* simple rounding produces random results around .5 
+ * this trick should clip off the random part. 
+ * (note xsize/ysize prescaled by 16.0 above) */
+           A[i].x = ROUND(P.x * xsize) / 16;
+           A[i].y = ROUND(P.y * ysize) / 16;
+           if (sides > 2) {
+               A[i].x += ND_coord_i(n).x;
+               A[i].y += ND_coord_i(n).y;
+           }
+       }
+    }
+
+    z = 0;
+    while (z < i) {
+       dist2 = DIST2(p, dia_pt(A[z]));
+       if (z == 0) {
+           mindist2 = dist2;
+           conn = 0;
+       }
+       if (dist2 < mindist2) {
+           mindist2 = dist2;
+           conn = 2 * z;
+       }
+       z++;
+    }
+
+    z = 0;
+    while (z < i) {
+       P.x = (dia_pt(A[z]).x + dia_pt(A[z + 1]).x) / 2;
+       P.y = (dia_pt(A[z]).y + dia_pt(A[z + 1]).y) / 2;
+       dist2 = DIST2(p, P);
+       if (dist2 < mindist2) {
+           mindist2 = dist2;
+           conn = 2 * z + 1;
+       }
+       z++;
+    }
+
+    return conn;
+}
+
+
+static void
+dia_bezier(GVJ_t *job, pointf * A, int n, int arrow_at_start, int arrow_at_end, int filled)
+{
+    int i, conn_h, conn_t;
+    pointf p, firstp = { 0, 0 }, llp = {
+    0, 0}, urp = {
+    0, 0};
+    node_t *head, *tail;
+    char *shape_t;
+    pointf cp_h, cp_t;
+
+    if (cstk[SP].pen == P_NONE) {
+       /* its invisible, don't draw */
+       return;
+    }
+
+    gvdevice_printf(job,
+       "    <dia:object type=\"Standard - BezierLine\" version=\"0\" id=\"%s\">\n",
+        "00");
+    gvdevice_fputs(job, "       <dia:attribute name=\"bez_points\">\n");
+    for (i = 0; i < n; i++) {
+       p = dia_pt(A[i]);
+       if (!i)
+           llp = urp = firstp = p;
+       if (p.x < llp.x || p.y < llp.y)
+           llp = p;
+       if (p.x > urp.x || p.y > urp.y)
+           urp = p;
+       gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", p.x, p.y);
+    }
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    dia_style(job, &cstk[SP]);
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_pos\">\n");
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_bb\">\n");
+    gvdevice_printf(job, "        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+              llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    if (!Curedge) return;
+
+    conn_h = conn_t = -1;
+
+    head = Curedge->head;
+    tail = Curedge->tail;
+
+    shape_t = ND_shape(tail)->name;
+
+    /* arrowheads */
+    if (arrow_at_start) {
+       gvdevice_fputs(job, "      <dia:attribute name=\"start_arrow\">\n");
+       gvdevice_fputs(job, "          <dia:enum val=\"3\"/>\n");
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+       gvdevice_fputs(job, "      <dia:attribute name=\"start_arrow_length\">\n");
+       gvdevice_fputs(job, "           <dia:real val=\"0.8\"/>\n");
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+       dia_fputs
+           ("           <dia:attribute name=\"start_arrow_width\">\n");
+       gvdevice_fputs(job, "                   <dia:real val=\"0.8\"/>\n");
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+    }
+    if (arrow_at_end) {
+       gvdevice_fputs(job, "      <dia:attribute name=\"end_arrow\">\n");
+       gvdevice_fputs(job, "          <dia:enum val=\"3\"/>\n");
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+       gvdevice_fputs(job, "      <dia:attribute name=\"end_arrow_length\">\n");
+       gvdevice_fputs(job, "           <dia:real val=\"0.8\"/>\n");
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+       dia_fputs
+           ("           <dia:attribute name=\"end_arrow_width\">\n");
+       gvdevice_fputs(job, "                   <dia:real val=\"0.8\"/>\n");
+       gvdevice_fputs(job, "      </dia:attribute>\n");
+    }
+
+    gvdevice_fputs(job, "      <dia:attribute name=\"conn_endpoints\">\n");
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", dia_pt(A[0]).x,
+              dia_pt(A[0]).y);
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", dia_pt(A[n - 1]).x,
+              dia_pt(A[n - 1]).y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:connections>\n");
+
+    if ((strcmp(shape_t, "ellipse") == 0)
+       || (strcmp(shape_t, "circle") == 0)
+       || (strcmp(shape_t, "doublecircle") == 0)) {
+       cp_h = dia_pt(ND_coord_i(head));
+       if (AG_IS_DIRECTED(Rootgraph))
+           conn_h = ellipse_connection(cp_h, dia_pt(A[n - 1]));
+       else
+           conn_h = ellipse_connection(cp_h, dia_pt(A[0]));
+    } else {
+       if (AG_IS_DIRECTED(Rootgraph))
+           conn_h = box_connection(head, dia_pt(A[n - 1]));
+       else
+           conn_h = box_connection(head, dia_pt(A[0]));
+    }
+
+    if ((strcmp(shape_t, "ellipse") == 0)
+       || (strcmp(shape_t, "circle") == 0)
+       || (strcmp(shape_t, "doublecircle") == 0)) {
+       cp_t = dia_pt(ND_coord_i(tail));
+       if (AG_IS_DIRECTED(Rootgraph))
+           conn_t = ellipse_connection(cp_t, dia_pt(A[0]));
+       else
+           conn_t = ellipse_connection(cp_t, dia_pt(A[n - 1]));
+    } else {
+       if (AG_IS_DIRECTED(Rootgraph))
+           conn_t = box_connection(tail, dia_pt(A[0]));
+       else
+           conn_t = box_connection(tail, dia_pt(A[n - 1]));
+    }
+
+    if (arrow_at_start) {
+       gvdevice_printf(job,
+           "        <dia:connection handle=\"0\" to=\"%d\" connection=\"%d\"/>\n",
+            head->id, conn_h);
+       gvdevice_printf(job,
+           "        <dia:connection handle=\"%d\" to=\"%d\" connection=\"%d\"/>\n",
+            (n - 1), tail->id, conn_t);
+    } else {
+       gvdevice_printf(job,
+           "        <dia:connection handle=\"0\" to=\"%d\" connection=\"%d\"/>\n",
+            tail->id, conn_t);
+       gvdevice_printf(job,
+           "        <dia:connection handle=\"%d\" to=\"%d\" connection=\"%d\"/>\n",
+            (n - 1), head->id, conn_h);
+    }
+
+    gvdevice_fputs(job, "      </dia:connections>\n");
+    gvdevice_fputs(job, "    </dia:object>\n");
+}
+
+
+
+static void dia_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+    int i;
+    pointf p, firstp = { 0, 0 }, llp = {
+    0, 0}, urp = {
+    0, 0};
+
+    if (cstk[SP].pen == P_NONE) {
+       /* its invisible, don't draw */
+       return;
+    }
+
+    switch (Obj) {
+    case NODE:
+       gvdevice_printf(job,
+           "    <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%d\">\n",
+            Curnode->id);
+       break;
+    case EDGE:
+       return;
+       break;
+    case CLST:
+       gvdevice_printf(job,
+           "    <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%s\">\n",
+            Curgraph->name);
+       break;
+    default:
+       gvdevice_printf(job,
+           "    <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%s\">\n",
+            "polygon");
+       break;
+    }
+    gvdevice_fputs(job, "       <dia:attribute name=\"poly_points\">\n");
+    for (i = 0; i < n; i++) {
+       p = dia_pt(A[i]);
+       if (!i)
+           llp = urp = firstp = p;
+       if (p.x < llp.x || p.y < llp.y)
+           llp = p;
+       if (p.x > urp.x || p.y > urp.y)
+           urp = p;
+       gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", p.x, p.y);
+    }
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_pos\">\n");
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_bb\">\n");
+    gvdevice_printf(job, "        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+              llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    dia_style(job, &cstk[SP]);
+    dia_stylefill(job, &cstk[SP], filled);
+    gvdevice_fputs(job, "    </dia:object>\n");
+}
+
+static void dia_polyline(GVJ_t * job, pointf * A, int n)
+{
+    int i;
+    pointf p, firstp = { 0, 0 }, llp = {
+    0, 0}, urp = {
+    0, 0};
+
+    if (cstk[SP].pen == P_NONE) {
+       /* its invisible, don't draw */
+       return;
+    }
+    gvdevice_printf(job,
+       "    <dia:object type=\"Standard - PolyLine\" version=\"0\" id=\"%s\">\n",
+        "0");
+    gvdevice_fputs(job, "      <dia:attribute name=\"poly_points\">\n");
+    for (i = 0; i < n; i++) {
+       p = dia_pt(A[i]);
+       if (!i)
+           llp = urp = firstp = p;
+       if (p.x < llp.x || p.y < llp.y)
+           llp = p;
+       if (p.x > urp.x || p.y > urp.y)
+           urp = p;
+       gvdevice_printf(job, "<dia:point val=\"%g,%g\"/>\n", p.x, p.y);
+    }
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    dia_style(job, &cstk[SP]);
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_pos\">\n");
+    gvdevice_printf(job, "        <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "      <dia:attribute name=\"obj_bb\">\n");
+    gvdevice_printf(job, "        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+              llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
+    gvdevice_fputs(job, "      </dia:attribute>\n");
+    gvdevice_fputs(job, "    </dia:object>\n");
+}
+
+gvrender_engine_t dia_engine = {
+    dia_begin_job, dia_end_job,
+    dia_begin_graph, dia_end_graph,
+    0, /* dia_begin_layer */ 0,        /* dia_end_layer */
+    dia_begin_page, dia_end_page,
+    dia_begin_cluster, dia_end_cluster,
+    0, /* dia_begin_nodes */ 0,        /* dia_end_nodes */
+    0, /* dia_begin_edges */ 0,        /* dia_end_edges */
+    dia_begin_node, dia_end_node,
+    dia_begin_edge, dia_end_edge,
+    0, /* dia_begin_anchor */ 0, /* dia_end_anchor */
+    dia_textpara, dia_resolve_color,
+    dia_ellipse, dia_polygon,
+    dia_bezier, dia_polyline,
+    dia_comment,
+    0,                         /* dia_library_shape */
+};
+
+/* NB.  List must be LANG_C sorted */
+static char *dia_knowncolors[] = {
+    "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t dia_features = {
+    GVDEVICE_BINARY_FORMAT
+    GVDEVICE_COMPRESSED_FORMAT
+      | GVRENDER_Y_GOES_DOWN,  /* flags */
+    DEFAULT_EMBED_MARGIN,      /* default margin - points */
+    4.,                         /* default pad - graph units */
+    {0.,0.},                    /* default page width, height - points */
+    {72.,72.},                 /* default dpi */
+    dia_knowncolors,           /* knowncolors */
+    sizeof(dia_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+    RGBA_BYTE,                 /* color_type */
+};
+
+gvplugin_installed_t gvrender_core_dia_types[] = {
+    {FORMAT_DIA, "dia", -1, &dia_engine, &dia_features},
+    {0, NULL, 0, NULL, NULL}
+};
diff --git a/plugin/core/gvrender_core_hpgl.c b/plugin/core/gvrender_core_hpgl.c
new file mode 100644 (file)
index 0000000..e0edfd9
--- /dev/null
@@ -0,0 +1,540 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_HPGL, } format_type;
+
+static int Depth;
+
+static void hpglptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+    int i;
+    point p;
+
+    for (i = 0; i < n; i++) {
+       PF2P(A[i],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    if (close) {
+       PF2P(A[0],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static char *hpgl_string(char *s)
+{
+    static char *buf = NULL;
+    static int bufsize = 0;
+    int pos = 0;
+    char *p;
+    unsigned char c;
+
+    if (!buf) {
+        bufsize = 64;
+        buf = malloc(bufsize * sizeof(char));
+    }
+
+    p = buf;
+    while ((c = *s++)) {
+        if (pos > (bufsize - 8)) {
+            bufsize *= 2;
+            buf = realloc(buf, bufsize * sizeof(char));
+            p = buf + pos;
+        }
+        if (isascii(c)) {
+            if (c == '\\') {
+                *p++ = '\\';
+                pos++;
+            }
+            *p++ = c;
+            pos++;
+        } else {
+            *p++ = '\\';
+            sprintf(p, "%03o", c);
+            p += 3;
+            pos += 4;
+        }
+    }
+    *p = '\0';
+    return buf;
+}
+
+static int hpglColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+    static int top = 0;
+    static short red[maxColors], green[maxColors], blue[maxColors];
+    int c;
+    int ct = -1;
+    long rd, gd, bd, dist;
+    long mindist = 3 * 255 * 255;       /* init to max poss dist */
+
+    *new = 0;                   /* in case it is not a new color */
+    for (c = 0; c < top; c++) {
+        rd = (long) (red[c] - r);
+        gd = (long) (green[c] - g);
+        bd = (long) (blue[c] - b);
+        dist = rd * rd + gd * gd + bd * bd;
+        if (dist < mindist) {
+            if (dist == 0)
+                return c;       /* Return exact match color */
+            mindist = dist;
+            ct = c;
+        }
+    }
+    /* no exact match.  We now know closest, but first try to allocate exact */
+    if (top++ == maxColors)
+        return ct;              /* Return closest available color */
+    red[c] = r;
+    green[c] = g;
+    blue[c] = b;
+    *new = 1;                   /* flag new color */
+    return c;                   /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *hpglcolor[] = {
+    "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void hpgl_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+    int object_code = 0;        /* always 0 for color */
+    int i, new;
+
+    switch (color->type) {
+       case COLOR_STRING:
+           for (i = 0; hpglcolor[i]; i++) {
+               if (streq(hpglcolor[i], color->u.string)) {
+                   color->u.index = i;
+                   break;
+               }
+           }
+           break;
+       case RGBA_BYTE:
+           i = 32 + hpglColorResolve(&new,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           if (new)
+               gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+                       object_code, i,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           color->u.index = i;
+           break;
+       default:
+           assert(0);  /* internal error */
+    }
+
+    color->type = COLOR_INDEX;
+}
+
+static void hpgl_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+    switch (obj->pen) {
+       case PEN_DASHED: 
+           *line_style = 1;
+           *style_val = 10.;
+           break;
+       case PEN_DOTTED:
+           *line_style = 2;
+           *style_val = 10.;
+           break;
+       case PEN_SOLID:
+       default:
+           *line_style = 0;
+           *style_val = 0.;
+           break;
+    }
+}
+
+static void hpgl_comment(GVJ_t *job, char *str)
+{
+    gvdevice_printf(job, "# %s\n", str);
+}
+
+static void hpgl_begin_graph(GVJ_t * job)
+{
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, "#FIG 3.2\n");
+    gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+       job->common->info[0], job->common->info[1], job->common->info[2]);
+    gvdevice_printf(job, "# For: %s\n", job->common->user);
+    gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+    gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+    gvdevice_fputs(job, "Portrait\n"); /* orientation */
+    gvdevice_fputs(job, "Center\n");   /* justification */
+    gvdevice_fputs(job, "Inches\n");   /* units */
+    gvdevice_fputs(job, "Letter\n");   /* papersize */
+    gvdevice_fputs(job, "100.00\n");   /* magnification % */
+    gvdevice_fputs(job, "Single\n");   /* multiple-page */
+    gvdevice_fputs(job, "-2\n");       /* transparent color (none) */
+    gvdevice_fputs(job, "1200");            /* resolution */
+    gvdevice_fputs(job, " 2\n");       /* coordinate system (upper left) */
+}
+
+static void hpgl_end_graph(GVJ_t * job)
+{
+    gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void hpgl_begin_page(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void hpgl_begin_node(GVJ_t * job)
+{
+    Depth = 1;
+}
+
+static void hpgl_end_node(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void hpgl_begin_edge(GVJ_t * job)
+{
+    Depth = 0;
+}
+
+static void hpgl_end_edge(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void hpgl_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 4;        /* always 4 for text */
+    int sub_type = 0;           /* text justification */
+    int color = obj->pencolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int font = -1;             /* init to xfig's default font */
+    double font_size = para->fontsize * job->zoom;
+    double angle = job->rotation ? (PI / 2.0) : 0.0;
+    int font_flags = 4;                /* PostScript font */
+    double height = 0.0;
+    double length = 0.0;
+
+    if (para->postscript_alias) /* if it is a standard postscript font */
+       font = para->postscript_alias->xfig_code; 
+
+    switch (para->just) {
+    case 'l':
+        sub_type = 0;
+        break;
+    case 'r':
+        sub_type = 2;
+        break;
+    default:
+    case 'n':
+        sub_type = 1;
+        break;
+    }
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+            object_code, sub_type, color, depth, pen_style, font,
+            font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+            hpgl_string(para->str));
+}
+
+static void hpgl_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 1;        /* always 1 for ellipse */
+    int sub_type = 1;           /* ellipse defined by radii */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int direction = 0;
+    double angle = 0.0;
+    int center_x, center_y, radius_x, radius_y;
+    int start_x, start_y, end_x, end_y;
+
+    hpgl_line_style(obj, &line_style, &style_val);
+
+    start_x = center_x = ROUND(A[0].x);
+    start_y = center_y = ROUND(A[0].y);
+    radius_x = ROUND(A[1].x - A[0].x);
+    radius_y = ROUND(A[1].y - A[0].y);
+    end_x = ROUND(A[1].x);
+    end_y = ROUND(A[1].y);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, direction,
+            angle, center_x, center_y, radius_x, radius_y, start_x,
+            start_y, end_x, end_y);
+}
+
+static void hpgl_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+             int arrow_at_end, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 3;        /* always 3 for spline */
+    int sub_type;
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill;
+    double style_val;
+    int cap_style = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+    int i;
+
+    pointf pf, V[4];
+    point p;
+    int j, step;
+    int count = 0;
+    int size;
+
+    char *buffer;
+    char *buf;
+    buffer =
+        malloc((npoints + 1) * (BEZIERSUBDIVISION +
+                                1) * 20 * sizeof(char));
+    buf = buffer;
+
+    hpgl_line_style(obj, &line_style, &style_val);
+
+    if (filled) {
+        sub_type = 5;     /* closed X-spline */
+        area_fill = 20;   /* fully saturated color */
+        fill_color = job->obj->fillcolor.u.index;
+    }
+    else {
+        sub_type = 4;     /* opened X-spline */
+        area_fill = -1;
+        fill_color = 0;
+    }
+    V[3].x = A[0].x;
+    V[3].y = A[0].y;
+    /* Write first point in line */
+    count++;
+    PF2P(A[0], p);
+    size = sprintf(buf, " %d %d", p.x, p.y);
+    buf += size;
+    /* write subsequent points */
+    for (i = 0; i + 3 < n; i += 3) {
+        V[0] = V[3];
+        for (j = 1; j <= 3; j++) {
+            V[j].x = A[i + j].x;
+            V[j].y = A[i + j].y;
+        }
+        for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+            count++;
+            pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+           PF2P(pf, p);
+            size = sprintf(buf, " %d %d", p.x, p.y);
+            buf += size;
+        }
+    }
+
+    gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+            object_code,
+            sub_type,
+            line_style,
+            thickness,
+            pen_color,
+            fill_color,
+            depth,
+            pen_style,
+            area_fill,
+            style_val, cap_style, forward_arrow, backward_arrow, count);
+
+    gvdevice_printf(job, " %s\n", buffer);      /* print points */
+    free(buffer);
+    for (i = 0; i < count; i++) {
+        gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0);   /* -1 on all */
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static void hpgl_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 3;           /* always 3 for polygon */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n + 1;
+
+    hpgl_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    hpglptarray(job, A, n, 1);        /* closed shape */
+}
+
+static void hpgl_polyline(GVJ_t * job, pointf * A, int n)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 1;           /* always 1 for polyline */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = 0;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = 0;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+
+    hpgl_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    hpglptarray(job, A, n, 0);        /* open shape */
+}
+
+gvrender_engine_t hpgl_engine = {
+    0,                         /* hpgl_begin_job */
+    0,                         /* hpgl_end_job */
+    hpgl_begin_graph,
+    hpgl_end_graph,
+    0,                         /* hpgl_begin_layer */
+    0,                         /* hpgl_end_layer */
+    hpgl_begin_page,
+    0,                         /* hpgl_end_page */
+    0,                         /* hpgl_begin_cluster */
+    0,                         /* hpgl_end_cluster */
+    0,                         /* hpgl_begin_nodes */
+    0,                         /* hpgl_end_nodes */
+    0,                         /* hpgl_begin_edges */
+    0,                         /* hpgl_end_edges */
+    hpgl_begin_node,
+    hpgl_end_node,
+    hpgl_begin_edge,
+    hpgl_end_edge,
+    0,                         /* hpgl_begin_anchor */
+    0,                         /* hpgl_end_anchor */
+    hpgl_textpara,
+    hpgl_resolve_color,
+    hpgl_ellipse,
+    hpgl_polygon,
+    hpgl_bezier,
+    hpgl_polyline,
+    hpgl_comment,
+    0,                         /* hpgl_library_shape */
+};
+
+
+/* NB.  List must be LANG_C sorted */
+static char *hpgl_knowncolors[] = {
+    "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t hpgl_features = {
+    EMIT_COLORS
+       | GVRENDER_Y_GOES_DOWN, /* flags */
+    DEFAULT_EMBED_MARGIN,      /* default margin - points */
+    4.,                         /* default pad - graph units */
+    {0.,0.},                    /* default page width, height - points */
+    {1440.,1440.},             /* default dpi */
+        /* FIXME - this default dpi is a very strange number!!!
+         * It was picked to make .png usershapes the right size on my screen.
+         * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+         * (I was expecting 1.3333 which is 96/72, but thats too big.)
+         * Also 1200 is hardcoded in hpgl_begin_graph() instead of using job->dpi 
+          */
+
+        /* It may be TWIPS, i.e. 20 * POINT_PER_INCH 
+         *    but that doesn't explain what the 1200 is? */
+
+    hpgl_knowncolors,          /* knowncolors */
+    sizeof(hpgl_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+    RGBA_BYTE,                 /* color_type */
+    "hpgl",                     /* imageloader for usershapes */
+};
+
+gvplugin_installed_t gvrender_hpgl_types[] = {
+    {FORMAT_HPGL, "hpgl", -1, &hpgl_engine, &hpgl_features},
+    {0, NULL, 0, NULL, NULL}
+};
diff --git a/plugin/core/gvrender_core_mif.c b/plugin/core/gvrender_core_mif.c
new file mode 100644 (file)
index 0000000..05601d4
--- /dev/null
@@ -0,0 +1,375 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "gvcint.h"
+#include "graph.h"
+
+typedef enum { FORMAT_MIF, } format_type;
+
+/* MIF font modifiers */
+#define REGULAR 0
+#define BOLD   1
+#define ITALIC 2
+
+/* MIF patterns */
+#define P_SOLID        0
+#define P_NONE  15
+#define P_DOTTED 4             /* i wasn't sure about this */
+#define P_DASHED 11            /* or this */
+
+/* MIF bold line constant */
+#define WIDTH_NORMAL 1
+#define WIDTH_BOLD 3
+
+static char *FillStr = "<Fill 3>";
+static char *NoFillStr = "<Fill 15>";
+
+static void mif_ptarray(GVJ_t * job, pointf * A, int n)
+{
+    int i;
+
+    gvdevice_printf(job, " <NumPoints %d>\n", n);
+    for (i = 0; i < n; i++)
+       gvdevice_printf(job, " <Point %.2f %.2f>\n", A[i].x, A[i].y);
+}
+
+typedef struct {
+    char *name;
+    int CMYK[4];
+} mif_color_t;
+
+static mif_color_t mif_colors[] = {
+    {"Black", {0, 0, 0, 100}},
+    {"White", {0, 0, 0, 0}},
+    {"Red", {0, 100, 100, 0}},
+    {"Green", {100, 0, 100, 0}},
+    {"Blue", {100, 100, 0, 0}},
+    {"Cyan", {100, 0, 0, 0}},
+    {"Magenta", {0, 100, 0, 0}},
+    {"Yellow", {0, 0, 100, 0}},
+    {"aquamarine", {100, 0, 0, 18}},
+    {"plum", {0, 100, 0, 33}},
+    {"peru", {0, 24, 100, 32}},
+    {"pink", {0, 50, 0, 0}},
+    {"mediumpurple", {10, 100, 0, 0}},
+    {"grey", {0, 0, 0, 50}},
+    {"lightgrey", {0, 0, 0, 25}},
+    {"lightskyblue", {38, 33, 0, 0}},
+    {"lightcoral", {0, 50, 60, 0}},
+    {"yellowgreen", {31, 0, 100, 0}},
+};
+
+static void mif_color(GVJ_t * job, int i)
+{
+    if (isupper(mif_colors[i].name[0]))
+       gvdevice_printf(job, "<Separation %d>\n", i);
+    else
+       gvdevice_printf(job, "<ObColor `%s'>\n", mif_colors[i].name);
+}
+
+#if 0
+static void mif_style(GVJ_t * job, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, "style=\"fill:");
+    if (filled)
+       mif_color(job->obj->fillcolor);
+    else
+        gvdevice_fputs(job, "none");
+
+    gvdevice_fputs(job, ";stroke:");
+     
+
+
+    while ((line = *s++)) {
+       if (streq(line, "solid"))
+           pen = P_SOLID;
+       else if (streq(line, "dashed"))
+           pen = P_DASHED;
+       else if (streq(line, "dotted"))
+           pen = P_DOTTED;
+       else if (streq(line, "invis"))
+           pen = P_NONE;
+       else if (streq(line, "bold"))
+           penwidth = WIDTH_BOLD;
+       else if (streq(line, "filled"))
+           fill = P_SOLID;
+       else if (streq(line, "unfilled"))
+           fill = P_NONE;
+       else {
+           agerr(AGERR,
+                 "mif_style: unsupported style %s - ignoring\n",
+                 line);
+       }
+    }
+
+    fw = fa = "Regular";
+    switch (cp->fontopt) {
+    case BOLD:
+       fw = "Bold";
+       break;
+    case ITALIC:
+       fa = "Italic";
+       break;
+    }
+    gvdevice_printf(job, 
+           "<Font <FFamily `%s'> <FSize %.1f pt> <FWeight %s> <FAngle %s>>\n",
+           cp->fontfam, job->scale.x * cp->fontsz, fw, fa);
+
+    gvdevice_printf(job, "<Pen %d> <Fill %d> <PenWidth %d>\n",
+           job->pen, job->fill, job->penwidth);
+}
+#endif
+
+static void mif_comment(GVJ_t * job, char *str)
+{
+    gvdevice_printf(job, "# %s\n", str);
+}
+
+static void mif_color_declaration(GVJ_t * job, char *str, int CMYK[4])
+{
+    gvdevice_fputs(job, " <Color \n");
+    gvdevice_printf(job, "  <ColorTag `%s'>\n", str);
+    gvdevice_printf(job, "  <ColorCyan  %d.000000>\n", CMYK[0]);
+    gvdevice_printf(job, "  <ColorMagenta  %d.000000>\n", CMYK[1]);
+    gvdevice_printf(job, "  <ColorYellow  %d.000000>\n", CMYK[2]);
+    gvdevice_printf(job, "  <ColorBlack  %d.000000>\n", CMYK[3]);
+    if (isupper(str[0])) {
+        gvdevice_printf(job, "  <ColorAttribute ColorIs%s>\n", str);
+        gvdevice_fputs(job, "  <ColorAttribute ColorIsReserved>\n");
+    }
+    gvdevice_fputs(job, " > # end of Color\n");
+}
+
+static void
+mif_begin_job(GVJ_t * job)
+{
+    gvdevice_init_compression(job, COMPRESSION_NONE);
+    gvdevice_printf(job,
+       "<MIFFile 3.00> # Generated by %s version %s (%s)\n",
+       job->common->info[0], job->common->info[1], job->common->info[2]);
+}
+
+static void mif_end_job(GVJ_t * job)
+{
+    gvdevice_fputs(job, "# end of MIFFile\n");
+    gvdevice_fini_compression(job);
+}
+
+static void mif_begin_graph(GVJ_t * job)
+{
+    int i;
+
+    gvdevice_printf(job, "# For: %s\n", job->common->user);
+    gvdevice_printf(job, "# Title: %s\n", job->obj->u.g->name);
+    gvdevice_printf(job, "# Pages: %d\n",
+       job->pagesArraySize.x * job->pagesArraySize.y);
+    gvdevice_fputs(job, "<Units Upt>\n");
+    gvdevice_fputs(job, "<ColorCatalog \n");
+    for (i = 0; i < (sizeof(mif_colors) / sizeof(mif_color_t)); i++)
+       mif_color_declaration(job, mif_colors[i].name, mif_colors[i].CMYK);
+    gvdevice_fputs(job, "> # end of ColorCatalog\n");
+    gvdevice_printf(job, "<BRect %g %g %g %g>\n",
+       job->canvasBox.LL.x,
+       job->canvasBox.UR.y,
+       job->canvasBox.UR.x - job->canvasBox.LL.x,
+       job->canvasBox.UR.y - job->canvasBox.LL.y);
+}
+
+static void
+mif_begin_page(GVJ_t *job)
+{
+    gvdevice_printf(job,
+           " <ArrowStyle <TipAngle 15> <BaseAngle 90> <Length %.1f> <HeadType Filled>>\n",
+           14 * job->scale.x);
+}
+
+static void mif_set_color(GVJ_t * job, char *name)
+{
+    int i;
+
+    for (i = 0; i < (sizeof(mif_colors)/sizeof(mif_color_t)); i++) {
+       if (strcasecmp(mif_colors[i].name, name) == 0)
+           mif_color(job, i);
+    }
+    agerr(AGERR, "color %s not supported in MIF\n", name);
+}
+
+static char *mif_string(GVJ_t * job, char *s)
+{
+    static char *buf = NULL;
+    static int bufsize = 0;
+    int pos = 0;
+    char *p, esc;
+
+    if (!buf) {
+       bufsize = 64;
+       buf = malloc(bufsize);
+    }
+
+    p = buf;
+    while (*s) {
+       if (pos > (bufsize - 8)) {
+           bufsize *= 2;
+           buf = realloc(buf, bufsize);
+           p = buf + pos;
+       }
+       esc = 0;
+       switch (*s) {
+       case '\t':
+           esc = 't';
+           break;
+       case '>':
+       case '\'':
+       case '`':
+       case '\\':
+           esc = *s;
+           break;
+       }
+       if (esc) {
+           *p++ = '\\';
+           *p++ = esc;
+           pos += 2;
+       } else {
+           *p++ = *s;
+           pos++;
+       }
+       s++;
+    }
+    *p = '\0';
+    return buf;
+}
+
+static void mif_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+    char *anchor;
+
+//    p.y -= para->font.size / 2 + 2;
+    switch (para->just) {
+    case 'l':
+       anchor = "Left";
+       break;
+    case 'r':
+       anchor = "Right";
+       break;
+    default:
+    case 'n':
+       anchor = "Center";
+       break;
+    }
+    gvdevice_printf(job,
+           "<TextLine <Angle %d> <TLOrigin %.2f %.2f> <TLAlignment %s>",
+           job->rotation, p.x, p.y, anchor);
+    gvdevice_printf(job, " <String `%s'>>\n", mif_string(job, para->str));
+}
+
+static void mif_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+                      int arrow_at_end, int filled)
+{
+    gvdevice_printf(job,
+           "<PolyLine <Fill 15> <Smoothed Yes> <HeadCap Square>\n");
+    mif_ptarray(job, A, n);
+    gvdevice_fputs(job, ">\n");
+}
+
+static void mif_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+    gvdevice_printf(job, "<Polygon %s\n", (filled ? FillStr : NoFillStr));
+    mif_ptarray(job, A, n);
+    gvdevice_fputs(job, ">\n");
+}
+
+static void mif_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+    pointf dia;
+
+    dia.x = (A[1].x - A[0].x) * 2;
+    dia.y = (A[1].y - A[0].y) * 2;
+
+    gvdevice_printf(job, "<Ellipse %s <BRect %.2f %.2f %.1f %.1f>>\n",
+           filled ? FillStr : NoFillStr,
+            A[1].x - dia.x, A[1].y, dia.x, -dia.y);
+}
+
+static void mif_polyline(GVJ_t * job, pointf * A, int n)
+{
+    gvdevice_fputs(job, "<PolyLine <HeadCap Square>\n");
+    mif_ptarray(job, A, n);
+    gvdevice_fputs(job, ">\n");
+}
+
+gvrender_engine_t mif_engine = {
+    mif_begin_job,
+    mif_end_job,
+    mif_begin_graph,
+    0,                         /* mif_end_graph */
+    0,                         /* mif_begin_layer */
+    0,                         /* mif_end_layer */
+    mif_begin_page,
+    0,                         /* mif_end_page */
+    0,                         /* mif_begin_cluster */
+    0,                         /* mif_end_cluster */
+    0,                         /* mif_begin_nodes */
+    0,                         /* mif_end_nodes */
+    0,                         /* mif_begin_edges */
+    0,                         /* mif_end_edges */
+    0,                         /* mif_begin_node */
+    0,                         /* mif_end_node */
+    0,                         /* mif_begin_edge */
+    0,                         /* mif_end_edge */
+    0,                         /* mif_begin_anchor */
+    0,                         /* mif_end_anchor */
+    mif_textpara,
+    0,                                 /* mif_resolve_color */
+    mif_ellipse,
+    mif_polygon,
+    mif_bezier,
+    mif_polyline,
+    mif_comment,
+    0,                         /* mif_library_shape */
+};
+
+gvrender_features_t mif_features = {
+    GVRENDER_Y_GOES_DOWN,      /* flags */
+    DEFAULT_PRINT_MARGIN,      /* default margin - points */
+    4.,                         /* default pad - graph units */
+    {0.,0.},                    /* default page width, height - points */
+    {72.,72.},                 /* default dpi */
+    NULL,                      /* knowncolors */
+    0,                         /* sizeof knowncolors */
+    CMYK_BYTE,                 /* color_type */
+};
+
+gvplugin_installed_t gvrender_mif_types[] = {
+    {FORMAT_MIF, "mif", -1, &mif_engine, &mif_features},
+    {0, NULL, 0, NULL, NULL}
+};
diff --git a/plugin/core/gvrender_core_mp.c b/plugin/core/gvrender_core_mp.c
new file mode 100644 (file)
index 0000000..2b46c1f
--- /dev/null
@@ -0,0 +1,539 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_MP, } format_type;
+
+static int Depth;
+
+static void mpptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+    int i;
+    point p;
+
+    for (i = 0; i < n; i++) {
+       PF2P(A[i],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    if (close) {
+       PF2P(A[0],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static char *mp_string(char *s)
+{
+    static char *buf = NULL;
+    static int bufsize = 0;
+    int pos = 0;
+    char *p;
+    unsigned char c;
+
+    if (!buf) {
+        bufsize = 64;
+        buf = malloc(bufsize * sizeof(char));
+    }
+
+    p = buf;
+    while ((c = *s++)) {
+        if (pos > (bufsize - 8)) {
+            bufsize *= 2;
+            buf = realloc(buf, bufsize * sizeof(char));
+            p = buf + pos;
+        }
+        if (isascii(c)) {
+            if (c == '\\') {
+                *p++ = '\\';
+                pos++;
+            }
+            *p++ = c;
+            pos++;
+        } else {
+            *p++ = '\\';
+            sprintf(p, "%03o", c);
+            p += 3;
+            pos += 4;
+        }
+    }
+    *p = '\0';
+    return buf;
+}
+
+static int mpColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+    static int top = 0;
+    static short red[maxColors], green[maxColors], blue[maxColors];
+    int c;
+    int ct = -1;
+    long rd, gd, bd, dist;
+    long mindist = 3 * 255 * 255;       /* init to max poss dist */
+
+    *new = 0;                   /* in case it is not a new color */
+    for (c = 0; c < top; c++) {
+        rd = (long) (red[c] - r);
+        gd = (long) (green[c] - g);
+        bd = (long) (blue[c] - b);
+        dist = rd * rd + gd * gd + bd * bd;
+        if (dist < mindist) {
+            if (dist == 0)
+                return c;       /* Return exact match color */
+            mindist = dist;
+            ct = c;
+        }
+    }
+    /* no exact match.  We now know closest, but first try to allocate exact */
+    if (top++ == maxColors)
+        return ct;              /* Return closest available color */
+    red[c] = r;
+    green[c] = g;
+    blue[c] = b;
+    *new = 1;                   /* flag new color */
+    return c;                   /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *mpcolor[] = {
+    "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void mp_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+    int object_code = 0;        /* always 0 for color */
+    int i, new;
+
+    switch (color->type) {
+       case COLOR_STRING:
+           for (i = 0; mpcolor[i]; i++) {
+               if (streq(mpcolor[i], color->u.string)) {
+                   color->u.index = i;
+                   break;
+               }
+           }
+           break;
+       case RGBA_BYTE:
+           i = 32 + mpColorResolve(&new,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           if (new)
+               gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+                       object_code, i,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           color->u.index = i;
+           break;
+       default:
+           assert(0);  /* internal error */
+    }
+
+    color->type = COLOR_INDEX;
+}
+
+static void mp_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+    switch (obj->pen) {
+       case PEN_DASHED: 
+           *line_style = 1;
+           *style_val = 10.;
+           break;
+       case PEN_DOTTED:
+           *line_style = 2;
+           *style_val = 10.;
+           break;
+       case PEN_SOLID:
+       default:
+           *line_style = 0;
+           *style_val = 0.;
+           break;
+    }
+}
+
+static void mp_comment(GVJ_t *job, char *str)
+{
+    gvdevice_printf(job, "# %s\n", str);
+}
+
+static void mp_begin_graph(GVJ_t * job)
+{
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, "#FIG 3.2\n");
+    gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+       job->common->info[0], job->common->info[1], job->common->info[2]);
+    gvdevice_printf(job, "# For: %s\n", job->common->user);
+    gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+    gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+    gvdevice_fputs(job, "Portrait\n"); /* orientation */
+    gvdevice_fputs(job, "Center\n");   /* justification */
+    gvdevice_fputs(job, "Inches\n");   /* units */
+    gvdevice_fputs(job, "Letter\n");   /* papersize */
+    gvdevice_fputs(job, "100.00\n");   /* magnification % */
+    gvdevice_fputs(job, "Single\n");   /* multiple-page */
+    gvdevice_fputs(job, "-2\n");       /* transparent color (none) */
+    gvdevice_fputs(job, "1200");            /* resolution */
+    gvdevice_fputs(job, " 2\n");       /* coordinate system (upper left) */
+}
+
+static void mp_end_graph(GVJ_t * job)
+{
+    gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void mp_begin_page(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void mp_begin_node(GVJ_t * job)
+{
+    Depth = 1;
+}
+
+static void mp_end_node(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void mp_begin_edge(GVJ_t * job)
+{
+    Depth = 0;
+}
+
+static void mp_end_edge(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void mp_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 4;        /* always 4 for text */
+    int sub_type = 0;           /* text justification */
+    int color = obj->pencolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int font = -1;             /* init to xfig's default font */
+    double font_size = para->fontsize * job->zoom;
+    double angle = job->rotation ? (PI / 2.0) : 0.0;
+    int font_flags = 4;                /* PostScript font */
+    double height = 0.0;
+    double length = 0.0;
+
+    if (para->postscript_alias) /* if it is a standard postscript font */
+       font = para->postscript_alias->xfig_code; 
+
+    switch (para->just) {
+    case 'l':
+        sub_type = 0;
+        break;
+    case 'r':
+        sub_type = 2;
+        break;
+    default:
+    case 'n':
+        sub_type = 1;
+        break;
+    }
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+            object_code, sub_type, color, depth, pen_style, font,
+            font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+            mp_string(para->str));
+}
+
+static void mp_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 1;        /* always 1 for ellipse */
+    int sub_type = 1;           /* ellipse defined by radii */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int direction = 0;
+    double angle = 0.0;
+    int center_x, center_y, radius_x, radius_y;
+    int start_x, start_y, end_x, end_y;
+
+    mp_line_style(obj, &line_style, &style_val);
+
+    start_x = center_x = ROUND(A[0].x);
+    start_y = center_y = ROUND(A[0].y);
+    radius_x = ROUND(A[1].x - A[0].x);
+    radius_y = ROUND(A[1].y - A[0].y);
+    end_x = ROUND(A[1].x);
+    end_y = ROUND(A[1].y);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, direction,
+            angle, center_x, center_y, radius_x, radius_y, start_x,
+            start_y, end_x, end_y);
+}
+
+static void mp_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+             int arrow_at_end, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 3;        /* always 3 for spline */
+    int sub_type;
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill;
+    double style_val;
+    int cap_style = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+    int i;
+
+    pointf pf, V[4];
+    point p;
+    int j, step;
+    int count = 0;
+    int size;
+
+    char *buffer;
+    char *buf;
+    buffer =
+        malloc((npoints + 1) * (BEZIERSUBDIVISION +
+                                1) * 20 * sizeof(char));
+    buf = buffer;
+
+    mp_line_style(obj, &line_style, &style_val);
+
+    if (filled) {
+        sub_type = 5;     /* closed X-spline */
+        area_fill = 20;   /* fully saturated color */
+        fill_color = job->obj->fillcolor.u.index;
+    }
+    else {
+        sub_type = 4;     /* opened X-spline */
+        area_fill = -1;
+        fill_color = 0;
+    }
+    V[3].x = A[0].x;
+    V[3].y = A[0].y;
+    /* Write first point in line */
+    count++;
+    PF2P(A[0], p);
+    size = sprintf(buf, " %d %d", p.x, p.y);
+    buf += size;
+    /* write subsequent points */
+    for (i = 0; i + 3 < n; i += 3) {
+        V[0] = V[3];
+        for (j = 1; j <= 3; j++) {
+            V[j].x = A[i + j].x;
+            V[j].y = A[i + j].y;
+        }
+        for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+            count++;
+            pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+           PF2P(pf, p);
+            size = sprintf(buf, " %d %d", p.x, p.y);
+            buf += size;
+        }
+    }
+
+    gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+            object_code,
+            sub_type,
+            line_style,
+            thickness,
+            pen_color,
+            fill_color,
+            depth,
+            pen_style,
+            area_fill,
+            style_val, cap_style, forward_arrow, backward_arrow, count);
+
+    gvdevice_printf(job, " %s\n", buffer);      /* print points */
+    free(buffer);
+    for (i = 0; i < count; i++) {
+        gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0);   /* -1 on all */
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static void mp_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 3;           /* always 3 for polygon */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n + 1;
+
+    mp_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    mpptarray(job, A, n, 1);        /* closed shape */
+}
+
+static void mp_polyline(GVJ_t * job, pointf * A, int n)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 1;           /* always 1 for polyline */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = 0;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = 0;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+
+    mp_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    mpptarray(job, A, n, 0);        /* open shape */
+}
+
+gvrender_engine_t mp_engine = {
+    0,                         /* mp_begin_job */
+    0,                         /* mp_end_job */
+    mp_begin_graph,
+    mp_end_graph,
+    0,                         /* mp_begin_layer */
+    0,                         /* mp_end_layer */
+    mp_begin_page,
+    0,                         /* mp_end_page */
+    0,                         /* mp_begin_cluster */
+    0,                         /* mp_end_cluster */
+    0,                         /* mp_begin_nodes */
+    0,                         /* mp_end_nodes */
+    0,                         /* mp_begin_edges */
+    0,                         /* mp_end_edges */
+    mp_begin_node,
+    mp_end_node,
+    mp_begin_edge,
+    mp_end_edge,
+    0,                         /* mp_begin_anchor */
+    0,                         /* mp_end_anchor */
+    mp_textpara,
+    mp_resolve_color,
+    mp_ellipse,
+    mp_polygon,
+    mp_bezier,
+    mp_polyline,
+    mp_comment,
+    0,                         /* mp_library_shape */
+};
+
+
+/* NB.  List must be LANG_C sorted */
+static char *mp_knowncolors[] = {
+    "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t mp_features = {
+    EMIT_COLORS
+       | GVRENDER_Y_GOES_DOWN, /* flags */
+    DEFAULT_EMBED_MARGIN,      /* default margin - points */
+    4.,                         /* default pad - graph units */
+    {0.,0.},                    /* default page width, height - points */
+    {1440.,1440.},             /* default dpi */
+        /* FIXME - this default dpi is a very strange number!!!
+         * It was picked to make .png usershapes the right size on my screen.
+         * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+         * (I was expecting 1.3333 which is 96/72, but thats too big.)
+         * Also 1200 is hardcoded in mp_begin_graph() instead of using job->dpi 
+          */
+
+        /* It may be TWIPS, i.e. 20 * POINT_PER_INCH 
+         *    but that doesn't explain what the 1200 is? */
+
+    mp_knowncolors,            /* knowncolors */
+    sizeof(mp_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+    RGBA_BYTE,                 /* color_type */
+};
+
+gvplugin_installed_t gvrender_mp_types[] = {
+    {FORMAT_MP, "mp", -1, &mp_engine, &mp_features},
+    {0, NULL, 0, NULL, NULL}
+};
diff --git a/plugin/core/gvrender_core_pic.c b/plugin/core/gvrender_core_pic.c
new file mode 100644 (file)
index 0000000..061af3f
--- /dev/null
@@ -0,0 +1,539 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_PIC, } format_type;
+
+static int Depth;
+
+static void picptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+    int i;
+    point p;
+
+    for (i = 0; i < n; i++) {
+       PF2P(A[i],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    if (close) {
+       PF2P(A[0],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static char *pic_string(char *s)
+{
+    static char *buf = NULL;
+    static int bufsize = 0;
+    int pos = 0;
+    char *p;
+    unsigned char c;
+
+    if (!buf) {
+        bufsize = 64;
+        buf = malloc(bufsize * sizeof(char));
+    }
+
+    p = buf;
+    while ((c = *s++)) {
+        if (pos > (bufsize - 8)) {
+            bufsize *= 2;
+            buf = realloc(buf, bufsize * sizeof(char));
+            p = buf + pos;
+        }
+        if (isascii(c)) {
+            if (c == '\\') {
+                *p++ = '\\';
+                pos++;
+            }
+            *p++ = c;
+            pos++;
+        } else {
+            *p++ = '\\';
+            sprintf(p, "%03o", c);
+            p += 3;
+            pos += 4;
+        }
+    }
+    *p = '\0';
+    return buf;
+}
+
+static int picColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+    static int top = 0;
+    static short red[maxColors], green[maxColors], blue[maxColors];
+    int c;
+    int ct = -1;
+    long rd, gd, bd, dist;
+    long mindist = 3 * 255 * 255;       /* init to max poss dist */
+
+    *new = 0;                   /* in case it is not a new color */
+    for (c = 0; c < top; c++) {
+        rd = (long) (red[c] - r);
+        gd = (long) (green[c] - g);
+        bd = (long) (blue[c] - b);
+        dist = rd * rd + gd * gd + bd * bd;
+        if (dist < mindist) {
+            if (dist == 0)
+                return c;       /* Return exact match color */
+            mindist = dist;
+            ct = c;
+        }
+    }
+    /* no exact match.  We now know closest, but first try to allocate exact */
+    if (top++ == maxColors)
+        return ct;              /* Return closest available color */
+    red[c] = r;
+    green[c] = g;
+    blue[c] = b;
+    *new = 1;                   /* flag new color */
+    return c;                   /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *piccolor[] = {
+    "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void pic_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+    int object_code = 0;        /* always 0 for color */
+    int i, new;
+
+    switch (color->type) {
+       case COLOR_STRING:
+           for (i = 0; piccolor[i]; i++) {
+               if (streq(piccolor[i], color->u.string)) {
+                   color->u.index = i;
+                   break;
+               }
+           }
+           break;
+       case RGBA_BYTE:
+           i = 32 + picColorResolve(&new,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           if (new)
+               gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+                       object_code, i,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           color->u.index = i;
+           break;
+       default:
+           assert(0);  /* internal error */
+    }
+
+    color->type = COLOR_INDEX;
+}
+
+static void pic_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+    switch (obj->pen) {
+       case PEN_DASHED: 
+           *line_style = 1;
+           *style_val = 10.;
+           break;
+       case PEN_DOTTED:
+           *line_style = 2;
+           *style_val = 10.;
+           break;
+       case PEN_SOLID:
+       default:
+           *line_style = 0;
+           *style_val = 0.;
+           break;
+    }
+}
+
+static void pic_comment(GVJ_t *job, char *str)
+{
+    gvdevice_printf(job, "# %s\n", str);
+}
+
+static void pic_begin_graph(GVJ_t * job)
+{
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, "#FIG 3.2\n");
+    gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+       job->common->info[0], job->common->info[1], job->common->info[2]);
+    gvdevice_printf(job, "# For: %s\n", job->common->user);
+    gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+    gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+    gvdevice_fputs(job, "Portrait\n"); /* orientation */
+    gvdevice_fputs(job, "Center\n");   /* justification */
+    gvdevice_fputs(job, "Inches\n");   /* units */
+    gvdevice_fputs(job, "Letter\n");   /* papersize */
+    gvdevice_fputs(job, "100.00\n");   /* magnification % */
+    gvdevice_fputs(job, "Single\n");   /* multiple-page */
+    gvdevice_fputs(job, "-2\n");       /* transparent color (none) */
+    gvdevice_fputs(job, "1200");            /* resolution */
+    gvdevice_fputs(job, " 2\n");       /* coordinate system (upper left) */
+}
+
+static void pic_end_graph(GVJ_t * job)
+{
+    gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void pic_begin_page(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void pic_begin_node(GVJ_t * job)
+{
+    Depth = 1;
+}
+
+static void pic_end_node(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void pic_begin_edge(GVJ_t * job)
+{
+    Depth = 0;
+}
+
+static void pic_end_edge(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void pic_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 4;        /* always 4 for text */
+    int sub_type = 0;           /* text justification */
+    int color = obj->pencolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int font = -1;             /* init to xfig's default font */
+    double font_size = para->fontsize * job->zoom;
+    double angle = job->rotation ? (PI / 2.0) : 0.0;
+    int font_flags = 4;                /* PostScript font */
+    double height = 0.0;
+    double length = 0.0;
+
+    if (para->postscript_alias) /* if it is a standard postscript font */
+       font = para->postscript_alias->xfig_code; 
+
+    switch (para->just) {
+    case 'l':
+        sub_type = 0;
+        break;
+    case 'r':
+        sub_type = 2;
+        break;
+    default:
+    case 'n':
+        sub_type = 1;
+        break;
+    }
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+            object_code, sub_type, color, depth, pen_style, font,
+            font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+            pic_string(para->str));
+}
+
+static void pic_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 1;        /* always 1 for ellipse */
+    int sub_type = 1;           /* ellipse defined by radii */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int direction = 0;
+    double angle = 0.0;
+    int center_x, center_y, radius_x, radius_y;
+    int start_x, start_y, end_x, end_y;
+
+    pic_line_style(obj, &line_style, &style_val);
+
+    start_x = center_x = ROUND(A[0].x);
+    start_y = center_y = ROUND(A[0].y);
+    radius_x = ROUND(A[1].x - A[0].x);
+    radius_y = ROUND(A[1].y - A[0].y);
+    end_x = ROUND(A[1].x);
+    end_y = ROUND(A[1].y);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, direction,
+            angle, center_x, center_y, radius_x, radius_y, start_x,
+            start_y, end_x, end_y);
+}
+
+static void pic_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+             int arrow_at_end, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 3;        /* always 3 for spline */
+    int sub_type;
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill;
+    double style_val;
+    int cap_style = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+    int i;
+
+    pointf pf, V[4];
+    point p;
+    int j, step;
+    int count = 0;
+    int size;
+
+    char *buffer;
+    char *buf;
+    buffer =
+        malloc((npoints + 1) * (BEZIERSUBDIVISION +
+                                1) * 20 * sizeof(char));
+    buf = buffer;
+
+    pic_line_style(obj, &line_style, &style_val);
+
+    if (filled) {
+        sub_type = 5;     /* closed X-spline */
+        area_fill = 20;   /* fully saturated color */
+        fill_color = job->obj->fillcolor.u.index;
+    }
+    else {
+        sub_type = 4;     /* opened X-spline */
+        area_fill = -1;
+        fill_color = 0;
+    }
+    V[3].x = A[0].x;
+    V[3].y = A[0].y;
+    /* Write first point in line */
+    count++;
+    PF2P(A[0], p);
+    size = sprintf(buf, " %d %d", p.x, p.y);
+    buf += size;
+    /* write subsequent points */
+    for (i = 0; i + 3 < n; i += 3) {
+        V[0] = V[3];
+        for (j = 1; j <= 3; j++) {
+            V[j].x = A[i + j].x;
+            V[j].y = A[i + j].y;
+        }
+        for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+            count++;
+            pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+           PF2P(pf, p);
+            size = sprintf(buf, " %d %d", p.x, p.y);
+            buf += size;
+        }
+    }
+
+    gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+            object_code,
+            sub_type,
+            line_style,
+            thickness,
+            pen_color,
+            fill_color,
+            depth,
+            pen_style,
+            area_fill,
+            style_val, cap_style, forward_arrow, backward_arrow, count);
+
+    gvdevice_printf(job, " %s\n", buffer);      /* print points */
+    free(buffer);
+    for (i = 0; i < count; i++) {
+        gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0);   /* -1 on all */
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static void pic_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 3;           /* always 3 for polygon */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n + 1;
+
+    pic_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    picptarray(job, A, n, 1);        /* closed shape */
+}
+
+static void pic_polyline(GVJ_t * job, pointf * A, int n)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 1;           /* always 1 for polyline */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = 0;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = 0;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+
+    pic_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    picptarray(job, A, n, 0);        /* open shape */
+}
+
+gvrender_engine_t pic_engine = {
+    0,                         /* pic_begin_job */
+    0,                         /* pic_end_job */
+    pic_begin_graph,
+    pic_end_graph,
+    0,                         /* pic_begin_layer */
+    0,                         /* pic_end_layer */
+    pic_begin_page,
+    0,                         /* pic_end_page */
+    0,                         /* pic_begin_cluster */
+    0,                         /* pic_end_cluster */
+    0,                         /* pic_begin_nodes */
+    0,                         /* pic_end_nodes */
+    0,                         /* pic_begin_edges */
+    0,                         /* pic_end_edges */
+    pic_begin_node,
+    pic_end_node,
+    pic_begin_edge,
+    pic_end_edge,
+    0,                         /* pic_begin_anchor */
+    0,                         /* pic_end_anchor */
+    pic_textpara,
+    pic_resolve_color,
+    pic_ellipse,
+    pic_polygon,
+    pic_bezier,
+    pic_polyline,
+    pic_comment,
+    0,                         /* pic_library_shape */
+};
+
+
+/* NB.  List must be LANG_C sorted */
+static char *pic_knowncolors[] = {
+    "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t pic_features = {
+    EMIT_COLORS
+       | GVRENDER_Y_GOES_DOWN, /* flags */
+    DEFAULT_EMBED_MARGIN,      /* default margin - points */
+    4.,                         /* default pad - graph units */
+    {0.,0.},                    /* default page width, height - points */
+    {1440.,1440.},             /* default dpi */
+        /* FIXME - this default dpi is a very strange number!!!
+         * It was picked to make .png usershapes the right size on my screen.
+         * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+         * (I was expecting 1.3333 which is 96/72, but thats too big.)
+         * Also 1200 is hardcoded in pic_begin_graph() instead of using job->dpi 
+          */
+
+        /* It may be TWIPS, i.e. 20 * POINT_PER_INCH 
+         *    but that doesn't explain what the 1200 is? */
+
+    pic_knowncolors,           /* knowncolors */
+    sizeof(pic_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+    RGBA_BYTE,                 /* color_type */
+};
+
+gvplugin_installed_t gvrender_pic_types[] = {
+    {FORMAT_PIC, "pic", -1, &pic_engine, &pic_features},
+    {0, NULL, 0, NULL, NULL}
+};
diff --git a/plugin/core/gvrender_core_tk.c b/plugin/core/gvrender_core_tk.c
new file mode 100644 (file)
index 0000000..5428328
--- /dev/null
@@ -0,0 +1,336 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "gvcint.h"
+#include "graph.h"
+#include "types.h"             /* need the SVG font name schemes */
+
+/* highlight flag */
+#define HIGHLIGHT 1
+#define NOHIGHLIGHT 0
+
+typedef enum { FORMAT_TK, } format_type;
+
+static char *tkgen_string(char *s)
+{
+    return s;
+}
+
+static void tkgen_print_color(GVJ_t * job, gvcolor_t color)
+{
+    switch (color.type) {
+    case COLOR_STRING:
+       gvdevice_fputs(job, color.u.string);
+       break;
+    case RGBA_BYTE:
+       if (color.u.rgba[3] == 0) /* transparent */
+           gvdevice_fputs(job, "none");
+       else
+           gvdevice_printf(job, "#%02x%02x%02x",
+               color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
+       break;
+    default:
+       assert(0);              /* internal error */
+    }
+}
+
+static void tkgen_print_tags(GVJ_t *job, int tag)
+{
+    char *ObjType;
+    unsigned int ObjHandle;
+    obj_state_t *obj = job->obj;
+
+    switch (obj->emit_state) {
+    case EMIT_NDRAW:
+    case EMIT_NLABEL:
+       ObjType = "node";
+        ObjHandle = obj->u.n->handle;
+       break;
+    case EMIT_EDRAW:
+    case EMIT_TDRAW:
+    case EMIT_HDRAW:
+    case EMIT_ELABEL:
+    case EMIT_TLABEL:
+    case EMIT_HLABEL:
+       ObjType = "edge";
+        ObjHandle = obj->u.e->handle;
+       break;
+    case EMIT_GDRAW:
+    case EMIT_CDRAW:
+    case EMIT_GLABEL:
+    case EMIT_CLABEL:
+       ObjType = "graph";
+        ObjHandle = obj->u.g->handle;
+       break;
+    default:
+       assert (0);
+       break;
+    }
+    gvdevice_printf(job, " -tags %d%s%ld", tag, ObjType, ObjHandle);
+}
+
+
+static void tkgen_grstyle(GVJ_t * job, int filled)
+{
+#if 0
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, " style=\"fill:");
+    if (filled)
+       tkgen_print_color(job, obj->fillcolor);
+    else
+       gvdevice_fputs(job, "none");
+    gvdevice_fputs(job, ";stroke:");
+    tkgen_print_color(job, obj->pencolor);
+    if (obj->penwidth != PENWIDTH_NORMAL)
+       gvdevice_printf(job, ";stroke-width:%g", obj->penwidth);
+    if (obj->pen == PEN_DASHED) {
+       gvdevice_printf(job, ";stroke-dasharray:%s", sdarray);
+    } else if (obj->pen == PEN_DOTTED) {
+       gvdevice_printf(job, ";stroke-dasharray:%s", sdotarray);
+    }
+    gvdevice_fputs(job, ";\"");
+#endif
+}
+
+static void tkgen_comment(GVJ_t * job, char *str)
+{
+    gvdevice_fputs(job, "# ");
+    gvdevice_fputs(job, tkgen_string(str));
+    gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_begin_job(GVJ_t * job)
+{
+    gvdevice_fputs(job, "# Generated by ");
+    gvdevice_fputs(job, tkgen_string(job->common->info[0]));
+    gvdevice_fputs(job, " version ");
+    gvdevice_fputs(job, tkgen_string(job->common->info[1]));
+    gvdevice_fputs(job, " (");
+    gvdevice_fputs(job, tkgen_string(job->common->info[2]));
+    gvdevice_fputs(job, ")\n#     For user: ");
+    gvdevice_fputs(job, tkgen_string(job->common->user));
+    gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_begin_graph(GVJ_t * job)
+{
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, "#");
+    if (obj->u.g->name[0]) {
+        gvdevice_fputs(job, " Title: ");
+       gvdevice_fputs(job, tkgen_string(obj->u.g->name));
+    }
+    gvdevice_printf(job, " Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+}
+
+static void tkgen_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, "$c create text");
+    gvdevice_printf(job, " %d %d", ROUND(p.x), ROUND(p.y));
+    gvdevice_fputs(job, " -text {");
+    gvdevice_fputs(job, para->str);
+    gvdevice_fputs(job, "}");
+    gvdevice_fputs(job, " -fill ");
+    tkgen_print_color(job, obj->pencolor);
+    gvdevice_fputs(job, " -font {");
+    gvdevice_fputs(job, para->fontname);
+    gvdevice_printf(job, " %g}", para->fontsize);
+    switch (para->just) {
+    case 'l':
+        gvdevice_fputs(job, " -anchor w");
+        break;
+    case 'r':
+        gvdevice_fputs(job, " -anchor e");
+        break;
+    default:
+    case 'n':
+        break;
+    }
+    gvdevice_fputs(job, " -state disabled");
+    tkgen_print_tags(job, NOHIGHLIGHT);
+    gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+#if 0
+    /* A[] contains 2 points: the center and corner. */
+    gvdevice_fputs(job, "<ellipse");
+    tkgen_grstyle(job, filled);
+    gvdevice_printf(job, " cx=\"%g\" cy=\"%g\"", A[0].x, -A[0].y);
+    gvdevice_printf(job, " rx=\"%g\" ry=\"%g\"",
+           A[1].x - A[0].x, A[1].y - A[0].y);
+    gvdevice_fputs(job, "/>\n");
+#endif
+}
+
+static void
+tkgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+             int arrow_at_end, int filled)
+{
+#if 0
+    gvdevice_fputs(job, "<path");
+    tkgen_grstyle(job, filled);
+    gvdevice_fputs(job, " d=\"");
+    tkgen_bzptarray(job, A, n);
+    gvdevice_fputs(job, "\"/>\n");
+#endif
+}
+
+static void tkgen_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+    int i;
+
+    gvdevice_fputs(job, "$c create polygon");
+    for (i = 0; i < n; i++)
+       gvdevice_printf(job, " %d %d", ROUND(A[i].x), ROUND(-A[i].y));
+    gvdevice_fputs(job, " -state disabled");
+    tkgen_print_tags(job, NOHIGHLIGHT);
+    gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_polyline(GVJ_t * job, pointf * A, int n)
+{
+#if 0
+    int i;
+
+    gvdevice_fputs(job, "<polyline");
+    tkgen_grstyle(job, 0);
+    gvdevice_fputs(job, " points=\"");
+    for (i = 0; i < n; i++)
+       gvdevice_printf(job, "%g,%g ", A[i].x, -A[i].y);
+    gvdevice_fputs(job, "\"/>\n");
+#endif
+}
+
+/* color names from http://www.w3.org/TR/SVG/types.html */
+/* NB.  List must be LANG_C sorted */
+static char *tkgen_knowncolors[] = {
+    "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
+    "beige", "bisque", "black", "blanchedalmond", "blue",
+    "blueviolet", "brown", "burlywood",
+    "cadetblue", "chartreuse", "chocolate", "coral",
+    "cornflowerblue", "cornsilk", "crimson", "cyan",
+    "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
+    "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
+    "darkolivegreen", "darkorange", "darkorchid", "darkred",
+    "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
+    "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
+    "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
+    "firebrick", "floralwhite", "forestgreen", "fuchsia",
+    "gainsboro", "ghostwhite", "gold", "goldenrod", "gray",
+    "green", "greenyellow", "grey",
+    "honeydew", "hotpink", "indianred",
+    "indigo", "ivory", "khaki",
+    "lavender", "lavenderblush", "lawngreen", "lemonchiffon",
+    "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
+    "lightgray", "lightgreen", "lightgrey", "lightpink",
+    "lightsalmon", "lightseagreen", "lightskyblue",
+    "lightslategray", "lightslategrey", "lightsteelblue",
+    "lightyellow", "lime", "limegreen", "linen",
+    "magenta", "maroon", "mediumaquamarine", "mediumblue",
+    "mediumorchid", "mediumpurple", "mediumseagreen",
+    "mediumslateblue", "mediumspringgreen", "mediumturquoise",
+    "mediumvioletred", "midnightblue", "mintcream",
+    "mistyrose", "moccasin",
+    "navajowhite", "navy", "oldlace",
+    "olive", "olivedrab", "orange", "orangered", "orchid",
+    "palegoldenrod", "palegreen", "paleturquoise",
+    "palevioletred", "papayawhip", "peachpuff", "peru", "pink",
+    "plum", "powderblue", "purple",
+    "red", "rosybrown", "royalblue",
+    "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell",
+    "sienna", "silver", "skyblue", "slateblue", "slategray",
+    "slategrey", "snow", "springgreen", "steelblue",
+    "tan", "teal", "thistle", "tomato", "turquoise",
+    "violet",
+    "wheat", "white", "whitesmoke",
+    "yellow", "yellowgreen"
+};
+
+gvrender_engine_t tkgen_engine = {
+    tkgen_begin_job,
+    0,                         /* tkgen_end_job */
+    tkgen_begin_graph,
+    0,                         /* tkgen_end_graph */
+    0,                                 /* tkgen_begin_layer */
+    0,                                 /* tkgen_end_layer */
+    0,                                 /* tkgen_begin_page */
+    0,                                 /* tkgen_end_page */
+    0,                                 /* tkgen_begin_cluster */
+    0,                                 /* tkgen_end_cluster */
+    0,                         /* tkgen_begin_nodes */
+    0,                         /* tkgen_end_nodes */
+    0,                         /* tkgen_begin_edges */
+    0,                         /* tkgen_end_edges */
+    0,                         /* tkgen_begin_node */
+    0,                         /* tkgen_end_node */
+    0,                         /* tkgen_begin_edge */
+    0,                         /* tkgen_end_edge */
+    0,                         /* tkgen_begin_anchor */
+    0,                         /* tkgen_end_anchor */
+    tkgen_textpara,
+    0,                         /* tkgen_resolve_color */
+    tkgen_ellipse,
+    tkgen_polygon,
+    tkgen_bezier,
+    tkgen_polyline,
+    tkgen_comment,
+    0,                         /* tkgen_library_shape */
+};
+
+gvrender_features_t render_features_tk = {
+    GVRENDER_Y_GOES_DOWN,       /* flags */
+    4.,                         /* default pad - graph units */
+    tkgen_knowncolors,         /* knowncolors */
+    sizeof(tkgen_knowncolors) / sizeof(char *),        /* sizeof knowncolors */
+    RGBA_BYTE,                 /* color_type */
+};
+
+gvdevice_features_t device_features_tk = {
+    0,                         /* flags */
+    {0.,0.},                   /* default margin - points */
+    {0.,0.},                    /* default page width, height - points */
+    {72.,72.},                 /* default dpi */
+};
+
+gvplugin_installed_t gvrender_tk_types[] = {
+    {FORMAT_TK, "tk", 1, &tkgen_engine, &render_features_tk},
+    {0, NULL, 0, NULL, NULL}
+};
+
+gvplugin_installed_t gvdevice_tk_types[] = {
+    {FORMAT_TK, "tk:tk", 1, NULL, &device_features_tk},
+    {0, NULL, 0, NULL, NULL}
+};
diff --git a/plugin/core/gvrender_core_vtx.c b/plugin/core/gvrender_core_vtx.c
new file mode 100644 (file)
index 0000000..0422806
--- /dev/null
@@ -0,0 +1,539 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_VTX, } format_type;
+
+static int Depth;
+
+static void vtxptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+    int i;
+    point p;
+
+    for (i = 0; i < n; i++) {
+       PF2P(A[i],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    if (close) {
+       PF2P(A[0],p);
+        gvdevice_printf(job, " %d %d", p.x, p.y);
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static char *vtx_string(char *s)
+{
+    static char *buf = NULL;
+    static int bufsize = 0;
+    int pos = 0;
+    char *p;
+    unsigned char c;
+
+    if (!buf) {
+        bufsize = 64;
+        buf = malloc(bufsize * sizeof(char));
+    }
+
+    p = buf;
+    while ((c = *s++)) {
+        if (pos > (bufsize - 8)) {
+            bufsize *= 2;
+            buf = realloc(buf, bufsize * sizeof(char));
+            p = buf + pos;
+        }
+        if (isascii(c)) {
+            if (c == '\\') {
+                *p++ = '\\';
+                pos++;
+            }
+            *p++ = c;
+            pos++;
+        } else {
+            *p++ = '\\';
+            sprintf(p, "%03o", c);
+            p += 3;
+            pos += 4;
+        }
+    }
+    *p = '\0';
+    return buf;
+}
+
+static int vtxColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+    static int top = 0;
+    static short red[maxColors], green[maxColors], blue[maxColors];
+    int c;
+    int ct = -1;
+    long rd, gd, bd, dist;
+    long mindist = 3 * 255 * 255;       /* init to max poss dist */
+
+    *new = 0;                   /* in case it is not a new color */
+    for (c = 0; c < top; c++) {
+        rd = (long) (red[c] - r);
+        gd = (long) (green[c] - g);
+        bd = (long) (blue[c] - b);
+        dist = rd * rd + gd * gd + bd * bd;
+        if (dist < mindist) {
+            if (dist == 0)
+                return c;       /* Return exact match color */
+            mindist = dist;
+            ct = c;
+        }
+    }
+    /* no exact match.  We now know closest, but first try to allocate exact */
+    if (top++ == maxColors)
+        return ct;              /* Return closest available color */
+    red[c] = r;
+    green[c] = g;
+    blue[c] = b;
+    *new = 1;                   /* flag new color */
+    return c;                   /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *vtxcolor[] = {
+    "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void vtx_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+    int object_code = 0;        /* always 0 for color */
+    int i, new;
+
+    switch (color->type) {
+       case COLOR_STRING:
+           for (i = 0; vtxcolor[i]; i++) {
+               if (streq(vtxcolor[i], color->u.string)) {
+                   color->u.index = i;
+                   break;
+               }
+           }
+           break;
+       case RGBA_BYTE:
+           i = 32 + vtxColorResolve(&new,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           if (new)
+               gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+                       object_code, i,
+                       color->u.rgba[0],
+                       color->u.rgba[1],
+                       color->u.rgba[2]);
+           color->u.index = i;
+           break;
+       default:
+           assert(0);  /* internal error */
+    }
+
+    color->type = COLOR_INDEX;
+}
+
+static void vtx_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+    switch (obj->pen) {
+       case PEN_DASHED: 
+           *line_style = 1;
+           *style_val = 10.;
+           break;
+       case PEN_DOTTED:
+           *line_style = 2;
+           *style_val = 10.;
+           break;
+       case PEN_SOLID:
+       default:
+           *line_style = 0;
+           *style_val = 0.;
+           break;
+    }
+}
+
+static void vtx_comment(GVJ_t *job, char *str)
+{
+    gvdevice_printf(job, "# %s\n", str);
+}
+
+static void vtx_begin_graph(GVJ_t * job)
+{
+    obj_state_t *obj = job->obj;
+
+    gvdevice_fputs(job, "#FIG 3.2\n");
+    gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+       job->common->info[0], job->common->info[1], job->common->info[2]);
+    gvdevice_printf(job, "# For: %s\n", job->common->user);
+    gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+    gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+    gvdevice_fputs(job, "Portrait\n"); /* orientation */
+    gvdevice_fputs(job, "Center\n");   /* justification */
+    gvdevice_fputs(job, "Inches\n");   /* units */
+    gvdevice_fputs(job, "Letter\n");   /* papersize */
+    gvdevice_fputs(job, "100.00\n");   /* magnification % */
+    gvdevice_fputs(job, "Single\n");   /* multiple-page */
+    gvdevice_fputs(job, "-2\n");       /* transparent color (none) */
+    gvdevice_fputs(job, "1200");            /* resolution */
+    gvdevice_fputs(job, " 2\n");       /* coordinate system (upper left) */
+}
+
+static void vtx_end_graph(GVJ_t * job)
+{
+    gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void vtx_begin_page(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void vtx_begin_node(GVJ_t * job)
+{
+    Depth = 1;
+}
+
+static void vtx_end_node(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void vtx_begin_edge(GVJ_t * job)
+{
+    Depth = 0;
+}
+
+static void vtx_end_edge(GVJ_t * job)
+{
+    Depth = 2;
+}
+
+static void vtx_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 4;        /* always 4 for text */
+    int sub_type = 0;           /* text justification */
+    int color = obj->pencolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int font = -1;             /* init to xfig's default font */
+    double font_size = para->fontsize * job->zoom;
+    double angle = job->rotation ? (PI / 2.0) : 0.0;
+    int font_flags = 4;                /* PostScript font */
+    double height = 0.0;
+    double length = 0.0;
+
+    if (para->postscript_alias) /* if it is a standard postscript font */
+       font = para->postscript_alias->xfig_code; 
+
+    switch (para->just) {
+    case 'l':
+        sub_type = 0;
+        break;
+    case 'r':
+        sub_type = 2;
+        break;
+    default:
+    case 'n':
+        sub_type = 1;
+        break;
+    }
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+            object_code, sub_type, color, depth, pen_style, font,
+            font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+            vtx_string(para->str));
+}
+
+static void vtx_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 1;        /* always 1 for ellipse */
+    int sub_type = 1;           /* ellipse defined by radii */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int direction = 0;
+    double angle = 0.0;
+    int center_x, center_y, radius_x, radius_y;
+    int start_x, start_y, end_x, end_y;
+
+    vtx_line_style(obj, &line_style, &style_val);
+
+    start_x = center_x = ROUND(A[0].x);
+    start_y = center_y = ROUND(A[0].y);
+    radius_x = ROUND(A[1].x - A[0].x);
+    radius_y = ROUND(A[1].y - A[0].y);
+    end_x = ROUND(A[1].x);
+    end_y = ROUND(A[1].y);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, direction,
+            angle, center_x, center_y, radius_x, radius_y, start_x,
+            start_y, end_x, end_y);
+}
+
+static void vtx_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+             int arrow_at_end, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 3;        /* always 3 for spline */
+    int sub_type;
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill;
+    double style_val;
+    int cap_style = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+    int i;
+
+    pointf pf, V[4];
+    point p;
+    int j, step;
+    int count = 0;
+    int size;
+
+    char *buffer;
+    char *buf;
+    buffer =
+        malloc((npoints + 1) * (BEZIERSUBDIVISION +
+                                1) * 20 * sizeof(char));
+    buf = buffer;
+
+    vtx_line_style(obj, &line_style, &style_val);
+
+    if (filled) {
+        sub_type = 5;     /* closed X-spline */
+        area_fill = 20;   /* fully saturated color */
+        fill_color = job->obj->fillcolor.u.index;
+    }
+    else {
+        sub_type = 4;     /* opened X-spline */
+        area_fill = -1;
+        fill_color = 0;
+    }
+    V[3].x = A[0].x;
+    V[3].y = A[0].y;
+    /* Write first point in line */
+    count++;
+    PF2P(A[0], p);
+    size = sprintf(buf, " %d %d", p.x, p.y);
+    buf += size;
+    /* write subsequent points */
+    for (i = 0; i + 3 < n; i += 3) {
+        V[0] = V[3];
+        for (j = 1; j <= 3; j++) {
+            V[j].x = A[i + j].x;
+            V[j].y = A[i + j].y;
+        }
+        for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+            count++;
+            pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+           PF2P(pf, p);
+            size = sprintf(buf, " %d %d", p.x, p.y);
+            buf += size;
+        }
+    }
+
+    gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+            object_code,
+            sub_type,
+            line_style,
+            thickness,
+            pen_color,
+            fill_color,
+            depth,
+            pen_style,
+            area_fill,
+            style_val, cap_style, forward_arrow, backward_arrow, count);
+
+    gvdevice_printf(job, " %s\n", buffer);      /* print points */
+    free(buffer);
+    for (i = 0; i < count; i++) {
+        gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0);   /* -1 on all */
+    }
+    gvdevice_fputs(job, "\n");
+}
+
+static void vtx_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 3;           /* always 3 for polygon */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = obj->fillcolor.u.index;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = filled ? 20 : -1;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n + 1;
+
+    vtx_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    vtxptarray(job, A, n, 1);        /* closed shape */
+}
+
+static void vtx_polyline(GVJ_t * job, pointf * A, int n)
+{
+    obj_state_t *obj = job->obj;
+
+    int object_code = 2;        /* always 2 for polyline */
+    int sub_type = 1;           /* always 1 for polyline */
+    int line_style;            /* solid, dotted, dashed */
+    int thickness = obj->penwidth;
+    int pen_color = obj->pencolor.u.index;
+    int fill_color = 0;
+    int depth = Depth;
+    int pen_style = 0;          /* not used */
+    int area_fill = 0;
+    double style_val;
+    int join_style = 0;
+    int cap_style = 0;
+    int radius = 0;
+    int forward_arrow = 0;
+    int backward_arrow = 0;
+    int npoints = n;
+
+    vtx_line_style(obj, &line_style, &style_val);
+
+    gvdevice_printf(job,
+            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+            object_code, sub_type, line_style, thickness, pen_color,
+            fill_color, depth, pen_style, area_fill, style_val, join_style,
+            cap_style, radius, forward_arrow, backward_arrow, npoints);
+    vtxptarray(job, A, n, 0);        /* open shape */
+}
+
+gvrender_engine_t vtx_engine = {
+    0,                         /* vtx_begin_job */
+    0,                         /* vtx_end_job */
+    vtx_begin_graph,
+    vtx_end_graph,
+    0,                         /* vtx_begin_layer */
+    0,                         /* vtx_end_layer */
+    vtx_begin_page,
+    0,                         /* vtx_end_page */
+    0,                         /* vtx_begin_cluster */
+    0,                         /* vtx_end_cluster */
+    0,                         /* vtx_begin_nodes */
+    0,                         /* vtx_end_nodes */
+    0,                         /* vtx_begin_edges */
+    0,                         /* vtx_end_edges */
+    vtx_begin_node,
+    vtx_end_node,
+    vtx_begin_edge,
+    vtx_end_edge,
+    0,                         /* vtx_begin_anchor */
+    0,                         /* vtx_end_anchor */
+    vtx_textpara,
+    vtx_resolve_color,
+    vtx_ellipse,
+    vtx_polygon,
+    vtx_bezier,
+    vtx_polyline,
+    vtx_comment,
+    0,                         /* vtx_library_shape */
+};
+
+
+/* NB.  List must be LANG_C sorted */
+static char *vtx_knowncolors[] = {
+    "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t vtx_features = {
+    EMIT_COLORS
+       | GVRENDER_Y_GOES_DOWN, /* flags */
+    DEFAULT_EMBED_MARGIN,      /* default margin - points */
+    4.,                         /* default pad - graph units */
+    {0.,0.},                    /* default page width, height - points */
+    {1440.,1440.},             /* default dpi */
+        /* FIXME - this default dpi is a very strange number!!!
+         * It was picked to make .png usershapes the right size on my screen.
+         * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+         * (I was expecting 1.3333 which is 96/72, but thats too big.)
+         * Also 1200 is hardcoded in vtx_begin_graph() instead of using job->dpi 
+          */
+
+        /* It may be TWIPS, i.e. 20 * POINT_PER_INCH 
+         *    but that doesn't explain what the 1200 is? */
+
+    vtx_knowncolors,           /* knowncolors */
+    sizeof(vtx_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+    RGBA_BYTE,                 /* color_type */
+};
+
+gvplugin_installed_t gvrender_vtx_types[] = {
+    {FORMAT_VTX, "vtx", -1, &vtx_engine, &vtx_features},
+    {0, NULL, 0, NULL, NULL}
+};