/* Sets up a structure array that contains the Graphviz PS font name and the corresponding installed font string. */ gv_font_map* get_font_mapping(PangoFontMap * fontmap) { PostscriptAlias *ps_alias; availfont_t *gv_af_p; int j, ps_fontnames_sz = sizeof(postscript_alias) / sizeof(PostscriptAlias); gv_font_map* gv_fmap = N_NEW(ps_fontnames_sz, gv_font_map); agxbuf xb; agxbuf xb2; unsigned char buf[BUFSIZ]; unsigned char buf2[BUFSIZ]; agxbinit(&xb, BUFSIZ, buf); agxbinit(&xb2, BUFSIZ, buf2); gv_af_p = gv_get_ps_fontlist(fontmap); // get the available installed fonts /* add the Graphviz PS font name and available system font string to the array */ for (j = 0; j < ps_fontnames_sz; j++) { ps_alias = &postscript_alias[j]; gv_fmap[ps_alias->xfig_code].gv_ps_fontname = ps_alias->name; gv_fmap[ps_alias->xfig_code].gv_font = gv_get_font(gv_af_p, ps_alias, &xb, &xb2); } gv_flist_free_af(gv_af_p); agxbfree(&xb); agxbfree(&xb2); #ifndef WIN32 if (Verbose > 1) printFontMap (gv_fmap, ps_fontnames_sz); #endif return gv_fmap; }
/* processClusterEdges: * Look for cluster edges. Replace cluster edge endpoints * corresponding to a cluster with special cluster nodes. * Delete original nodes. * Return 0 if no cluster edges; 1 otherwise. */ int processClusterEdges(graph_t * g) { int rv; node_t *n; edge_t *e; graph_t *clg; agxbuf xb; Dt_t *map; unsigned char buf[SMALLBUF]; map = dtopen(&mapDisc, Dtoset); clg = agsubg(g, "__clusternodes"); agxbinit(&xb, SMALLBUF, buf); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { checkCompound(e, clg, &xb, map); } } agxbfree(&xb); dtclose(map); rv = agnnodes(clg); for (n = agfstnode(clg); n; n = agnxtnode(clg, n)) { agdelete(g, n); } agclose(clg); if (rv) SET_CLUST_EDGE(g); return rv; }
/* processClusterEdges: * Look for cluster edges. Replace cluster edge endpoints * corresponding to a cluster with special cluster nodes. * Delete original nodes. * Return 0 if no cluster edges; 1 otherwise. */ int processClusterEdges(graph_t * g) { int rv; node_t *n; node_t *nxt; edge_t *e; graph_t *clg; agxbuf xb; Dt_t *map; Dt_t *cmap = mkClustMap (g); unsigned char buf[SMALLBUF]; map = dtopen(&mapDisc, Dtoset); clg = agsubg(g, "__clusternodes",1); agbindrec(clg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); agxbinit(&xb, SMALLBUF, buf); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (IS_CLUST_NODE(n)) continue; for (e = agfstout(g, n); e; e = agnxtout(g, e)) { checkCompound(e, clg, &xb, map, cmap); } } agxbfree(&xb); dtclose(map); rv = agnnodes(clg); for (n = agfstnode(clg); n; n = nxt) { nxt = agnxtnode(clg, n); agdelete(g, n); } agclose(clg); if (rv) SET_CLUST_EDGE(g); dtclose(cmap); return rv; }
static void xd_set_style (char **s) { unsigned char buf[BUFSIZ]; agxbuf xbuf; char* p; int more; agxbinit(&xbuf, BUFSIZ, buf); while ((p = *s++)) { agxbput(&xbuf, p); while (*p) p++; p++; if (*p) { /* arguments */ agxbputc(&xbuf, '('); more = 0; while (*p) { if (more) agxbputc(&xbuf, ','); agxbput(&xbuf, p); while (*p) p++; p++; more++; } agxbputc(&xbuf, ')'); } xd_str ("S ", agxbuse(&xbuf)); } agxbfree(&xbuf); }
int clearHTMLlexer() { #ifdef HAVE_LIBEXPAT int rv = state.warn | state.error; XML_ParserFree(state.parser); agxbfree (&state.lb); return rv; #else return 1; #endif }
static void xdot_style (GVJ_t *job) { unsigned char buf0[BUFSIZ]; char buf [128]; /* enough to hold a double */ agxbuf xbuf; char* p, **s; int more; agxbinit(&xbuf, BUFSIZ, buf0); /* First, check if penwidth state is correct */ if (job->obj->penwidth != penwidth[job->obj->emit_state]) { penwidth[job->obj->emit_state] = job->obj->penwidth; agxbput (&xbuf, "setlinewidth("); sprintf (buf, "%.3f", job->obj->penwidth); xdot_trim_zeros (buf, 0); agxbput(&xbuf, buf); agxbputc (&xbuf, ')'); xdot_str (job, "S ", agxbuse(&xbuf)); } /* now process raw style, if any */ s = job->obj->rawstyle; if (!s) return; while ((p = *s++)) { if (streq(p, "filled") || streq(p, "bold") || streq(p, "setlinewidth")) continue; agxbput(&xbuf, p); while (*p) p++; p++; if (*p) { /* arguments */ agxbputc(&xbuf, '('); more = 0; while (*p) { if (more) agxbputc(&xbuf, ','); agxbput(&xbuf, p); while (*p) p++; p++; more++; } agxbputc(&xbuf, ')'); } xdot_str (job, "S ", agxbuse(&xbuf)); } agxbfree(&xbuf); }
/* initAnchor: * Save current map values * Initialize fields in job->obj pertaining to anchors. * In particular, this also sets the output rectangle. * If there is something to do, close current anchor if * necessary, start the anchor and returns 1. * Otherwise, it returns 0. * * FIX: Should we provide a tooltip if none is set, as is done * for nodes, edges, etc. ? */ static int initAnchor (GVJ_t* job, htmlenv_t* env, htmldata_t* data, boxf b, htmlmap_data_t* save, int closePrev) { obj_state_t *obj = job->obj; int changed; char* id; static int anchorId; int internalId = 0; agxbuf xb; char intbuf[30]; /* hold 64-bit decimal integer */ unsigned char buf[SMALLBUF]; save->url = obj->url; save->tooltip = obj->tooltip; save->target = obj->target; save->id = obj->id; save->explicit_tooltip = obj->explicit_tooltip; id = data->id; if (!id || !*id) { /* no external id, so use the internal one */ agxbinit(&xb, SMALLBUF, buf); if (!env->objid) { env->objid = strdup (getObjId (job, obj->u.n, &xb)); env->objid_set = 1; } agxbput (&xb, env->objid); sprintf (intbuf, "_%d", anchorId++); agxbput (&xb, intbuf); id = agxbuse (&xb); internalId = 1; } changed = initMapData (job, NULL, data->href, data->title, data->target, id, obj->u.g); if (internalId) agxbfree (&xb); if (changed) { if (closePrev && (save->url || save->explicit_tooltip)) gvrender_end_anchor(job); if (obj->url || obj->explicit_tooltip) { emit_map_rect(job, b); gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target, obj->id); } } return changed; }
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, AGRAPH, "_draw_", ""); agxset(g, xd->g_draw, agxbuse(xbufs[EMIT_GDRAW])); } if (GD_label(g)) agxset(g, xd->g_l_draw, agxbuse(xbufs[EMIT_GLABEL])); agsafeset (g, "xdotversion", xd->version_s, ""); for (i = 0; i < NUMXBUFS; i++) agxbfree(xbuf+i); free (xd); penwidth[EMIT_GDRAW] = 1; penwidth[EMIT_GLABEL] = 1; textflags[EMIT_GDRAW] = 0; textflags[EMIT_GLABEL] = 0; }
/* make_html_label: * Return non-zero if problem parsing HTML. In this case, use object name. */ int make_html_label(void *obj, textlabel_t * lp) { int rv; double wd2, ht2; boxf box; graph_t *g; htmllabel_t *lbl; htmlenv_t env; char *s; env.obj = obj; switch (agobjkind(obj)) { #ifdef WITH_CGRAPH case AGRAPH: #else case AGGRAPH: #endif env.g = ((Agraph_t *) obj)->root; break; case AGNODE: env.g = agraphof(((Agnode_t *) obj)); break; case AGEDGE: env.g = agraphof(aghead (((Agedge_t *) obj))); break; } g = env.g->root; env.finfo.size = lp->fontsize; env.finfo.name = lp->fontname; env.finfo.color = lp->fontcolor; lbl = parseHTML(lp->text, &rv, GD_charset(env.g)); if (!lbl) { /* Parse of label failed; revert to simple text label */ agxbuf xb; unsigned char buf[SMALLBUF]; agxbinit(&xb, SMALLBUF, buf); lp->html = FALSE; lp->text = strdup(nameOf(obj, &xb)); switch (lp->charset) { case CHAR_LATIN1: s = latin1ToUTF8(lp->text); break; default: /* UTF8 */ s = htmlEntityUTF8(lp->text, env.g); break; } free(lp->text); lp->text = s; make_simple_label(g, lp); agxbfree(&xb); return rv; } if (lbl->kind == HTML_TBL) { if (! lbl->u.tbl->data.pencolor && getPenColor(obj)) lbl->u.tbl->data.pencolor = strdup(getPenColor(obj)); rv |= size_html_tbl(g, lbl->u.tbl, NULL, &env); wd2 = (lbl->u.tbl->data.box.UR.x + 1) / 2; ht2 = (lbl->u.tbl->data.box.UR.y + 1) / 2; box = boxfof(-wd2, -ht2, wd2, ht2); pos_html_tbl(lbl->u.tbl, box, BOTTOM | RIGHT | TOP | LEFT); lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } else { rv |= size_html_txt(g, lbl->u.txt, &env); wd2 = (lbl->u.txt->box.UR.x + 1) / 2; ht2 = (lbl->u.txt->box.UR.y + 1) / 2; box = boxfof(-wd2, -ht2, wd2, ht2); lbl->u.txt->box = box; lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } lp->u.html = lbl; /* If the label is a table, replace label text because this may * be used for the title and alt fields in image maps. */ if (lbl->kind == HTML_TBL) { free (lp->text); lp->text = strdup ("<TABLE>"); } return rv; }
static void cleanup(void) { agxbfree(&xb); }
static boolean pango_textlayout(textspan_t * span, char **fontpath) { static char buf[1024]; /* returned in fontpath, only good until next call */ static PangoFontMap *fontmap; static PangoContext *context; static PangoFontDescription *desc; static char *fontname; static double fontsize; static gv_font_map* gv_fmap; char *fnt, *psfnt = NULL; PangoLayout *layout; PangoRectangle logical_rect; cairo_font_options_t* options; PangoFont *font; #ifdef ENABLE_PANGO_MARKUP PangoAttrList *attrs; GError *error = NULL; int flags; #endif char *text; double textlayout_scale; PostscriptAlias *pA; if (!context) { fontmap = pango_cairo_font_map_new(); gv_fmap = get_font_mapping(fontmap); #ifdef HAVE_PANGO_FONT_MAP_CREATE_CONTEXT context = pango_font_map_create_context (fontmap); #else context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP(fontmap)); #endif options=cairo_font_options_create(); cairo_font_options_set_antialias(options,CAIRO_ANTIALIAS_GRAY); cairo_font_options_set_hint_style(options,CAIRO_HINT_STYLE_FULL); cairo_font_options_set_hint_metrics(options,CAIRO_HINT_METRICS_ON); cairo_font_options_set_subpixel_order(options,CAIRO_SUBPIXEL_ORDER_BGR); pango_cairo_context_set_font_options(context, options); pango_cairo_context_set_resolution(context, FONT_DPI); cairo_font_options_destroy(options); g_object_unref(fontmap); } if (!fontname || strcmp(fontname, span->font->name) != 0 || fontsize != span->font->size) { fontname = span->font->name; fontsize = span->font->size; pango_font_description_free (desc); pA = span->font->postscript_alias; if (pA) { psfnt = fnt = gv_fmap[pA->xfig_code].gv_font; if(!psfnt) psfnt = fnt = pango_psfontResolve (pA); } else fnt = fontname; desc = pango_font_description_from_string(fnt); /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */ pango_font_description_set_size (desc, (gint)(fontsize * PANGO_SCALE)); if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */ const char *fontclass; fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font)); buf[0] = '\0'; if (psfnt) { strcat(buf, "(ps:pango "); strcat(buf, psfnt); strcat(buf, ") "); } strcat(buf, "("); strcat(buf, fontclass); strcat(buf, ") "); #ifdef HAVE_PANGO_FC_FONT_LOCK_FACE if (strcmp(fontclass, "PangoCairoFcFont") == 0) { FT_Face face; PangoFcFont *fcfont; FT_Stream stream; FT_StreamDesc streamdesc; fcfont = PANGO_FC_FONT(font); face = pango_fc_font_lock_face(fcfont); if (face) { strcat(buf, "\""); strcat(buf, face->family_name); strcat(buf, ", "); strcat(buf, face->style_name); strcat(buf, "\" "); stream = face->stream; if (stream) { streamdesc = stream->pathname; if (streamdesc.pointer) strcat(buf, (char*)streamdesc.pointer); else strcat(buf, "*no pathname available*"); } else strcat(buf, "*no stream available*"); } pango_fc_font_unlock_face(fcfont); } else #endif { PangoFontDescription *tdesc; char *tfont; tdesc = pango_font_describe(font); tfont = pango_font_description_to_string(tdesc); strcat(buf, "\""); strcat(buf, tfont); strcat(buf, "\" "); g_free(tfont); } *fontpath = buf; } } #ifdef ENABLE_PANGO_MARKUP if ((span->font) && (flags = span->font->flags)) { unsigned char buf[BUFSIZ]; agxbuf xb; agxbinit(&xb, BUFSIZ, buf); agxbput(&xb,"<span"); if (flags & HTML_BF) agxbput(&xb," weight=\"bold\""); if (flags & HTML_IF) agxbput(&xb," style=\"italic\""); if (flags & HTML_UL) agxbput(&xb," underline=\"single\""); if (flags & HTML_S) agxbput(&xb," strikethrough=\"true\""); agxbput (&xb,">"); if (flags & HTML_SUP) agxbput(&xb,"<sup>"); if (flags & HTML_SUB) agxbput(&xb,"<sub>"); agxbput (&xb,xml_string0(span->str, TRUE)); if (flags & HTML_SUB) agxbput(&xb,"</sub>"); if (flags & HTML_SUP) agxbput(&xb,"</sup>"); agxbput (&xb,"</span>"); if (!pango_parse_markup (agxbuse(&xb), -1, 0, &attrs, &text, NULL, &error)) { fprintf (stderr, "Error - pango_parse_markup: %s\n", error->message); text = span->str; attrs = NULL; } agxbfree (&xb); } else { text = span->str; attrs = NULL; } #else text = span->str; #endif layout = pango_layout_new (context); span->layout = (void *)layout; /* layout free with textspan - see labels.c */ span->free_layout = pango_free_layout; /* function for freeing pango layout */ pango_layout_set_text (layout, text, -1); pango_layout_set_font_description (layout, desc); #ifdef ENABLE_PANGO_MARKUP if (attrs) pango_layout_set_attributes (layout, attrs); #endif pango_layout_get_extents (layout, NULL, &logical_rect); /* if pango doesn't like the font then it sets width=0 but height = garbage */ if (logical_rect.width == 0) logical_rect.height = 0; textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE); span->size.x = (int)(logical_rect.width * textlayout_scale + 1); /* round up so that width/height are never too small */ span->size.y = (int)(logical_rect.height * textlayout_scale + 1); /* FIXME -- Horrible kluge !!! */ /* For now we are using pango for single line blocks only. * The logical_rect.height seems to be too high from the font metrics on some platforms. * Use an assumed height based on the point size. */ span->size.y = (int)(span->font->size * 1.1 + .5); /* The y offset from baseline to 0,0 of the bitmap representation */ #if !defined(WIN32) && defined PANGO_VERSION_MAJOR && (PANGO_VERSION_MAJOR >= 1) span->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale; #else { /* do it the hard way on rhel5/centos5 */ PangoLayoutIter *iter = pango_layout_get_iter (layout); span->yoffset_layout = pango_layout_iter_get_baseline (iter) * textlayout_scale; } #endif /* The distance below midline for y centering of text strings */ span->yoffset_centerline = 0.2 * span->font->size; if (logical_rect.width == 0) return FALSE; return TRUE; }
/* dotneato_args_initialize" * Scan argv[] for allowed flags. * Return 0 on success; v+1 if calling function should call exit(v). * If -c is set, config file is created and we exit. */ int dotneato_args_initialize(GVC_t * gvc, int argc, char **argv) { char c, *rest, *layout; const char *val; int i, v, nfiles; unsigned char buf[SMALLBUF]; agxbuf xb; int Kflag = 0; /* establish if we are running in a CGI environment */ HTTPServerEnVar = getenv("SERVER_NAME"); /* establish Gvfilepath, if any */ Gvfilepath = getenv("GV_FILE_PATH"); gvc->common.cmdname = dotneato_basename(argv[0]); if (gvc->common.verbose) { fprintf(stderr, "%s - %s version %s (%s)\n", gvc->common.cmdname, gvc->common.info[0], gvc->common.info[1], gvc->common.info[2]); } /* configure for available plugins */ /* needs to know if "dot -c" is set (gvc->common.config) */ /* must happen before trying to select any plugins */ if (gvc->common.config) { gvconfig(gvc, gvc->common.config); exit (0); } /* feed the globals */ Verbose = gvc->common.verbose; CmdName = gvc->common.cmdname; nfiles = 0; for (i = 1; i < argc; i++) if (argv[i] && argv[i][0] != '-') nfiles++; gvc->input_filenames = N_NEW(nfiles + 1, char *); nfiles = 0; agxbinit(&xb, SMALLBUF, buf); for (i = 1; i < argc; i++) { if (argv[i] && argv[i][0] == '-') { rest = &(argv[i][2]); switch (c = argv[i][1]) { case 'G': if (*rest) global_def(&xb, rest, AGRAPH, agattr); else { fprintf(stderr, "Missing argument for -G flag\n"); return (dotneato_usage(1)); } break; case 'N': if (*rest) global_def(&xb, rest, AGNODE,agattr); else { fprintf(stderr, "Missing argument for -N flag\n"); return (dotneato_usage(1)); } break; case 'E': if (*rest) global_def(&xb, rest, AGEDGE,agattr); else { fprintf(stderr, "Missing argument for -E flag\n"); return (dotneato_usage(1)); } break; case 'T': val = getFlagOpt(argc, argv, &i); if (!val) { fprintf(stderr, "Missing argument for -T flag\n"); return (dotneato_usage(1)); } v = gvjobs_output_langname(gvc, val); if (!v) { fprintf(stderr, "Format: \"%s\" not recognized. Use one of:%s\n", val, gvplugin_list(gvc, API_device, val)); if (GvExitOnUsage) exit(1); return(2); } break; case 'K': val = getFlagOpt(argc, argv, &i); if (!val) { fprintf(stderr, "Missing argument for -K flag\n"); return (dotneato_usage(1)); } v = gvlayout_select(gvc, val); if (v == NO_SUPPORT) { fprintf(stderr, "There is no layout engine support for \"%s\"\n", val); if (streq(val, "dot")) { fprintf(stderr, "Perhaps \"dot -c\" needs to be run (with installer's privileges) to register the plugins?\n"); } else { fprintf(stderr, "Use one of:%s\n", gvplugin_list(gvc, API_layout, val)); } if (GvExitOnUsage) exit(1); return(2); } Kflag = 1; break; case 'P': P_graph = gvplugin_graph(gvc); break; case 'V': fprintf(stderr, "%s - %s version %s (%s)\n", gvc->common.cmdname, gvc->common.info[0], gvc->common.info[1], gvc->common.info[2]); if (GvExitOnUsage) exit(0); return (1); break; case 'l': val = getFlagOpt(argc, argv, &i); if (!val) { fprintf(stderr, "Missing argument for -l flag\n"); return (dotneato_usage(1)); } use_library(gvc, val); break; case 'o': val = getFlagOpt(argc, argv, &i); if (! gvc->common.auto_outfile_names) gvjobs_output_filename(gvc, val); break; case 'q': if (*rest) { v = atoi(rest); if (v <= 0) { fprintf(stderr, "Invalid parameter \"%s\" for -q flag - ignored\n", rest); } else if (v == 1) agseterr(AGERR); else agseterr(AGMAX); } else agseterr(AGERR); break; case 's': if (*rest) { PSinputscale = atof(rest); if (PSinputscale < 0) { fprintf(stderr, "Invalid parameter \"%s\" for -s flag\n", rest); return (dotneato_usage(1)); } else if (PSinputscale == 0) PSinputscale = POINTS_PER_INCH; } else PSinputscale = POINTS_PER_INCH; break; case 'x': Reduce = TRUE; break; case 'y': Y_invert = TRUE; break; case '?': return (dotneato_usage(0)); break; default: agerr(AGERR, "%s: option -%c unrecognized\n\n", gvc->common.cmdname, c); return (dotneato_usage(1)); } } else if (argv[i]) gvc->input_filenames[nfiles++] = argv[i]; } agxbfree (&xb); /* if no -K, use cmd name to set layout type */ if (!Kflag) { layout = gvc->common.cmdname; if (streq(layout, "dot_static") || streq(layout, "dot_builtins") || streq(layout, "lt-dot") || streq(layout, "lt-dot_builtins") || streq(layout, "") /* when run as a process from Gvedit on Windows */ ) layout = "dot"; i = gvlayout_select(gvc, layout); if (i == NO_SUPPORT) { fprintf(stderr, "There is no layout engine support for \"%s\"\n", layout); if (streq(layout, "dot")) fprintf(stderr, "Perhaps \"dot -c\" needs to be run (with installer's privileges) to register the plugins?\n"); else fprintf(stderr, "Use one of:%s\n", gvplugin_list(gvc, API_layout, "")); if (GvExitOnUsage) exit(1); return(2); } } /* if no -Txxx, then set default format */ if (!gvc->jobs || !gvc->jobs->output_langname) { v = gvjobs_output_langname(gvc, "dot"); if (!v) { // assert(v); /* "dot" should always be available as an output format */ fprintf(stderr, "Unable to find even the default \"-Tdot\" renderer. Has the config\nfile been generated by running \"dot -c\" with installer's priviledges?\n"); return(2); } } /* set persistent attributes here (if not already set from command line options) */ if (!agattr(NULL, AGNODE, "label", 0)) agattr(NULL, AGNODE, "label", NODENAME_ESC); return 0; }
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 */ agxbuf xb; node_t *n; edge_t *e; point pt; e_arrows = s_arrows = 0; setYInvert(g); agxbinit(&xb, BUFSIZ, xbuffer); safe_dcl(g, g->proto->n, "pos", "", agnodeattr); safe_dcl(g, g->proto->n, "rects", "", agnodeattr); N_width = safe_dcl(g, g->proto->n, "width", "", agnodeattr); N_height = safe_dcl(g, g->proto->n, "height", "", agnodeattr); safe_dcl(g, g->proto->e, "pos", "", agedgeattr); if (GD_has_labels(g) & EDGE_LABEL) safe_dcl(g, g->proto->e, "lp", "", agedgeattr); if (GD_has_labels(g) & HEAD_LABEL) safe_dcl(g, g->proto->e, "head_lp", "", agedgeattr); if (GD_has_labels(g) & TAIL_LABEL) safe_dcl(g, g->proto->e, "tail_lp", "", agedgeattr); if (GD_label(g)) { safe_dcl(g, g, "lp", "", agraphattr); if (GD_label(g)->text[0]) { pt = GD_label(g)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(g, "lp", buf); } } safe_dcl(g, g, "bb", "", agraphattr); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { sprintf(buf, "%d,%d", ND_coord_i(n).x, YDIR(ND_coord_i(n).y)); agset(n, "pos", buf); sprintf(buf, "%.2f", PS2INCH(ND_ht_i(n))); agxset(n, N_height->index, buf); sprintf(buf, "%.2f", PS2INCH(ND_lw_i(n) + ND_rw_i(n))); agxset(n, N_width->index, buf); if (strcmp(ND_shape(n)->name, "record") == 0) { set_record_rects(n, ND_shape_info(n), &xb); agxbpop(&xb); /* get rid of last space */ agset(n, "rects", agxbuse(&xb)); } else { polygon_t *poly; int i; if (N_vertices && isPolygon(n)) { poly = (polygon_t *) ND_shape_info(n); sides = poly->sides; if (sides < 3) { char *p = agget(n, "samplepoints"); if (p) sides = atoi(p); else sides = 8; if (sides < 3) sides = 8; } for (i = 0; i < sides; i++) { if (i > 0) agxbputc(&xb, ' '); if (poly->sides >= 3) sprintf(buf, "%.3f %.3f", PS2INCH(poly->vertices[i].x), YFDIR(PS2INCH(poly->vertices[i].y))); else sprintf(buf, "%.3f %.3f", ND_width(n) / 2.0 * cos(i / (double) sides * PI * 2.0), YFDIR(ND_height(n) / 2.0 * sin(i / (double) sides * PI * 2.0))); agxbput(&xb, buf); } agxset(n, N_vertices->index, agxbuse(&xb)); } } if (State >= GVSPLINES) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (ED_edge_type(e) == IGNORED) continue; if (ED_spl(e) == NULL) continue; /* reported in postproc */ for (i = 0; i < ED_spl(e)->size; i++) { if (i > 0) agxbputc(&xb, ';'); if (ED_spl(e)->list[i].sflag) { s_arrows = 1; sprintf(buf, "s,%d,%d ", ED_spl(e)->list[i].sp.x, YDIR(ED_spl(e)->list[i].sp.y)); agxbput(&xb, buf); } if (ED_spl(e)->list[i].eflag) { e_arrows = 1; sprintf(buf, "e,%d,%d ", ED_spl(e)->list[i].ep.x, YDIR(ED_spl(e)->list[i].ep.y)); agxbput(&xb, buf); } for (j = 0; j < ED_spl(e)->list[i].size; j++) { if (j > 0) agxbputc(&xb, ' '); pt = ED_spl(e)->list[i].list[j]; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agxbput(&xb, buf); } } agset(e, "pos", agxbuse(&xb)); if (ED_label(e)) { pt = ED_label(e)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(e, "lp", buf); } if (ED_head_label(e)) { pt = ED_head_label(e)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(e, "head_lp", buf); } if (ED_tail_label(e)) { pt = ED_tail_label(e)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(e, "tail_lp", buf); } } } } rec_attach_bb(g); agxbfree(&xb); if (HAS_CLUST_EDGE(g)) undoClusterEdges(g); *sp = s_arrows; *ep = e_arrows; }
static void xdot_gradient_fillcolor (GVJ_t* job, int filled, pointf* A, int n) { unsigned char buf0[BUFSIZ]; agxbuf xbuf; obj_state_t* obj = job->obj; float angle = obj->gradient_angle * M_PI / 180; float r1,r2; pointf G[2],c1,c2; if (xd->version < 14) { xdot_fillcolor (job); return; } agxbinit(&xbuf, BUFSIZ, buf0); if (filled == GRADIENT) { get_gradient_points(A, G, n, angle, 2); agxbputc (&xbuf, '['); xdot_point (&xbuf, G[0]); xdot_point (&xbuf, G[1]); } else { get_gradient_points(A, G, n, 0, 3); //r1 is inner radius, r2 is outer radius r1 = G[1].x; r2 = G[1].y; if (angle == 0) { c1.x = G[0].x; c1.y = G[0].y; } else { c1.x = G[0].x + (r2/4) * cos(angle); c1.y = G[0].y + (r2/4) * sin(angle); } c2.x = G[0].x; c2.y = G[0].y; r1 = r2/4; agxbputc(&xbuf, '('); xdot_point (&xbuf, c1); xdot_num (&xbuf, r1); xdot_point (&xbuf, c2); xdot_num (&xbuf, r2); } agxbput(&xbuf, "2 "); if (obj->gradient_frac > 0) { xdot_color_stop (&xbuf, obj->gradient_frac, &obj->fillcolor); xdot_color_stop (&xbuf, obj->gradient_frac, &obj->stopcolor); } else { xdot_color_stop (&xbuf, 0, &obj->fillcolor); xdot_color_stop (&xbuf, 1, &obj->stopcolor); } agxbpop(&xbuf); if (filled == GRADIENT) agxbputc(&xbuf, ']'); else agxbputc(&xbuf, ')'); xdot_str (job, "C ", agxbuse(&xbuf)); agxbfree(&xbuf); }
/* make_html_label: * Return non-zero if problem parsing HTML. In this case, use object name. */ int make_html_label(graph_t *g, textlabel_t * lp, void *obj) { int rv; int wd2, ht2; box box; htmllabel_t *lbl; htmlenv_t env; env.obj = obj; switch (agobjkind(obj)) { case AGGRAPH: env.g = ((Agraph_t *) obj)->root; break; case AGNODE: env.g = ((Agnode_t *) obj)->graph; break; case AGEDGE: env.g = ((Agedge_t *) obj)->head->graph; break; } env.finfo.size = lp->fontsize; env.finfo.name = lp->fontname; env.finfo.color = lp->fontcolor; lbl = parseHTML(lp->text, &rv, GD_charset(env.g)); if (!lbl) { /* Parse of label failed; revert to simple text label */ agxbuf xb; unsigned char buf[SMALLBUF]; agxbinit(&xb, SMALLBUF, buf); lp->html = FALSE; lp->text = strdup(nameOf(obj, &xb)); size_label(env.g, lp); agxbfree(&xb); return rv; } if (lbl->kind == HTML_TBL) { lbl->u.tbl->data.pencolor = getPenColor(obj); rv |= size_html_tbl(g, lbl->u.tbl, NULL, &env); wd2 = (lbl->u.tbl->data.box.UR.x + 1) / 2; ht2 = (lbl->u.tbl->data.box.UR.y + 1) / 2; box = boxof(-wd2, -ht2, wd2, ht2); pos_html_tbl(lbl->u.tbl, box, BOTTOM | RIGHT | TOP | LEFT); lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } else { rv |= size_html_txt(g, lbl->u.txt, &env); wd2 = (lbl->u.txt->box.UR.x + 1) / 2; ht2 = (lbl->u.txt->box.UR.y + 1) / 2; box = boxof(-wd2, -ht2, wd2, ht2); lbl->u.txt->box = box; lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } lp->u.html = lbl; /* If the label is a table, replace label text because this may * be used for the title and alt fields in image maps. */ if (lbl->kind == HTML_TBL) { free (lp->text); lp->text = strdup ("<TABLE>"); } return rv; }
/* * 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. */ void extend_attrs(GVJ_t * job, graph_t *g, int s_arrows, int e_arrows) { 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]; gvc = job->gvc; 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(&xbuf0, BUFSIZ, buf0); agxbinit(&xbuf1, BUFSIZ, buf1); agxbinit(&xbuf2, BUFSIZ, buf2); agxbinit(&xbuf3, BUFSIZ, buf3); agxbinit(&xbuf4, BUFSIZ, buf4); agxbinit(&xbuf5, 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_edge_graphics (job, e); 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), (void *) g); agxset(g, g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL])); } emit_clusters(job, g, 0); agxbfree(&xbuf0); agxbfree(&xbuf1); agxbfree(&xbuf2); agxbfree(&xbuf3); agxbfree(&xbuf4); agxbfree(&xbuf5); }
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 */ agxbuf xb; node_t *n; edge_t *e; pointf ptf; int dim3 = (GD_odim(g) >= 3); Agsym_t* bbsym; gv_fixLocale (1); e_arrows = s_arrows = 0; setYInvert(g); agxbinit(&xb, BUFSIZ, xbuffer); safe_dcl(g, AGNODE, "pos", ""); safe_dcl(g, AGNODE, "rects", ""); N_width = safe_dcl(g, AGNODE, "width", ""); N_height = safe_dcl(g, AGNODE, "height", ""); safe_dcl(g, AGEDGE, "pos", ""); if (GD_has_labels(g) & NODE_XLABEL) safe_dcl(g, AGNODE, "xlp", ""); if (GD_has_labels(g) & EDGE_LABEL) safe_dcl(g, AGEDGE, "lp", ""); if (GD_has_labels(g) & EDGE_XLABEL) safe_dcl(g, AGEDGE, "xlp", ""); if (GD_has_labels(g) & HEAD_LABEL) safe_dcl(g, AGEDGE, "head_lp", ""); if (GD_has_labels(g) & TAIL_LABEL) safe_dcl(g, AGEDGE, "tail_lp", ""); if (GD_label(g)) { safe_dcl(g, AGRAPH, "lp", ""); safe_dcl(g, AGRAPH, "lwidth", ""); safe_dcl(g, AGRAPH, "lheight", ""); if (GD_label(g)->text[0]) { ptf = GD_label(g)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(g, "lp", buf); ptf = GD_label(g)->dimen; sprintf(buf, "%.2f", PS2INCH(ptf.x)); agset(g, "lwidth", buf); sprintf(buf, "%.2f", PS2INCH(ptf.y)); agset(g, "lheight", buf); } } bbsym = safe_dcl(g, AGRAPH, "bb", ""); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (dim3) { int k; sprintf(buf, "%.5g,%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y), POINTS_PER_INCH*(ND_pos(n)[2])); agxbput (&xb, buf); for (k = 3; k < GD_odim(g); k++) { sprintf(buf, ",%.5g", POINTS_PER_INCH*(ND_pos(n)[k])); agxbput (&xb, buf); } agset(n, "pos", agxbuse(&xb)); } else { sprintf(buf, "%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y)); agset(n, "pos", buf); } sprintf(buf, "%.5g", PS2INCH(ND_ht(n))); agxset(n, N_height, buf); sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n))); agxset(n, N_width, buf); if (ND_xlabel(n) && ND_xlabel(n)->set) { ptf = ND_xlabel(n)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(n, "xlp", buf); } if (strcmp(ND_shape(n)->name, "record") == 0) { set_record_rects(n, ND_shape_info(n), &xb); agxbpop(&xb); /* get rid of last space */ agset(n, "rects", agxbuse(&xb)); } else { polygon_t *poly; int i; if (N_vertices && isPolygon(n)) { poly = (polygon_t *) ND_shape_info(n); sides = poly->sides; if (sides < 3) { char *p = agget(n, "samplepoints"); if (p) sides = atoi(p); else sides = 8; if (sides < 3) sides = 8; } for (i = 0; i < sides; i++) { if (i > 0) agxbputc(&xb, ' '); if (poly->sides >= 3) sprintf(buf, "%.5g %.5g", PS2INCH(poly->vertices[i].x), YFDIR(PS2INCH(poly->vertices[i].y))); else sprintf(buf, "%.5g %.5g", ND_width(n) / 2.0 * cos(i / (double) sides * M_PI * 2.0), YFDIR(ND_height(n) / 2.0 * sin(i / (double) sides * M_PI * 2.0))); agxbput(&xb, buf); } agxset(n, N_vertices, agxbuse(&xb)); } } if (State >= GVSPLINES) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (ED_edge_type(e) == IGNORED) continue; if (ED_spl(e) == NULL) continue; /* reported in postproc */ for (i = 0; i < ED_spl(e)->size; i++) { if (i > 0) agxbputc(&xb, ';'); if (ED_spl(e)->list[i].sflag) { s_arrows = 1; sprintf(buf, "s,%.5g,%.5g ", ED_spl(e)->list[i].sp.x, YDIR(ED_spl(e)->list[i].sp.y)); agxbput(&xb, buf); } if (ED_spl(e)->list[i].eflag) { e_arrows = 1; sprintf(buf, "e,%.5g,%.5g ", ED_spl(e)->list[i].ep.x, YDIR(ED_spl(e)->list[i].ep.y)); agxbput(&xb, buf); } for (j = 0; j < ED_spl(e)->list[i].size; j++) { if (j > 0) agxbputc(&xb, ' '); ptf = ED_spl(e)->list[i].list[j]; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agxbput(&xb, buf); } } agset(e, "pos", agxbuse(&xb)); if (ED_label(e)) { ptf = ED_label(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "lp", buf); } if (ED_xlabel(e) && ED_xlabel(e)->set) { ptf = ED_xlabel(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "xlp", buf); } if (ED_head_label(e)) { ptf = ED_head_label(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "head_lp", buf); } if (ED_tail_label(e)) { ptf = ED_tail_label(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "tail_lp", buf); } } } } rec_attach_bb(g, bbsym); agxbfree(&xb); if (HAS_CLUST_EDGE(g)) undoClusterEdges(g); *sp = s_arrows; *ep = e_arrows; gv_fixLocale (0); }