Graphviz  2.29.20120524.0446
plugin/core/gvrender_core_dot.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #ifdef WIN32
00019 #include <io.h>
00020 #include "compat.h"
00021 #endif
00022 
00023 #include <stdarg.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 
00027 #include "macros.h"
00028 #include "const.h"
00029 
00030 #include "gvplugin_render.h"
00031 #include "gvplugin_device.h"
00032 #include "agxbuf.h"
00033 #include "utils.h"
00034 #include "gvio.h"
00035 
00036 #define GNEW(t)          (t*)malloc(sizeof(t))
00037 
00038 /* #define NEW_XDOT */
00039 
00040 typedef enum {
00041         FORMAT_DOT,
00042         FORMAT_CANON,
00043         FORMAT_PLAIN,
00044         FORMAT_PLAIN_EXT,
00045         FORMAT_XDOT
00046 } format_type;
00047 
00048 #ifdef WIN32 /*dependencies*/
00049 #ifdef WITH_CGRAPH
00050     #pragma comment( lib, "cgraph.lib" )
00051 #else
00052     #pragma comment( lib, "graph.lib" )
00053 #endif
00054     #pragma comment( lib, "gvc.lib" )
00055 //    #pragma comment( lib, "ingraphs.lib" )
00056 #endif
00057 
00058 #define XDOTVERSION "1.2"
00059 
00060 #define NUMXBUFS (EMIT_HLABEL+1)
00061 /* There are as many xbufs as there are values of emit_state_t.
00062  * However, only the first NUMXBUFS are distinct. Nodes, clusters, and
00063  * edges are drawn atomically, so they share the DRAW and LABEL buffers
00064  */
00065 static agxbuf xbuf[NUMXBUFS];
00066 static agxbuf* xbufs[] = {
00067     xbuf+EMIT_GDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_TDRAW, xbuf+EMIT_HDRAW, 
00068     xbuf+EMIT_GLABEL, xbuf+EMIT_CLABEL, xbuf+EMIT_TLABEL, xbuf+EMIT_HLABEL, 
00069     xbuf+EMIT_CDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_CLABEL, xbuf+EMIT_CLABEL, 
00070 };
00071 static double penwidth [] = {
00072     1, 1, 1, 1,
00073     1, 1, 1, 1,
00074     1, 1, 1, 1,
00075 };
00076 
00077 typedef struct {
00078     attrsym_t *g_draw;
00079     attrsym_t *g_l_draw;
00080     attrsym_t *n_draw;
00081     attrsym_t *n_l_draw;
00082     attrsym_t *e_draw;
00083     attrsym_t *h_draw;
00084     attrsym_t *t_draw;
00085     attrsym_t *e_l_draw;
00086     attrsym_t *hl_draw;
00087     attrsym_t *tl_draw;
00088     unsigned char buf[NUMXBUFS][BUFSIZ];
00089 } xdot_state_t;
00090 static xdot_state_t* xd;
00091 
00092 static void xdot_str (GVJ_t *job, char* pfx, char* s)
00093 {   
00094     emit_state_t emit_state = job->obj->emit_state;
00095     char buf[BUFSIZ];
00096     
00097     sprintf (buf, "%s%d -", pfx, (int)strlen(s));
00098     agxbput(xbufs[emit_state], buf);
00099     agxbput(xbufs[emit_state], s);
00100     agxbputc(xbufs[emit_state], ' ');
00101 }
00102 
00103 static void xdot_points(GVJ_t *job, char c, pointf * A, int n)
00104 {
00105     emit_state_t emit_state = job->obj->emit_state;
00106     char buf[BUFSIZ];
00107     int i, rc;
00108 
00109     rc = agxbputc(xbufs[emit_state], c);
00110     sprintf(buf, " %d ", n);
00111     agxbput(xbufs[emit_state], buf);
00112     for (i = 0; i < n; i++)
00113         output_point(xbufs[emit_state], A[i]);
00114 }
00115 
00116 static char*
00117 color2str (unsigned char rgba[4])
00118 {
00119     static char buf [10];
00120 
00121     sprintf (buf, "#%02x%02x%02x%02x", rgba[0], rgba[1],  rgba[2], rgba[3]);
00122     return buf;
00123 }
00124 
00125 static void xdot_pencolor (GVJ_t *job)
00126 {
00127     xdot_str (job, "c ", color2str (job->obj->pencolor.u.rgba));
00128 }
00129 
00130 static void xdot_fillcolor (GVJ_t *job)
00131 {
00132     xdot_str (job, "C ", color2str (job->obj->fillcolor.u.rgba));
00133 }
00134 
00135 static void xdot_style (GVJ_t *job)
00136 {
00137     unsigned char buf[BUFSIZ];
00138     agxbuf xbuf;
00139     char* p, **s;
00140     int more;
00141 
00142     /* First, check if penwidth state is correct */
00143     if (job->obj->penwidth != penwidth[job->obj->emit_state]) {
00144         penwidth[job->obj->emit_state] = job->obj->penwidth;
00145         sprintf ((char*)buf, "setlinewidth(%.3f)", job->obj->penwidth);
00146         xdot_str (job, "S ", (char*)buf);
00147     }
00148 
00149     /* now process raw style, if any */
00150     s = job->obj->rawstyle;
00151     if (!s)
00152         return;
00153 
00154     agxbinit(&xbuf, BUFSIZ, buf);
00155     while ((p = *s++)) {
00156         if (streq(p, "filled") || streq(p, "bold") || streq(p, "setlinewidth")) continue;
00157         agxbput(&xbuf, p);
00158         while (*p)
00159             p++;
00160         p++;
00161         if (*p) {  /* arguments */
00162             agxbputc(&xbuf, '(');
00163             more = 0;
00164             while (*p) {
00165                 if (more)
00166                     agxbputc(&xbuf, ',');
00167                 agxbput(&xbuf, p);
00168                 while (*p) p++;
00169                 p++;
00170                 more++;
00171             }
00172             agxbputc(&xbuf, ')');
00173         }
00174         xdot_str (job, "S ", agxbuse(&xbuf));
00175     }
00176 
00177     agxbfree(&xbuf);
00178 
00179 }
00180 
00181 static void xdot_end_node(GVJ_t* job)
00182 {
00183     Agnode_t* n = job->obj->u.n; 
00184     if (agxblen(xbufs[EMIT_NDRAW]))
00185 #ifndef WITH_CGRAPH
00186         agxset(n, xd->n_draw->index, agxbuse(xbufs[EMIT_NDRAW]));
00187 #else /* WITH_CGRAPH */
00188         agxset(n, xd->n_draw, agxbuse(xbufs[EMIT_NDRAW]));
00189 #endif /* WITH_CGRAPH */
00190     if (agxblen(xbufs[EMIT_NLABEL]))
00191 #ifndef WITH_CGRAPH
00192         agxset(n, xd->n_l_draw->index, agxbuse(xbufs[EMIT_NLABEL]));
00193 #else /* WITH_CGRAPH */
00194         agxset(n, xd->n_l_draw, agxbuse(xbufs[EMIT_NLABEL]));
00195 #endif /* WITH_CGRAPH */
00196     penwidth[EMIT_NDRAW] = 1;
00197     penwidth[EMIT_NLABEL] = 1;
00198 }
00199 
00200 static void xdot_end_edge(GVJ_t* job)
00201 {
00202     Agedge_t* e = job->obj->u.e; 
00203 
00204     if (agxblen(xbufs[EMIT_EDRAW]))
00205 #ifndef WITH_CGRAPH
00206         agxset(e, xd->e_draw->index, agxbuse(xbufs[EMIT_EDRAW]));
00207 #else /* WITH_CGRAPH */
00208         agxset(e, xd->e_draw, agxbuse(xbufs[EMIT_EDRAW]));
00209 #endif /* WITH_CGRAPH */
00210     if (agxblen(xbufs[EMIT_TDRAW]))
00211 #ifndef WITH_CGRAPH
00212         agxset(e, xd->t_draw->index, agxbuse(xbufs[EMIT_TDRAW]));
00213 #else /* WITH_CGRAPH */
00214         agxset(e, xd->t_draw, agxbuse(xbufs[EMIT_TDRAW]));
00215 #endif /* WITH_CGRAPH */
00216     if (agxblen(xbufs[EMIT_HDRAW]))
00217 #ifndef WITH_CGRAPH
00218         agxset(e, xd->h_draw->index, agxbuse(xbufs[EMIT_HDRAW]));
00219 #else /* WITH_CGRAPH */
00220         agxset(e, xd->h_draw, agxbuse(xbufs[EMIT_HDRAW]));
00221 #endif /* WITH_CGRAPH */
00222     if (agxblen(xbufs[EMIT_ELABEL]))
00223 #ifndef WITH_CGRAPH
00224         agxset(e, xd->e_l_draw->index,agxbuse(xbufs[EMIT_ELABEL]));
00225 #else /* WITH_CGRAPH */
00226         agxset(e, xd->e_l_draw,agxbuse(xbufs[EMIT_ELABEL]));
00227 #endif /* WITH_CGRAPH */
00228     if (agxblen(xbufs[EMIT_TLABEL]))
00229 #ifndef WITH_CGRAPH
00230         agxset(e, xd->tl_draw->index, agxbuse(xbufs[EMIT_TLABEL]));
00231 #else /* WITH_CGRAPH */
00232         agxset(e, xd->tl_draw, agxbuse(xbufs[EMIT_TLABEL]));
00233 #endif /* WITH_CGRAPH */
00234     if (agxblen(xbufs[EMIT_HLABEL]))
00235 #ifndef WITH_CGRAPH
00236         agxset(e, xd->hl_draw->index, agxbuse(xbufs[EMIT_HLABEL]));
00237 #else /* WITH_CGRAPH */
00238         agxset(e, xd->hl_draw, agxbuse(xbufs[EMIT_HLABEL]));
00239 #endif /* WITH_CGRAPH */
00240     penwidth[EMIT_EDRAW] = 1;
00241     penwidth[EMIT_ELABEL] = 1;
00242     penwidth[EMIT_TDRAW] = 1;
00243     penwidth[EMIT_HDRAW] = 1;
00244     penwidth[EMIT_TLABEL] = 1;
00245     penwidth[EMIT_HLABEL] = 1;
00246 }
00247 
00248 #ifdef NEW_XDOT
00249 /* xdot_begin_anchor:
00250  * The encoding of which fields are present assumes that one of the fields is present,
00251  * so there is never a 0 after the H.
00252  */
00253 static void xdot_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, char *id)
00254 {
00255     emit_state_t emit_state = job->obj->emit_state;
00256     char buf[3];  /* very small integer */
00257     unsigned int flags = 0;
00258 
00259     agxbput(xbufs[emit_state], "H ");
00260     if (href)
00261         flags |= 1;
00262     if (tooltip)
00263         flags |= 2;
00264     if (target)
00265         flags |= 4;
00266     sprintf (buf, "%d ", flags);
00267     agxbput(xbufs[emit_state], buf);
00268     if (href)
00269         xdot_str (job, "", href);
00270     if (tooltip)
00271         xdot_str (job, "", tooltip);
00272     if (target)
00273         xdot_str (job, "", target);
00274 }
00275 
00276 static void xdot_end_anchor(GVJ_t * job)
00277 {
00278     emit_state_t emit_state = job->obj->emit_state;
00279 
00280     agxbput(xbufs[emit_state], "H 0 ");
00281 }
00282 #endif
00283 
00284 static void xdot_end_cluster(GVJ_t * job)
00285 {
00286     Agraph_t* cluster_g = job->obj->u.sg;
00287 
00288 #ifndef WITH_CGRAPH
00289     agxset(cluster_g, xd->g_draw->index, agxbuse(xbufs[EMIT_CDRAW]));
00290 #else /* WITH_CGRAPH */
00291     agxset(cluster_g, xd->g_draw, agxbuse(xbufs[EMIT_CDRAW]));
00292 #endif /* WITH_CGRAPH */
00293     if (GD_label(cluster_g))
00294 #ifndef WITH_CGRAPH
00295         agxset(cluster_g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_CLABEL]));
00296 #else /* WITH_CGRAPH */
00297         agxset(cluster_g, xd->g_l_draw, agxbuse(xbufs[EMIT_CLABEL]));
00298 #endif /* WITH_CGRAPH */
00299     penwidth[EMIT_CDRAW] = 1;
00300     penwidth[EMIT_CLABEL] = 1;
00301 }
00302 
00303 /* 
00304  * John M. suggests:
00305  * You might want to add four more:
00306  *
00307  * _ohdraw_ (optional head-end arrow for edges)
00308  * _ohldraw_ (optional head-end label for edges)
00309  * _otdraw_ (optional tail-end arrow for edges)
00310  * _otldraw_ (optional tail-end label for edges)
00311  * 
00312  * that would be generated when an additional option is supplied to 
00313  * dot, etc. and 
00314  * these would be the arrow/label positions to use if a user want to flip the 
00315  * direction of an edge (as sometimes is there want).
00316  * 
00317  * N.B. John M. asks:
00318  *   By the way, I don't know if you ever plan to add other letters for 
00319  * the xdot spec, but could you reserve "a" and also "A" (for  attribute), 
00320  * "n" and also "N" (for numeric), "w" (for sWitch),  "s" (for string) 
00321  * and "t" (for tooltip) and "x" (for position). We use  those letters in 
00322  * our drawing spec (and also "<" and ">"), so if you  start generating 
00323  * output with them, it could break what we have. 
00324  */
00325 static void
00326 xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows)
00327 {
00328     int i;
00329 
00330     xd = GNEW(xdot_state_t);
00331 
00332     if (GD_n_cluster(g))
00333 #ifndef WITH_CGRAPH
00334         xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
00335 #else
00336         xd->g_draw = safe_dcl(g, AGRAPH, "_draw_", "");
00337 #endif
00338     else
00339         xd->g_draw = NULL;
00340     if (GD_has_labels(g) & GRAPH_LABEL)
00341 #ifndef WITH_CGRAPH
00342         xd->g_l_draw = safe_dcl(g, g, "_ldraw_", "", agraphattr);
00343 #else
00344         xd->g_l_draw = safe_dcl(g, AGRAPH, "_ldraw_", "");
00345 #endif
00346     else
00347         xd->g_l_draw = NULL;
00348 
00349 #ifndef WITH_CGRAPH
00350     xd->n_draw = safe_dcl(g, g->proto->n, "_draw_", "", agnodeattr);
00351     xd->n_l_draw = safe_dcl(g, g->proto->n, "_ldraw_", "", agnodeattr);
00352 
00353     xd->e_draw = safe_dcl(g, g->proto->e, "_draw_", "", agedgeattr);
00354 #else
00355     xd->n_draw = safe_dcl(g, AGNODE, "_draw_", "");
00356     xd->n_l_draw = safe_dcl(g, AGNODE, "_ldraw_", "");
00357 
00358     xd->e_draw = safe_dcl(g, AGEDGE, "_draw_", "");
00359 #endif
00360     if (e_arrows)
00361 #ifndef WITH_CGRAPH
00362         xd->h_draw = safe_dcl(g, g->proto->e, "_hdraw_", "", agedgeattr);
00363 #else
00364         xd->h_draw = safe_dcl(g, AGEDGE, "_hdraw_", "");
00365 #endif
00366     else
00367         xd->h_draw = NULL;
00368     if (s_arrows)
00369 #ifndef WITH_CGRAPH
00370         xd->t_draw = safe_dcl(g, g->proto->e, "_tdraw_", "", agedgeattr);
00371 #else
00372         xd->t_draw = safe_dcl(g, AGEDGE, "_tdraw_", "");
00373 #endif
00374     else
00375         xd->t_draw = NULL;
00376     if (GD_has_labels(g) & (EDGE_LABEL|EDGE_XLABEL))
00377 #ifndef WITH_CGRAPH
00378         xd->e_l_draw = safe_dcl(g, g->proto->e, "_ldraw_", "", agedgeattr);
00379 #else
00380         xd->e_l_draw = safe_dcl(g, AGEDGE, "_ldraw_", "");
00381 #endif
00382     else
00383         xd->e_l_draw = NULL;
00384     if (GD_has_labels(g) & HEAD_LABEL)
00385 #ifndef WITH_CGRAPH
00386         xd->hl_draw = safe_dcl(g, g->proto->e, "_hldraw_", "", agedgeattr);
00387 #else
00388         xd->hl_draw = safe_dcl(g, AGEDGE, "_hldraw_", "");
00389 #endif
00390     else
00391         xd->hl_draw = NULL;
00392     if (GD_has_labels(g) & TAIL_LABEL)
00393 #ifndef WITH_CGRAPH
00394         xd->tl_draw = safe_dcl(g, g->proto->e, "_tldraw_", "", agedgeattr);
00395 #else
00396         xd->tl_draw = safe_dcl(g, AGEDGE, "_tldraw_", "");
00397 #endif
00398     else
00399         xd->tl_draw = NULL;
00400 
00401     for (i = 0; i < NUMXBUFS; i++)
00402         agxbinit(xbuf+i, BUFSIZ, xd->buf[i]);
00403 }
00404 
00405 static void dot_begin_graph(GVJ_t *job)
00406 {
00407     int e_arrows;            /* graph has edges with end arrows */
00408     int s_arrows;            /* graph has edges with start arrows */
00409     graph_t *g = job->obj->u.g;
00410 
00411     switch (job->render.id) {
00412         case FORMAT_DOT:
00413             attach_attrs(g);
00414             break;
00415         case FORMAT_CANON:
00416             if (HAS_CLUST_EDGE(g))
00417                 undoClusterEdges(g);
00418             break;
00419         case FORMAT_PLAIN:
00420         case FORMAT_PLAIN_EXT:
00421             break;
00422         case FORMAT_XDOT:
00423             attach_attrs_and_arrows(g, &s_arrows, &e_arrows);
00424             xdot_begin_graph(g, s_arrows, e_arrows);
00425     }
00426 }
00427 
00428 static void xdot_end_graph(graph_t* g)
00429 {
00430     int i;
00431 
00432     if (agxblen(xbufs[EMIT_GDRAW])) {
00433         if (!xd->g_draw)
00434 #ifndef WITH_CGRAPH
00435             xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
00436         agxset(g, xd->g_draw->index, agxbuse(xbufs[EMIT_GDRAW]));
00437 #else /* WITH_CGRAPH */
00438             xd->g_draw = safe_dcl(g, AGRAPH, "_draw_", "");
00439         agxset(g, xd->g_draw, agxbuse(xbufs[EMIT_GDRAW]));
00440 #endif /* WITH_CGRAPH */
00441     }
00442     if (GD_label(g))
00443 #ifndef WITH_CGRAPH
00444         agxset(g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL]));
00445 #else /* WITH_CGRAPH */
00446         agxset(g, xd->g_l_draw, agxbuse(xbufs[EMIT_GLABEL]));
00447 #endif /* WITH_CGRAPH */
00448     agsafeset (g, "xdotversion", XDOTVERSION, "");
00449 
00450     for (i = 0; i < NUMXBUFS; i++)
00451         agxbfree(xbuf+i);
00452     free (xd);
00453     penwidth[EMIT_GDRAW] = 1;
00454     penwidth[EMIT_GLABEL] = 1;
00455 }
00456 
00457 #ifdef WITH_CGRAPH
00458 typedef int (*putstrfn) (void *chan, const char *str);
00459 typedef int (*flushfn) (void *chan);
00460 #endif
00461 static void dot_end_graph(GVJ_t *job)
00462 {
00463     graph_t *g = job->obj->u.g;
00464 #ifdef WITH_CGRAPH
00465     Agiodisc_t* io_save;
00466     static Agiodisc_t io;
00467 
00468     if (io.afread == NULL) {
00469         io.afread = AgIoDisc.afread;
00470         io.putstr = (putstrfn)gvputs;
00471         io.flush = (flushfn)gvflush;
00472     }
00473 #endif
00474 
00475 #ifndef WITH_CGRAPH
00476     agsetiodisc(NULL, gvfwrite, gvferror);
00477 #else
00478     io_save = g->clos->disc.io;
00479     g->clos->disc.io = &io;
00480 #endif
00481     switch (job->render.id) {
00482         case FORMAT_PLAIN:
00483             write_plain(job, g, (FILE*)job, FALSE);
00484             break;
00485         case FORMAT_PLAIN_EXT:
00486             write_plain(job, g, (FILE*)job, TRUE);
00487             break;
00488         case FORMAT_DOT:
00489         case FORMAT_CANON:
00490             if (!(job->flags & OUTPUT_NOT_REQUIRED))
00491                 agwrite(g, (FILE*)job);
00492             break;
00493         case FORMAT_XDOT:
00494             xdot_end_graph(g);
00495             if (!(job->flags & OUTPUT_NOT_REQUIRED))
00496                 agwrite(g, (FILE*)job);
00497             break;
00498     }
00499 #ifndef WITH_CGRAPH
00500     agsetiodisc(NULL, NULL, NULL);
00501 #else
00502     g->clos->disc.io = io_save;
00503 #endif
00504 }
00505 
00506 static void xdot_textpara(GVJ_t * job, pointf p, textpara_t * para)
00507 {
00508     emit_state_t emit_state = job->obj->emit_state;
00509 
00510     char buf[BUFSIZ];
00511     int j;
00512     
00513     sprintf(buf, "F %f ", para->fontsize);
00514     agxbput(xbufs[emit_state], buf);
00515     xdot_str (job, "", para->fontname);
00516     xdot_pencolor(job);
00517 
00518     switch (para->just) {
00519     case 'l':
00520         j = -1; 
00521         break;
00522     case 'r':
00523         j = 1;
00524         break;
00525     default:
00526     case 'n':
00527         j = 0;
00528         break;
00529     }
00530     agxbput(xbufs[emit_state], "T ");
00531     output_point(xbufs[emit_state], p);
00532     sprintf(buf, "%d %d ", j, (int) para->width);
00533     agxbput(xbufs[emit_state], buf);
00534     xdot_str (job, "", para->str);
00535 }
00536 
00537 static void xdot_ellipse(GVJ_t * job, pointf * A, int filled)
00538 {
00539     emit_state_t emit_state = job->obj->emit_state;
00540 
00541     char buf[BUFSIZ];
00542 
00543     xdot_style (job);
00544     xdot_pencolor (job);
00545     if (filled) {
00546         xdot_fillcolor (job);
00547         agxbput(xbufs[emit_state], "E ");
00548     }
00549     else
00550         agxbput(xbufs[emit_state], "e ");
00551     output_point(xbufs[emit_state], A[0]);
00552     sprintf(buf, "%d %d ", ROUND(A[1].x - A[0].x), ROUND(A[1].y - A[0].y));
00553     agxbput(xbufs[emit_state], buf);
00554 }
00555 
00556 static void xdot_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start, int arrow_at_end, int filled)
00557 {
00558     xdot_style (job);
00559     xdot_pencolor (job);
00560     if (filled) {
00561         xdot_fillcolor (job);
00562         xdot_points(job, 'b', A, n);   /* NB - 'B' & 'b' are reversed in comparison to the other items */
00563     }
00564     else
00565         xdot_points(job, 'B', A, n);
00566 }
00567 
00568 static void xdot_polygon(GVJ_t * job, pointf * A, int n, int filled)
00569 {
00570     xdot_style (job);
00571     xdot_pencolor (job);
00572     if (filled) {
00573         xdot_fillcolor (job);
00574         xdot_points(job, 'P', A, n);
00575     }
00576     else
00577         xdot_points(job, 'p', A, n);
00578 }
00579 
00580 static void xdot_polyline(GVJ_t * job, pointf * A, int n)
00581 {
00582     xdot_style (job);
00583     xdot_pencolor (job);
00584     xdot_points(job, 'L', A, n);
00585 }
00586 
00587 void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
00588 {
00589     emit_state_t emit_state = job->obj->emit_state;
00590     char buf[BUFSIZ];
00591     
00592     agxbput(xbufs[emit_state], "I ");
00593     output_point(xbufs[emit_state], b.LL);
00594     sprintf(buf, "%d %d ", ROUND(b.UR.x - b.LL.x), ROUND(b.UR.y - b.LL.y));
00595     agxbput(xbufs[emit_state], buf);
00596     xdot_str (job, "", (char*)(us->name));
00597 }
00598 
00599 gvrender_engine_t dot_engine = {
00600     0,                          /* dot_begin_job */
00601     0,                          /* dot_end_job */
00602     dot_begin_graph,
00603     dot_end_graph,
00604     0,                          /* dot_begin_layer */
00605     0,                          /* dot_end_layer */
00606     0,                          /* dot_begin_page */
00607     0,                          /* dot_end_page */
00608     0,                          /* dot_begin_cluster */
00609     0,                          /* dot_end_cluster */
00610     0,                          /* dot_begin_nodes */
00611     0,                          /* dot_end_nodes */
00612     0,                          /* dot_begin_edges */
00613     0,                          /* dot_end_edges */
00614     0,                          /* dot_begin_node */
00615     0,                          /* dot_end_node */
00616     0,                          /* dot_begin_edge */
00617     0,                          /* dot_end_edge */
00618     0,                          /* dot_begin_anchor */
00619     0,                          /* dot_end_anchor */
00620     0,                          /* dot_begin_label */
00621     0,                          /* dot_end_label */
00622     0,                          /* dot_textpara */
00623     0,                          /* dot_resolve_color */
00624     0,                          /* dot_ellipse */
00625     0,                          /* dot_polygon */
00626     0,                          /* dot_bezier */
00627     0,                          /* dot_polyline */
00628     0,                          /* dot_comment */
00629     0,                          /* dot_library_shape */
00630 };
00631 
00632 gvrender_engine_t xdot_engine = {
00633     0,                          /* xdot_begin_job */
00634     0,                          /* xdot_end_job */
00635     dot_begin_graph,
00636     dot_end_graph,
00637     0,                          /* xdot_begin_layer */
00638     0,                          /* xdot_end_layer */
00639     0,                          /* xdot_begin_page */
00640     0,                          /* xdot_end_page */
00641     0,                          /* xdot_begin_cluster */
00642     xdot_end_cluster,
00643     0,                          /* xdot_begin_nodes */
00644     0,                          /* xdot_end_nodes */
00645     0,                          /* xdot_begin_edges */
00646     0,                          /* xdot_end_edges */
00647     0,                          /* xdot_begin_node */
00648     xdot_end_node,
00649     0,                          /* xdot_begin_edge */
00650     xdot_end_edge,
00651 #ifdef NEW_XDOT
00652     xdot_begin_anchor,
00653     xdot_end_anchor,
00654 #else
00655     0,                          /* xdot_begin_anchor */
00656     0,                          /* xdot_end_anchor */
00657 #endif
00658     0,                          /* xdot_begin_label */
00659     0,                          /* xdot_end_label */
00660     xdot_textpara,
00661     0,                          /* xdot_resolve_color */
00662     xdot_ellipse,
00663     xdot_polygon,
00664     xdot_bezier,
00665     xdot_polyline,
00666     0,                          /* xdot_comment */
00667     0,                          /* xdot_library_shape */
00668 };
00669 
00670 gvrender_features_t render_features_dot = {
00671     GVRENDER_DOES_TRANSFORM,    /* not really - uses raw graph coords */  /* flags */
00672     0.,                         /* default pad - graph units */
00673     NULL,                       /* knowncolors */
00674     0,                          /* sizeof knowncolors */
00675     COLOR_STRING,               /* color_type */
00676 };
00677 
00678 gvrender_features_t render_features_xdot = {
00679     GVRENDER_DOES_TRANSFORM     /* not really - uses raw graph coords */  
00680         | GVRENDER_DOES_MAPS
00681         | GVRENDER_DOES_TARGETS
00682         | GVRENDER_DOES_TOOLTIPS, /* flags */
00683     0.,                         /* default pad - graph units */
00684     NULL,                       /* knowncolors */
00685     0,                          /* sizeof knowncolors */
00686     RGBA_BYTE,          /* color_type */
00687 };
00688 
00689 gvdevice_features_t device_features_canon = {
00690     LAYOUT_NOT_REQUIRED,        /* flags */
00691     {0.,0.},                    /* default margin - points */
00692     {0.,0.},                    /* default height, width - device units */
00693     {72.,72.},                  /* default dpi */
00694 };
00695 
00696 gvdevice_features_t device_features_dot = {
00697     0,                          /* flags */
00698     {0.,0.},                    /* default margin - points */
00699     {0.,0.},                    /* default page width, height - points */
00700     {72.,72.},                  /* default dpi */
00701 };
00702 
00703 gvplugin_installed_t gvrender_dot_types[] = {
00704     {FORMAT_DOT, "dot", 1, &dot_engine, &render_features_dot},
00705     {FORMAT_XDOT, "xdot", 1, &xdot_engine, &render_features_xdot},
00706     {0, NULL, 0, NULL, NULL}
00707 };
00708 
00709 gvplugin_installed_t gvdevice_dot_types[] = {
00710     {FORMAT_DOT, "dot:dot", 1, NULL, &device_features_dot},
00711     {FORMAT_DOT, "gv:dot", 1, NULL, &device_features_dot},
00712     {FORMAT_CANON, "canon:dot", 1, NULL, &device_features_canon},
00713     {FORMAT_PLAIN, "plain:dot", 1, NULL, &device_features_dot},
00714     {FORMAT_PLAIN_EXT, "plain-ext:dot", 1, NULL, &device_features_dot},
00715     {FORMAT_XDOT, "xdot:xdot", 1, NULL, &device_features_dot},
00716     {0, NULL, 0, NULL, NULL}
00717 };