/* This software may only be used by you under license from AT&T Corp. ("AT&T"). A copy of AT&T's Source Code Agreement is available at AT&T's Internet website having the URL: If you received this software without first entering into a license with AT&T, you have an infringing copy of this software and cannot use it without violating AT&T's intellectual property rights. */ #pragma prototyped #include #include "render.h" #include "utils.h" #ifdef HAVE_LIBZ #include "zlib.h" #ifdef MSWIN32 #include #endif #endif #ifdef DMALLOC #include "dmalloc.h" #endif /* 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) #define NODE 1 #define EDGE 2 #define CLST 3 /* FIXME - these are not used currently - probably something missing */ #if 0 /* DIA dash array */ static char * sdarray = "5,2"; /* DIA dot array */ static char * sdotarray = "1,5"; static int GraphURL, ClusterURL, NodeURL, EdgeURL; static char *op[] = {"graph", "node", "edge", "graph"}; #endif static int N_pages; static point Pages; static double Scale; static pointf Offset; static int Rot; static box PB; static int onetime = TRUE; static node_t *Curnode; static edge_t *Curedge; static graph_t *Curgraph, *Rootgraph; 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; #ifdef HAVE_LIBZ static gzFile Zfile; #endif static int dia_fputs (char *s) { int len; len = strlen(s); #ifdef HAVE_LIBZ return gzwrite(Zfile,s,(unsigned)len); #else return 0; #endif } /* dia_printf: * Note that this function is unsafe due to the fixed buffer size. * It should only be used when the caller is sure the input will not * overflow the buffer. In particular, it should be avoided for * input coming from users. Also, if vsnprintf is available, the * code should check for return values to use it safely. */ static int dia_printf(const char *format, ...) { char buf[BUFSIZ]; va_list argp; int len; va_start(argp, format); #ifdef HAVE_VSNPRINTF (void)vsnprintf(buf, sizeof(buf), format, argp); #else (void)vsprintf(buf, format, argp); #endif va_end(argp); len = strlen(buf); /* some *sprintf (e.g C99 std) don't return the number of bytes actually written */ #ifdef HAVE_LIBZ return gzwrite(Zfile,buf,(unsigned)len); #else return 0; #endif } 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 diapt(point 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 char* dia_resolve_color(char *name) { #ifdef DIA_KNOWS_SVG_COLORNAMES /* color names from http://www.w3.org/TR/SVG/types.html */ static char *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", 0}; #else static char *known_colors[] = {0}; #endif static char buf[SMALLBUF]; char *tok, **known; color_t color; tok = canontoken(name); for (known = known_colors; *known; known++) if (streq(tok,*known)) break; if (*known == 0) { 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_grstyle(context_t* cp) { if (cp->pencolor!=DEFAULT_COLOR) { dia_fputs(" \n"); dia_printf(" \n",dia_resolve_color(cp->pencolor)); dia_fputs(" \n"); } if (cp->penwidth!=WIDTH_NORMAL) { dia_fputs(" \n"); dia_printf(" \n",Scale*(cp->penwidth)); dia_fputs(" \n"); } if (cp->pen == P_DASHED ) { dia_fputs(" \n"); dia_printf(" \n",1); dia_fputs(" \n"); } #if 0 } else if( cp->pen == P_DOTTED) { dia_printf("stroke-dasharray:%s;", sdotarray); } #endif } static void dia_grstylefill(context_t* cp, int filled) { if (filled) { dia_fputs(" \n"); dia_printf(" \n",dia_resolve_color(cp->fillcolor)); dia_fputs(" \n"); } else { dia_fputs(" \n"); dia_printf(" \n","true"); dia_fputs(" \n"); } } static void dia_comment(void* obj, attrsym_t* sym) { char *str = late_string(obj,sym,""); if (str[0]) { dia_fputs (" sequences in str */ dia_fputs (str); dia_fputs (" -->\n"); } } static void dia_begin_job(FILE *ofp, graph_t *g, char **lib, char *user, char *info[], point pages) { #if HAVE_LIBZ int fd; fd = dup(fileno(Output_file)); /* open dup so can gzclose independent of FILE close */ #ifdef HAVE_SETMODE #ifdef O_BINARY /* * Windows will do \n -> \r\n translations on * stdout unless told otherwise. */ setmode(fd, O_BINARY); #endif #endif Zfile = gzdopen(fd, "wb"); if (!Zfile) { agerr (AGERR, "Error opening compressed output file\n"); exit(1); } #else agerr(AGERR, "No support for compressed output. Not compiled with zlib.\n"); exit(1); #endif Pages = pages; N_pages = pages.x * pages.y; dia_printf("\n"); } static void dia_end_job(void) { } static void dia_begin_graph(graph_t* g, box bb, point pb) { 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(); dia_comment(g,agfindattr(g,"comment")); onetime = FALSE; } dia_fputs("\n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" #A4#\n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); } static void dia_end_graph(void) { dia_printf("\n"); #ifdef HAVE_LIBZ gzclose(Zfile); #endif } static void dia_begin_page(graph_t *g, point page, double scale, int rot, point offset) { int page_number; /* point sz; */ Scale = scale * SCALE; Rot = rot; page_number = page.x + page.y * Pages.x + 1; /* sz = sub_points(PB.UR,PB.LL); */ dia_printf(" \n"); } static void dia_end_page(void) { dia_fputs(" \n"); } static void dia_begin_cluster(graph_t* g) { dia_printf("\n"); Curgraph = g; } static void dia_end_cluster (void) { dia_printf("\n"); } static void dia_begin_nodes(void) { } static void dia_end_nodes(void) { } static void dia_begin_edges(void) { } static void dia_end_edges(void) { } static void dia_begin_node(node_t* n) { dia_printf("\n"); Curnode = n; } static void dia_end_node (void) { dia_printf("\n"); } static void dia_begin_edge (edge_t* e) { Curedge = e; } static void dia_end_edge (void) { } 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 { agerr (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_textline(point p, textline_t *line) { int anchor; char *string; pointf mp; context_t *cp; string = xml_string(line->str); if (strlen(string) == 0) { /* its zero length, don't draw */ return; } cp = &(cstk[SP]); if( cp->pen == P_NONE ) { /* its invisible, don't draw */ return; } switch(line->just) { case 'l': anchor=0; break; case 'r': anchor=2; break; default: case 'n': anchor=1; break; } mp = diapt(p); dia_printf(" \n","0"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" #"); dia_fputs(string); dia_fputs("#\n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",cp->fontfam); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",Scale*(cp->fontsz)); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",mp.x,mp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",dia_resolve_color(cp->pencolor)); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",anchor); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",mp.x,mp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n", mp.x-(Scale*(line->width)/2.),mp.y-0.4, mp.x+(Scale*(line->width)/2.),mp.y+0.4); dia_fputs(" \n"); dia_fputs(" \n"); } static void dia_ellipse(point p, int rx, int ry, 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 = diapt(p); if (Rot) {int t; t = rx; rx = ry; ry = t;} rp.x = Scale * rx; rp.y = Scale * ry; dia_printf(" \n",nodeId); dia_fputs(" \n"); dia_printf(" \n",cp.x-rp.x,cp.y-rp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",rp.x+rp.x); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",rp.y+rp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",cp.x-rp.x,cp.y-rp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n", cp.x-rp.x-.11,cp.y-rp.y-.11,cp.x+rp.x+.11,cp.y+rp.y+.11); dia_fputs(" \n"); dia_grstyle(&cstk[SP]); dia_grstylefill(&cstk[SP], filled); dia_fputs(" \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, mindist=0.0, dist; 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 = ALLOC(A_size,A,point);} xsize = ((ND_lw_i(n) + ND_rw_i(n)) / ND_width(n)) * 16.0; ysize = ((ND_ht_i(n)) / 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) { dist = DIST(p.x, p.y, diapt(A[z]).x, diapt(A[z]).y); if(z == 0) { mindist = dist; conn = 0; } if(dist < mindist) { mindist = dist; conn = 2*z; } z++; } z = 0; while(z < i) { dist = DIST(p.x, p.y, (diapt(A[z]).x + diapt(A[z+1]).x)/2, (diapt(A[z]).y + diapt(A[z+1]).y)/2); if(dist < mindist) { mindist = dist; conn = 2*z + 1; } z++; } return conn; } static void dia_bezier(point* A, int n, int arrow_at_start, int arrow_at_end) { int i, conn_h, conn_t; pointf p,firstp,llp,urp; node_t *head, *tail; char *shape_h, *shape_t; pointf cp_h, cp_t; conn_h = conn_t = -1; head = Curedge->head; tail = Curedge->tail; shape_h = ND_shape(head)->name; shape_t = ND_shape(tail)->name; if( cstk[SP].pen == P_NONE ) { /* its invisible, don't draw */ return; } dia_printf(" \n","00"); dia_fputs(" \n"); for (i = 0; i < n; i++) { p = diapt(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; dia_printf(" \n",p.x,p.y); } dia_fputs(" \n"); dia_grstyle(&cstk[SP]); dia_fputs(" \n"); dia_printf(" \n",firstp.x,firstp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n", llp.x-.11,llp.y-.11,urp.x+.11,urp.y+.11); dia_fputs(" \n"); // arrowheads if(arrow_at_start) { dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); } if(arrow_at_end) { dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); dia_fputs(" \n"); } dia_fputs(" \n"); dia_printf(" \n",diapt(A[0]).x,diapt(A[0]).y); dia_printf(" \n",diapt(A[n-1]).x,diapt(A[n-1]).y); dia_fputs(" \n"); dia_fputs(" \n"); if((strcmp(shape_t, "ellipse") == 0) || (strcmp(shape_t, "circle") == 0) || (strcmp(shape_t, "doublecircle") == 0)) { cp_h = diapt(ND_coord_i(head)); if(AG_IS_DIRECTED(Rootgraph)) conn_h = ellipse_connection(cp_h, diapt(A[n-1])); else conn_h = ellipse_connection(cp_h, diapt(A[0])); } else { if(AG_IS_DIRECTED(Rootgraph)) conn_h = box_connection(head, diapt(A[n-1])); else conn_h = box_connection(head, diapt(A[0])); } if((strcmp(shape_t, "ellipse") == 0) || (strcmp(shape_t, "circle") == 0) || (strcmp(shape_t, "doublecircle") == 0)) { cp_t = diapt(ND_coord_i(tail)); if(AG_IS_DIRECTED(Rootgraph)) conn_t = ellipse_connection(cp_t, diapt(A[0])); else conn_t = ellipse_connection(cp_t, diapt(A[n-1])); } else { if(AG_IS_DIRECTED(Rootgraph)) conn_t = box_connection(tail, diapt(A[0])); else conn_t = box_connection(tail, diapt(A[n-1])); } if(arrow_at_start) { dia_printf(" \n", head->id, conn_h); dia_printf(" \n", (n-1),tail->id, conn_t); } else { dia_printf(" \n", tail->id, conn_t); dia_printf(" \n", (n-1),head->id, conn_h); } dia_fputs(" \n"); dia_fputs(" \n"); } static void dia_polygon(point *A, int n, int filled) { int i; pointf p, firstp,llp,urp; if( cstk[SP].pen == P_NONE ) { /* its invisible, don't draw */ return; } switch(Obj) { case NODE: dia_printf(" \n",Curnode->id); break; case EDGE: return; break; case CLST: dia_printf(" \n",Curgraph->name); break; default: dia_printf(" \n","polygon"); break; } dia_fputs(" \n"); for (i = 0; i < n; i++) { p = diapt(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; dia_printf(" \n",p.x,p.y); } dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n",firstp.x,firstp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n", llp.x-.11,llp.y-.11,urp.x+.11,urp.y+.11); dia_fputs(" \n"); dia_grstyle(&cstk[SP]); dia_grstylefill(&cstk[SP],filled); dia_fputs(" \n"); } static void dia_polyline(point* A, int n) { int i; pointf p, firstp,llp,urp; if( cstk[SP].pen == P_NONE ) { /* its invisible, don't draw */ return; } dia_printf(" \n","0"); dia_fputs(" \n"); for (i = 0; i < n; i++) { p = diapt(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; dia_printf("\n",p.x,p.y); } dia_fputs(" \n"); dia_grstyle(&cstk[SP]); dia_fputs(" \n"); dia_printf(" \n",firstp.x,firstp.y); dia_fputs(" \n"); dia_fputs(" \n"); dia_printf(" \n", llp.x-.11,llp.y-.11,urp.x+.11,urp.y+.11); dia_fputs(" \n"); dia_fputs(" \n"); } static void dia_user_shape(char *name, point *A, int n, int filled) { point p; pointf mp; point sz; char *imagefile; if( cstk[SP].pen == P_NONE ) { /* its invisible, don't draw */ return; } imagefile = agget(Curnode,"shapefile"); if (imagefile == 0) { dia_polygon(A, n, filled); return; } p = ND_coord_i(Curnode); p.x -= ND_lw_i(Curnode); p.y += ND_ht_i(Curnode)/2; mp = diapt(p); sz.x = ROUND(Scale*(ND_lw_i(Curnode)+ND_rw_i(Curnode))); sz.y = ROUND(Scale*ND_ht_i(Curnode)); } codegen_t DIA_CodeGen = { dia_reset, dia_begin_job, dia_end_job, dia_begin_graph, dia_end_graph, dia_begin_page, dia_end_page, dia_begin_cluster, dia_end_cluster, dia_begin_nodes, dia_end_nodes, dia_begin_edges, dia_end_edges, dia_begin_node, dia_end_node, dia_begin_edge, dia_end_edge, dia_begin_context, dia_end_context, dia_set_font, dia_textline, dia_set_pencolor, dia_set_fillcolor, dia_set_style, dia_ellipse, dia_polygon, dia_bezier, dia_polyline, 1 /*dia_arrowhead */, dia_user_shape, 0 /* dia_comment */, 0 /* dia_textsize */ };