]> granicus.if.org Git - graphviz/commitdiff
Fully integrate xdot output into the plugin architecture, fixing a variety
authorerg <devnull@localhost>
Mon, 6 Nov 2006 21:58:55 +0000 (21:58 +0000)
committererg <devnull@localhost>
Mon, 6 Nov 2006 21:58:55 +0000 (21:58 +0000)
of bugs on the way.

lib/common/emit.c
lib/common/output.c
lib/common/render.h
lib/gvc/gvcjob.h
plugin/core/gvrender_core_dot.c

index 6dc9f576f9fca8393b7e553ce3ee265e22271cd5..df91d8e983af4df26d0e458aaa4f5e0b2ded245a 100644 (file)
@@ -1300,7 +1300,7 @@ static char* default_pencolor(char *pencolor, char *deflt)
     return buf;
 }
 
-void emit_edge_graphics(GVJ_t * job, edge_t * e)
+static void emit_edge_graphics(GVJ_t * job, edge_t * e)
 {
     int i, j, cnum, numc = 0;
     char *color, *pencolor, *fillcolor, *style;
@@ -2361,7 +2361,7 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
        if (obj->url || obj->explicit_tooltip)
            gvrender_end_anchor(job);
        if (GD_label(sg))
-           emit_label(job, EMIT_GLABEL, GD_label(sg));
+           emit_label(job, EMIT_CLABEL, GD_label(sg));
 
        if (flags & EMIT_PREORDER) {
            for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
index c418b56a3ab5c4a8ba16aa23e175236c73b2652d..2c95c896d328f4f41ca158fcee34afb670678f08 100644 (file)
 #include "render.h"
 #include "agxbuf.h"
 
-static int e_arrows;           /* graph has edges with end arrows */
-static int s_arrows;           /* graph has edges with start arrows */
-static attrsym_t *g_draw;
-static attrsym_t *g_l_draw;
 
 static void printptf(FILE * f, point pt)
 {
@@ -149,7 +145,7 @@ static void set_record_rects(node_t * n, field_t * f, agxbuf * xb)
 static void rec_attach_bb(graph_t * g)
 {
     int c;
-    char buf[32];
+    char buf[BUFSIZ];
     point pt;
 
     sprintf(buf, "%d,%d,%d,%d", GD_bb(g).LL.x, GD_bb(g).LL.y,
@@ -164,8 +160,10 @@ static void rec_attach_bb(graph_t * g)
        rec_attach_bb(GD_clust(g)[c]);
 }
 
-void attach_attrs(graph_t * g)
+void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep)
 {
+    int e_arrows;              /* graph has edges with end arrows */
+    int s_arrows;              /* graph has edges with start arrows */
     int i, j, sides;
     char buf[BUFSIZ];          /* Used only for small strings */
     unsigned char xbuffer[BUFSIZ];     /* Initial buffer for xb */
@@ -297,155 +295,14 @@ void attach_attrs(graph_t * g)
 
     if (HAS_CLUST_EDGE(g))
        undoClusterEdges(g);
+    
+    *sp = s_arrows;
+    *ep = e_arrows;
 }
 
-static int isInvis(char *style)
+void attach_attrs(graph_t * g)
 {
-    char **styles = 0;
-    char **sp;
-    char *p;
-
-    if (style[0]) {
-        styles = parse_style(style);
-        sp = styles;
-        while ((p = *sp++)) {
-            if (streq(p, "invis"))
-                return 1;
-        }
-    }
-    return 0;
+    int e, s;
+    attach_attrs_and_arrows (g, &s, &e);
 }
 
-/* 
- * John M. suggests:
- * You might want to add four more:
- *
- * _ohdraw_ (optional head-end arrow for edges)
- * _ohldraw_ (optional head-end label for edges)
- * _otdraw_ (optional tail-end arrow for edges)
- * _otldraw_ (optional tail-end label for edges)
- * 
- * that would be generated when an additional option is supplied to dot, etc. and 
- * these would be the arrow/label positions to use if a user want to flip the 
- * direction of an edge (as sometimes is there want).
- * 
- * N.B. John M. asks:
- *   By the way, I don't know if you ever plan to add other letters for 
- * the xdot spec, but could you reserve "a" and also "A" (for  attribute), 
- * "n" and also "N" (for numeric), "w" (for sWitch),  "s" (for string) 
- * and "t" (for tooltip) and "x" (for position). We use  those letters in 
- * our drawing spec (and also "<" and ">"), so if you  start generating 
- * output with them, it could break what we have. 
- */
-
-#define XDOTVERSION "1.1"
-
-void extend_attrs(GVJ_t * job, graph_t *g, agxbuf** xbufs)
-{
-    node_t *n;
-    edge_t *e;
-    attrsym_t *n_draw = NULL;
-    attrsym_t *n_l_draw = NULL;
-    attrsym_t *e_draw = NULL;
-    attrsym_t *h_draw = NULL;
-    attrsym_t *t_draw = NULL;
-    attrsym_t *e_l_draw = NULL;
-    attrsym_t *hl_draw = NULL;
-    attrsym_t *tl_draw = NULL;
-    unsigned char buf0[BUFSIZ];
-    unsigned char buf1[BUFSIZ];
-    unsigned char buf2[BUFSIZ];
-    unsigned char buf3[BUFSIZ];
-    unsigned char buf4[BUFSIZ];
-    unsigned char buf5[BUFSIZ];
-
-    agsafeset (g, "xdotversion", XDOTVERSION, "");
-    if (GD_has_labels(g) & GRAPH_LABEL)
-        g_l_draw = safe_dcl(g, g, "_ldraw_", "", agraphattr);
-    else
-        g_l_draw = NULL;
-    if (GD_n_cluster(g))
-        g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
-    else
-        g_draw = NULL;
-
-    n_draw = safe_dcl(g, g->proto->n, "_draw_", "", agnodeattr);
-    n_l_draw = safe_dcl(g, g->proto->n, "_ldraw_", "", agnodeattr);
-
-    e_draw = safe_dcl(g, g->proto->e, "_draw_", "", agedgeattr);
-    if (e_arrows)
-        h_draw = safe_dcl(g, g->proto->e, "_hdraw_", "", agedgeattr);
-    if (s_arrows)
-        t_draw = safe_dcl(g, g->proto->e, "_tdraw_", "", agedgeattr);
-    if (GD_has_labels(g) & EDGE_LABEL)
-        e_l_draw = safe_dcl(g, g->proto->e, "_ldraw_", "", agedgeattr);
-    if (GD_has_labels(g) & HEAD_LABEL)
-        hl_draw = safe_dcl(g, g->proto->e, "_hldraw_", "", agedgeattr);
-    if (GD_has_labels(g) & TAIL_LABEL)
-        tl_draw = safe_dcl(g, g->proto->e, "_tldraw_", "", agedgeattr);
-
-    agxbinit(xbufs[0], BUFSIZ, buf0);
-    agxbinit(xbufs[1], BUFSIZ, buf1);
-    agxbinit(xbufs[2], BUFSIZ, buf2);
-    agxbinit(xbufs[3], BUFSIZ, buf3);
-    agxbinit(xbufs[4], BUFSIZ, buf4);
-    agxbinit(xbufs[5], BUFSIZ, buf5);
-
-    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
-        if (ND_shape(n) && !isInvis(late_string(n, N_style, ""))) {
-            ND_shape(n)->fns->codefn(job, n);
-            agxset(n, n_draw->index, agxbuse(xbufs[EMIT_NDRAW]));
-            agxset(n, n_l_draw->index, agxbuse(xbufs[EMIT_NLABEL]));
-        }
-        if (State < GVSPLINES)
-            continue;
-        for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
-            if (ED_edge_type(e) == IGNORED)
-                continue;
-            if (isInvis(late_string(e, E_style, "")))
-                continue;
-            if (ED_spl(e) == NULL)
-                continue;
-
-            emit_begin_edge (job, e);
-            emit_edge_graphics (job, e);
-            emit_end_edge (job);
-            agxset(e, e_draw->index, agxbuse(xbufs[EMIT_EDRAW]));
-            if (t_draw) agxset(e, t_draw->index, agxbuse(xbufs[EMIT_TDRAW]));
-            if (h_draw) agxset(e, h_draw->index, agxbuse(xbufs[EMIT_HDRAW]));
-            if (e_l_draw) agxset(e, e_l_draw->index,agxbuse(xbufs[EMIT_ELABEL]));
-            if (tl_draw) agxset(e, tl_draw->index, agxbuse(xbufs[EMIT_TLABEL]));
-            if (hl_draw) agxset(e, hl_draw->index, agxbuse(xbufs[EMIT_HLABEL]));
-        }
-    }
-
-    emit_background(job, g);
-    if (agxblen(xbufs[EMIT_GDRAW])) {
-        if (!g_draw)
-            g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
-        agxset(g, g_draw->index, agxbuse(xbufs[EMIT_GDRAW]));
-    }
-    if (GD_label(g)) {
-        emit_label(job, EMIT_GLABEL, GD_label(g));
-        agxset(g, g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL]));
-    }
-    emit_clusters(job, g, 0);
-    agxbfree(xbufs[0]);
-    agxbfree(xbufs[1]);
-    agxbfree(xbufs[2]);
-    agxbfree(xbufs[3]);
-    agxbfree(xbufs[4]);
-    agxbfree(xbufs[5]);
-}
-
-void extend_attrs_glabel(graph_t *sg, agxbuf **xbufs)
-{
-    if (!g_draw)
-        g_draw = safe_dcl(sg->root, sg, "_draw_", "", agraphattr);
-    agxset(sg, g_draw->index, agxbuse(xbufs[EMIT_CDRAW]));
-    if (GD_label(sg)) {
-        if (!g_l_draw)
-            g_l_draw = safe_dcl(sg->root, sg, "_ldraw_", "", agraphattr);
-       agxset(sg, g_l_draw->index, agxbuse(xbufs[EMIT_CLABEL]));
-    }
-}
index 5d73f590b13266ea96cf1b8a52f307aea3e2eaa5..1615f87b9d1fa39c04dc7fedc6d2e6baf528f84b 100644 (file)
@@ -96,7 +96,6 @@ extern "C" {
     extern void emit_background(GVJ_t * job, graph_t *g);
     extern void emit_clusters(GVJ_t * job, Agraph_t * g, int flags);
     extern void emit_begin_edge(GVJ_t * job, edge_t * e);
-    extern void emit_edge_graphics(GVJ_t * job, edge_t * e);
     extern void emit_end_edge(GVJ_t * job);
     extern void emit_graph(GVJ_t * job, graph_t * g);
     extern void emit_label(GVJ_t * job, emit_state_t emit_state, textlabel_t *);
@@ -144,7 +143,6 @@ extern "C" {
     extern void translate_bb(Agraph_t *, int);
     extern void write_attributed_dot(graph_t *g, FILE *f);
     extern void write_canonical_dot(graph_t *g, FILE *f);
-    extern void write_extended_dot(GVJ_t * job, graph_t *g, FILE *f);
     extern void write_plain(GVJ_t * job, graph_t * g, FILE * f, bool extend);
 
 #if defined(_BLD_dot) && defined(_DLL)
index f991d032d6c2bf7c0c5f3d2f059b82d3a228c938..eeb8f1f26636fdef9b7f9d4e72deb80181f258aa 100644 (file)
@@ -132,35 +132,13 @@ extern "C" {
     typedef enum {MAP_RECTANGLE, MAP_CIRCLE, MAP_POLYGON, } map_shape_t;
 
     typedef enum {ROOTGRAPH_OBJTYPE, CLUSTER_OBJTYPE, NODE_OBJTYPE, EDGE_OBJTYPE} obj_type;
-#if 0
-    typedef enum {EMIT_GDRAW, EMIT_CDRAW, EMIT_NDRAW, EMIT_EDRAW, EMIT_TDRAW, EMIT_HDRAW, 
-       EMIT_GLABEL, EMIT_CLABEL, EMIT_NLABEL, EMIT_ELABEL, EMIT_TLABEL, EMIT_HLABEL} emit_state_t;
-#else
-
-/* FIXME - There are places in the core that rely on there being exactly 6 emit_states ! */
-#define emit_state_t int
-
-/* value specifying emit state */
-#define EMIT_DRAW      0
-#define EMIT_GDRAW     EMIT_DRAW
-#define EMIT_CDRAW     EMIT_DRAW
-#define EMIT_NDRAW     EMIT_DRAW
-#define EMIT_EDRAW     EMIT_DRAW
-
-/* values specifying emit state for arrowheads */
-#define EMIT_TDRAW     1
-#define EMIT_HDRAW     2
-
-/* values specifying emit state for labels */
-#define EMIT_LABEL     3
-#define EMIT_GLABEL    EMIT_LABEL
-#define EMIT_CLABEL    EMIT_LABEL
-#define EMIT_NLABEL    EMIT_LABEL
-#define EMIT_ELABEL    EMIT_LABEL
-#define EMIT_TLABEL    4
-#define EMIT_HLABEL    5
 
-#endif
+    /* See comment in gvrender_core_dot.c */
+    typedef enum {
+       EMIT_GDRAW, EMIT_CDRAW, EMIT_TDRAW, EMIT_HDRAW, 
+       EMIT_GLABEL, EMIT_CLABEL, EMIT_TLABEL, EMIT_HLABEL,
+       EMIT_NDRAW, EMIT_EDRAW, EMIT_NLABEL, EMIT_ELABEL,  
+    } emit_state_t;
 
     typedef struct obj_state_s obj_state_t;
 
index bc7880bd0ab3bd256b68cff68358d616f1bce71a..03654bc42f36d93ec9acc1b9f4d32ac91b85b1e3 100644 (file)
 #include "utils.h"
 
 extern void attach_attrs(graph_t * g);
+extern void attach_attrs_and_arrows(graph_t*, int*, int*);
 extern char *xml_string(char *str);
 extern void write_plain(GVJ_t * job, graph_t * g, FILE * f, bool extend);
-extern void extend_attrs(GVJ_t * job, graph_t *g, agxbuf** xbufs);
-extern void extend_attrs_glabel(graph_t *sg, agxbuf **xbufs);
+
+#define GNEW(t)          (t*)malloc(sizeof(t))
 
 typedef enum { FORMAT_DOT, FORMAT_CANON, FORMAT_PLAIN, FORMAT_PLAIN_EXT, FORMAT_XDOT } format_type;
 
-static agxbuf xbuf0;
-static agxbuf xbuf1;
-static agxbuf xbuf2;
-static agxbuf xbuf3;
-static agxbuf xbuf4;
-static agxbuf xbuf5;
-static agxbuf* xbufs[6] = {
-    &xbuf0, &xbuf1,
-    &xbuf2, &xbuf3,
-    &xbuf4, &xbuf5,
+#define XDOTVERSION "1.1"
+
+#define NUMXBUFS (EMIT_HLABEL+1)
+/* There are as many xbufs as there are values of emit_state_t.
+ * However, only the first NUMXBUFS are distinct. Nodes, clusters, and
+ * edges are drawn atomically, so they share the DRAW and LABEL buffers
+ * are shared.
+ */
+static agxbuf xbuf[NUMXBUFS];
+static agxbuf* xbufs[] = {
+    xbuf+EMIT_GDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_TDRAW, xbuf+EMIT_HDRAW, 
+    xbuf+EMIT_GLABEL, xbuf+EMIT_CLABEL, xbuf+EMIT_TLABEL, xbuf+EMIT_HLABEL, 
+    xbuf+EMIT_CDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_CLABEL, xbuf+EMIT_CLABEL, 
 };
 
+typedef struct {
+    attrsym_t *g_draw;
+    attrsym_t *g_l_draw;
+    attrsym_t *n_draw;
+    attrsym_t *n_l_draw;
+    attrsym_t *e_draw;
+    attrsym_t *h_draw;
+    attrsym_t *t_draw;
+    attrsym_t *e_l_draw;
+    attrsym_t *hl_draw;
+    attrsym_t *tl_draw;
+    unsigned char buf[NUMXBUFS][BUFSIZ];
+} xdot_state_t;
+static xdot_state_t* xd;
+
 static void xdot_str (GVJ_t *job, char* pfx, char* s)
 {   
     emit_state_t emit_state = job->obj->emit_state;
@@ -125,8 +144,113 @@ static void xdot_style (GVJ_t *job)
     agxbfree(&xbuf);
 }
 
+static void xdot_end_node(GVJ_t* job)
+{
+    Agnode_t* n = job->obj->u.n; 
+    if (agxblen(xbufs[EMIT_NDRAW]))
+       agxset(n, xd->n_draw->index, agxbuse(xbufs[EMIT_NDRAW]));
+    if (agxblen(xbufs[EMIT_NLABEL]))
+       agxset(n, xd->n_l_draw->index, agxbuse(xbufs[EMIT_NLABEL]));
+}
+
+static void xdot_end_edge(GVJ_t* job)
+{
+    Agedge_t* e = job->obj->u.e; 
+
+    if (agxblen(xbufs[EMIT_EDRAW]))
+       agxset(e, xd->e_draw->index, agxbuse(xbufs[EMIT_EDRAW]));
+    if (agxblen(xbufs[EMIT_TDRAW]))
+       agxset(e, xd->t_draw->index, agxbuse(xbufs[EMIT_TDRAW]));
+    if (agxblen(xbufs[EMIT_HDRAW]))
+       agxset(e, xd->h_draw->index, agxbuse(xbufs[EMIT_HDRAW]));
+    if (agxblen(xbufs[EMIT_ELABEL]))
+       agxset(e, xd->e_l_draw->index,agxbuse(xbufs[EMIT_ELABEL]));
+    if (agxblen(xbufs[EMIT_TLABEL]))
+       agxset(e, xd->tl_draw->index, agxbuse(xbufs[EMIT_TLABEL]));
+    if (agxblen(xbufs[EMIT_HLABEL]))
+       agxset(e, xd->hl_draw->index, agxbuse(xbufs[EMIT_HLABEL]));
+}
+
+static void xdot_end_cluster(GVJ_t * job)
+{
+    Agraph_t* cluster_g = job->obj->u.sg;
+
+    agxset(cluster_g, xd->g_draw->index, agxbuse(xbufs[EMIT_CDRAW]));
+    if (GD_label(cluster_g))
+       agxset(cluster_g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_CLABEL]));
+}
+
+/* 
+ * John M. suggests:
+ * You might want to add four more:
+ *
+ * _ohdraw_ (optional head-end arrow for edges)
+ * _ohldraw_ (optional head-end label for edges)
+ * _otdraw_ (optional tail-end arrow for edges)
+ * _otldraw_ (optional tail-end label for edges)
+ * 
+ * that would be generated when an additional option is supplied to 
+ * dot, etc. and 
+ * these would be the arrow/label positions to use if a user want to flip the 
+ * direction of an edge (as sometimes is there want).
+ * 
+ * N.B. John M. asks:
+ *   By the way, I don't know if you ever plan to add other letters for 
+ * the xdot spec, but could you reserve "a" and also "A" (for  attribute), 
+ * "n" and also "N" (for numeric), "w" (for sWitch),  "s" (for string) 
+ * and "t" (for tooltip) and "x" (for position). We use  those letters in 
+ * our drawing spec (and also "<" and ">"), so if you  start generating 
+ * output with them, it could break what we have. 
+ */
+static void
+xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows)
+{
+    int i;
+
+    xd = GNEW(xdot_state_t);
+
+    if (GD_has_labels(g) & GRAPH_LABEL)
+       xd->g_l_draw = safe_dcl(g, g, "_ldraw_", "", agraphattr);
+    else
+       xd->g_l_draw = NULL;
+    if (GD_n_cluster(g))
+       xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
+    else
+       xd->g_draw = NULL;
+
+    xd->n_draw = safe_dcl(g, g->proto->n, "_draw_", "", agnodeattr);
+    xd->n_l_draw = safe_dcl(g, g->proto->n, "_ldraw_", "", agnodeattr);
+
+    xd->e_draw = safe_dcl(g, g->proto->e, "_draw_", "", agedgeattr);
+    if (e_arrows)
+       xd->h_draw = safe_dcl(g, g->proto->e, "_hdraw_", "", agedgeattr);
+    else
+       xd->h_draw = NULL;
+    if (s_arrows)
+       xd->t_draw = safe_dcl(g, g->proto->e, "_tdraw_", "", agedgeattr);
+    else
+       xd->t_draw = NULL;
+    if (GD_has_labels(g) & EDGE_LABEL)
+       xd->e_l_draw = safe_dcl(g, g->proto->e, "_ldraw_", "", agedgeattr);
+    else
+       xd->e_l_draw = NULL;
+    if (GD_has_labels(g) & HEAD_LABEL)
+       xd->hl_draw = safe_dcl(g, g->proto->e, "_hldraw_", "", agedgeattr);
+    else
+       xd->hl_draw = NULL;
+    if (GD_has_labels(g) & TAIL_LABEL)
+       xd->tl_draw = safe_dcl(g, g->proto->e, "_tldraw_", "", agedgeattr);
+    else
+       xd->tl_draw = NULL;
+
+    for (i = 0; i < NUMXBUFS; i++)
+       agxbinit(xbuf+i, BUFSIZ, xd->buf[i]);
+}
+
 static void dot_begin_graph(GVJ_t *job)
 {
+    int e_arrows;            /* graph has edges with end arrows */
+    int s_arrows;            /* graph has edges with start arrows */
     graph_t *g = job->obj->u.g;
 
     switch (job->render.id) {
@@ -141,10 +265,29 @@ static void dot_begin_graph(GVJ_t *job)
        case FORMAT_PLAIN_EXT:
            break;
        case FORMAT_XDOT:
-           attach_attrs(g);
+           attach_attrs_and_arrows(g, &s_arrows, &e_arrows);
+           xdot_begin_graph(g, s_arrows, e_arrows);
     }
 }
 
+static void xdot_end_graph(graph_t* g)
+{
+    int i;
+
+    if (agxblen(xbufs[EMIT_GDRAW])) {
+       if (!xd->g_draw)
+           xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
+       agxset(g, xd->g_draw->index, agxbuse(xbufs[EMIT_GDRAW]));
+    }
+    if (GD_label(g))
+       agxset(g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL]));
+    agsafeset (g, "xdotversion", XDOTVERSION, "");
+
+    for (i = 0; i < NUMXBUFS; i++)
+       agxbfree(xbuf+i);
+    free (xd);
+}
+
 static void dot_end_graph(GVJ_t *job)
 {
     graph_t *g = job->obj->u.g;
@@ -162,18 +305,13 @@ static void dot_end_graph(GVJ_t *job)
                agwrite(g, job->output_file);
            break;
        case FORMAT_XDOT:
-           extend_attrs(job, g, xbufs);
+           xdot_end_graph(g);
            if (!(job->flags & OUTPUT_NOT_REQUIRED))
                agwrite(g, job->output_file);
            break;
     }
 }
 
-static void xdot_end_cluster(GVJ_t *job)
-{
-    extend_attrs_glabel(job->obj->u.sg, xbufs);
-}
-
 static void xdot_textpara(GVJ_t * job, pointf p, textpara_t * para)
 {
     emit_state_t emit_state = job->obj->emit_state;
@@ -301,9 +439,9 @@ gvrender_engine_t xdot_engine = {
     0,                         /* xdot_begin_edges */
     0,                         /* xdot_end_edges */
     0,                         /* xdot_begin_node */
-    0,                         /* xdot_end_node */
+    xdot_end_node,
     0,                         /* xdot_begin_edge */
-    0,                         /* xdot_end_edge */
+    xdot_end_edge,
     0,                         /* xdot_begin_anchor */
     0,                         /* xdot_end_anchor */
     xdot_textpara,