Graphviz  2.41.20171026.1811
gvrender_core_dot.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include "config.h"
15 
16 #ifdef _WIN32
17 #include <io.h>
18 #include "compat.h"
19 #endif
20 
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 
26 #include "macros.h"
27 #include "const.h"
28 
29 #include "gvplugin_render.h"
30 #include "gvplugin_device.h"
31 #include "agxbuf.h"
32 #include "utils.h"
33 #include "gvio.h"
34 
35 #define GNEW(t) (t*)malloc(sizeof(t))
36 
37 /* #define NEW_XDOT */
38 
39 typedef enum {
47 } format_type;
48 
49 #define XDOTVERSION "1.7"
50 
51 #define NUMXBUFS (EMIT_HLABEL+1)
52 /* There are as many xbufs as there are values of emit_state_t.
53  * However, only the first NUMXBUFS are distinct. Nodes, clusters, and
54  * edges are drawn atomically, so they share the DRAW and LABEL buffers
55  */
56 static agxbuf xbuf[NUMXBUFS];
57 static agxbuf* xbufs[] = {
58  xbuf+EMIT_GDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_TDRAW, xbuf+EMIT_HDRAW,
59  xbuf+EMIT_GLABEL, xbuf+EMIT_CLABEL, xbuf+EMIT_TLABEL, xbuf+EMIT_HLABEL,
60  xbuf+EMIT_CDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_CLABEL, xbuf+EMIT_CLABEL,
61 };
62 static double penwidth [] = {
63  1, 1, 1, 1,
64  1, 1, 1, 1,
65  1, 1, 1, 1,
66 };
67 static unsigned int textflags[EMIT_ELABEL+1];
68 
69 typedef struct {
80  unsigned char buf[NUMXBUFS][BUFSIZ];
81  unsigned short version;
82  char* version_s;
83 } xdot_state_t;
84 static xdot_state_t* xd;
85 
86 static void xdot_str_xbuf (agxbuf* xb, char* pfx, char* s)
87 {
88  char buf[BUFSIZ];
89 
90  sprintf (buf, "%s%d -", pfx, (int)strlen(s));
91  agxbput(xb, buf);
92  agxbput(xb, s);
93  agxbputc(xb, ' ');
94 }
95 
96 static void xdot_str (GVJ_t *job, char* pfx, char* s)
97 {
98  emit_state_t emit_state = job->obj->emit_state;
99  xdot_str_xbuf (xbufs[emit_state], pfx, s);
100 }
101 
102 /* xdot_trim_zeros
103  * Trailing zeros are removed and decimal point, if possible.
104  * Add trailing space if addSpace is non-zero.
105  */
106 static void xdot_trim_zeros (char* buf, int addSpace)
107 {
108  char* dotp;
109  char* p;
110 
111  if ((dotp = strchr (buf,'.'))) {
112  p = dotp+1;
113  while (*p) p++; // find end of string
114  p--;
115  while (*p == '0') *p-- = '\0';
116  if (*p == '.') // If all decimals were zeros, remove ".".
117  *p = '\0';
118  else
119  p++;
120  }
121  else if (addSpace)
122  p = buf + strlen(buf);
123 
124  if (addSpace) { /* p points to null byte */
125  *p++ = ' ';
126  *p = '\0';
127  }
128 }
129 
130 /* xdot_fmt_num:
131  * Convert double to string with space at end.
132  * Trailing zeros are removed and decimal point, if possible.
133  */
134 static void xdot_fmt_num (char* buf, double v)
135 {
136  // Prevents values like -0
137  if (v > -0.00000001 && v < 0.00000001)
138  {
139  v = 0;
140  }
141  sprintf(buf, "%.02f", v);
142  xdot_trim_zeros (buf, 1);
143 }
144 
145 static void xdot_point(agxbuf *xbuf, pointf p)
146 {
147  char buf[BUFSIZ];
148  xdot_fmt_num (buf, p.x);
149  agxbput(xbuf, buf);
150  xdot_fmt_num (buf, yDir(p.y));
151  agxbput(xbuf, buf);
152 }
153 
154 static void xdot_num(agxbuf *xbuf, double v)
155 {
156  char buf[BUFSIZ];
157  xdot_fmt_num (buf, v);
158  agxbput(xbuf, buf);
159 }
160 
161 static void xdot_points(GVJ_t *job, char c, pointf * A, int n)
162 {
163  emit_state_t emit_state = job->obj->emit_state;
164  char buf[BUFSIZ];
165  int i;
166 
167  agxbputc(xbufs[emit_state], c);
168  sprintf(buf, " %d ", n);
169  agxbput(xbufs[emit_state], buf);
170  for (i = 0; i < n; i++)
171  xdot_point(xbufs[emit_state], A[i]);
172 }
173 
174 static char*
175 color2str (unsigned char rgba[4])
176 {
177  static char buf [10];
178 
179  if (rgba[3] == 0xFF)
180  sprintf (buf, "#%02x%02x%02x", rgba[0], rgba[1], rgba[2]);
181  else
182  sprintf (buf, "#%02x%02x%02x%02x", rgba[0], rgba[1], rgba[2], rgba[3]);
183  return buf;
184 }
185 
186 static void xdot_pencolor (GVJ_t *job)
187 {
188  xdot_str (job, "c ", color2str (job->obj->pencolor.u.rgba));
189 }
190 
191 static void xdot_fillcolor (GVJ_t *job)
192 {
193  xdot_str (job, "C ", color2str (job->obj->fillcolor.u.rgba));
194 }
195 
196 static void xdot_style (GVJ_t *job)
197 {
198  unsigned char buf0[BUFSIZ];
199  char buf [128]; /* enough to hold a double */
200  agxbuf xbuf;
201  char* p, **s;
202  int more;
203 
204  agxbinit(&xbuf, BUFSIZ, buf0);
205 
206  /* First, check if penwidth state is correct */
207  if (job->obj->penwidth != penwidth[job->obj->emit_state]) {
208  penwidth[job->obj->emit_state] = job->obj->penwidth;
209  agxbput (&xbuf, "setlinewidth(");
210  sprintf (buf, "%.3f", job->obj->penwidth);
211  xdot_trim_zeros (buf, 0);
212  agxbput(&xbuf, buf);
213  agxbputc (&xbuf, ')');
214  xdot_str (job, "S ", agxbuse(&xbuf));
215  }
216 
217  /* now process raw style, if any */
218  s = job->obj->rawstyle;
219  if (!s)
220  return;
221 
222  while ((p = *s++)) {
223  if (streq(p, "filled") || streq(p, "bold") || streq(p, "setlinewidth")) continue;
224  agxbput(&xbuf, p);
225  while (*p)
226  p++;
227  p++;
228  if (*p) { /* arguments */
229  agxbputc(&xbuf, '(');
230  more = 0;
231  while (*p) {
232  if (more)
233  agxbputc(&xbuf, ',');
234  agxbput(&xbuf, p);
235  while (*p) p++;
236  p++;
237  more++;
238  }
239  agxbputc(&xbuf, ')');
240  }
241  xdot_str (job, "S ", agxbuse(&xbuf));
242  }
243 
244  agxbfree(&xbuf);
245 
246 }
247 
248 static void xdot_end_node(GVJ_t* job)
249 {
250  Agnode_t* n = job->obj->u.n;
251  if (agxblen(xbufs[EMIT_NDRAW]))
252  agxset(n, xd->n_draw, agxbuse(xbufs[EMIT_NDRAW]));
253  if (agxblen(xbufs[EMIT_NLABEL]))
254  agxset(n, xd->n_l_draw, agxbuse(xbufs[EMIT_NLABEL]));
255  penwidth[EMIT_NDRAW] = 1;
256  penwidth[EMIT_NLABEL] = 1;
257  textflags[EMIT_NDRAW] = 0;
258  textflags[EMIT_NLABEL] = 0;
259 }
260 
261 static void xdot_end_edge(GVJ_t* job)
262 {
263  Agedge_t* e = job->obj->u.e;
264 
265  if (agxblen(xbufs[EMIT_EDRAW]))
266  agxset(e, xd->e_draw, agxbuse(xbufs[EMIT_EDRAW]));
267  if (agxblen(xbufs[EMIT_TDRAW]))
268  agxset(e, xd->t_draw, agxbuse(xbufs[EMIT_TDRAW]));
269  if (agxblen(xbufs[EMIT_HDRAW]))
270  agxset(e, xd->h_draw, agxbuse(xbufs[EMIT_HDRAW]));
271  if (agxblen(xbufs[EMIT_ELABEL]))
272  agxset(e, xd->e_l_draw,agxbuse(xbufs[EMIT_ELABEL]));
273  if (agxblen(xbufs[EMIT_TLABEL]))
274  agxset(e, xd->tl_draw, agxbuse(xbufs[EMIT_TLABEL]));
275  if (agxblen(xbufs[EMIT_HLABEL]))
276  agxset(e, xd->hl_draw, agxbuse(xbufs[EMIT_HLABEL]));
277  penwidth[EMIT_EDRAW] = 1;
278  penwidth[EMIT_ELABEL] = 1;
279  penwidth[EMIT_TDRAW] = 1;
280  penwidth[EMIT_HDRAW] = 1;
281  penwidth[EMIT_TLABEL] = 1;
282  penwidth[EMIT_HLABEL] = 1;
283  textflags[EMIT_EDRAW] = 0;
284  textflags[EMIT_ELABEL] = 0;
285  textflags[EMIT_TDRAW] = 0;
286  textflags[EMIT_HDRAW] = 0;
287  textflags[EMIT_TLABEL] = 0;
288  textflags[EMIT_HLABEL] = 0;
289 }
290 
291 #ifdef NEW_XDOT
292 /* xdot_begin_anchor:
293  * The encoding of which fields are present assumes that one of the fields is present,
294  * so there is never a 0 after the H.
295  */
296 static void xdot_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, char *id)
297 {
298  emit_state_t emit_state = job->obj->emit_state;
299  char buf[3]; /* very small integer */
300  unsigned int flags = 0;
301 
302  agxbput(xbufs[emit_state], "H ");
303  if (href)
304  flags |= 1;
305  if (tooltip)
306  flags |= 2;
307  if (target)
308  flags |= 4;
309  sprintf (buf, "%d ", flags);
310  agxbput(xbufs[emit_state], buf);
311  if (href)
312  xdot_str (job, "", href);
313  if (tooltip)
314  xdot_str (job, "", tooltip);
315  if (target)
316  xdot_str (job, "", target);
317 }
318 
319 static void xdot_end_anchor(GVJ_t * job)
320 {
321  emit_state_t emit_state = job->obj->emit_state;
322 
323  agxbput(xbufs[emit_state], "H 0 ");
324 }
325 #endif
326 
327 static void xdot_end_cluster(GVJ_t * job)
328 {
329  Agraph_t* cluster_g = job->obj->u.sg;
330 
331  agxset(cluster_g, xd->g_draw, agxbuse(xbufs[EMIT_CDRAW]));
332  if (GD_label(cluster_g))
333  agxset(cluster_g, xd->g_l_draw, agxbuse(xbufs[EMIT_CLABEL]));
334  penwidth[EMIT_CDRAW] = 1;
335  penwidth[EMIT_CLABEL] = 1;
336  textflags[EMIT_CDRAW] = 0;
337  textflags[EMIT_CLABEL] = 0;
338 }
339 
340 static unsigned short
341 versionStr2Version (char* str)
342 {
343  char c, buf[BUFSIZ];
344  int n = 0;
345  char* s = str;
346  unsigned short us;
347 
348  while ((c = *s++)) {
349  if (isdigit(c)) {
350  if (n < BUFSIZ-1) buf[n++] = c;
351  else {
352  agerr(AGWARN, "xdot version \"%s\" too long", str);
353  break;
354  }
355  }
356  }
357  buf[n] = '\0';
358 
359  us = atoi(buf);
360  return us;
361 }
362 
363 /*
364  * John M. suggests:
365  * You might want to add four more:
366  *
367  * _ohdraw_ (optional head-end arrow for edges)
368  * _ohldraw_ (optional head-end label for edges)
369  * _otdraw_ (optional tail-end arrow for edges)
370  * _otldraw_ (optional tail-end label for edges)
371  *
372  * that would be generated when an additional option is supplied to
373  * dot, etc. and
374  * these would be the arrow/label positions to use if a user want to flip the
375  * direction of an edge (as sometimes is there want).
376  *
377  * N.B. John M. asks:
378  * By the way, I don't know if you ever plan to add other letters for
379  * the xdot spec, but could you reserve "a" and also "A" (for attribute),
380  * "n" and also "N" (for numeric), "w" (for sWitch), "s" (for string)
381  * and "t" (for tooltip) and "x" (for position). We use those letters in
382  * our drawing spec (and also "<" and ">"), so if you start generating
383  * output with them, it could break what we have.
384  */
385 static void
386 xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows, format_type id)
387 {
388  int i, us;
389  char* s;
390 
391  xd = GNEW(xdot_state_t);
392 
393  if (id == FORMAT_XDOT14) {
394  xd->version = 14;
395  xd->version_s = "1.4";
396  }
397  else if (id == FORMAT_XDOT12) {
398  xd->version = 12;
399  xd->version_s = "1.2";
400  }
401  else if ((s = agget(g, "xdotversion")) && s[0] && ((us = versionStr2Version(s)) > 10)) {
402  xd->version = us;
403  xd->version_s = s;
404  }
405  else {
406  xd->version = versionStr2Version(XDOTVERSION);
407  xd->version_s = XDOTVERSION;
408  }
409 
410  if (GD_n_cluster(g))
411  xd->g_draw = safe_dcl(g, AGRAPH, "_draw_", "");
412  else
413  xd->g_draw = NULL;
414  if (GD_has_labels(g) & GRAPH_LABEL)
415  xd->g_l_draw = safe_dcl(g, AGRAPH, "_ldraw_", "");
416  else
417  xd->g_l_draw = NULL;
418 
419  xd->n_draw = safe_dcl(g, AGNODE, "_draw_", "");
420  xd->n_l_draw = safe_dcl(g, AGNODE, "_ldraw_", "");
421 
422  xd->e_draw = safe_dcl(g, AGEDGE, "_draw_", "");
423  if (e_arrows)
424  xd->h_draw = safe_dcl(g, AGEDGE, "_hdraw_", "");
425  else
426  xd->h_draw = NULL;
427  if (s_arrows)
428  xd->t_draw = safe_dcl(g, AGEDGE, "_tdraw_", "");
429  else
430  xd->t_draw = NULL;
432  xd->e_l_draw = safe_dcl(g, AGEDGE, "_ldraw_", "");
433  else
434  xd->e_l_draw = NULL;
435  if (GD_has_labels(g) & HEAD_LABEL)
436  xd->hl_draw = safe_dcl(g, AGEDGE, "_hldraw_", "");
437  else
438  xd->hl_draw = NULL;
439  if (GD_has_labels(g) & TAIL_LABEL)
440  xd->tl_draw = safe_dcl(g, AGEDGE, "_tldraw_", "");
441  else
442  xd->tl_draw = NULL;
443 
444  for (i = 0; i < NUMXBUFS; i++)
445  agxbinit(xbuf+i, BUFSIZ, xd->buf[i]);
446 }
447 
448 static void dot_begin_graph(GVJ_t *job)
449 {
450  int e_arrows; /* graph has edges with end arrows */
451  int s_arrows; /* graph has edges with start arrows */
452  graph_t *g = job->obj->u.g;
453 
454  switch (job->render.id) {
455  case FORMAT_DOT:
456  attach_attrs(g);
457  break;
458  case FORMAT_CANON:
459  if (HAS_CLUST_EDGE(g))
460  undoClusterEdges(g);
461  break;
462  case FORMAT_PLAIN:
463  case FORMAT_PLAIN_EXT:
464  break;
465  case FORMAT_XDOT:
466  case FORMAT_XDOT12:
467  case FORMAT_XDOT14:
468  attach_attrs_and_arrows(g, &s_arrows, &e_arrows);
469  xdot_begin_graph(g, s_arrows, e_arrows, job->render.id);
470  break;
471  }
472 }
473 
474 static void xdot_end_graph(graph_t* g)
475 {
476  int i;
477 
478  if (agxblen(xbufs[EMIT_GDRAW])) {
479  if (!xd->g_draw)
480  xd->g_draw = safe_dcl(g, AGRAPH, "_draw_", "");
481  agxset(g, xd->g_draw, agxbuse(xbufs[EMIT_GDRAW]));
482  }
483  if (GD_label(g))
484  agxset(g, xd->g_l_draw, agxbuse(xbufs[EMIT_GLABEL]));
485  agsafeset (g, "xdotversion", xd->version_s, "");
486 
487  for (i = 0; i < NUMXBUFS; i++)
488  agxbfree(xbuf+i);
489  free (xd);
490  penwidth[EMIT_GDRAW] = 1;
491  penwidth[EMIT_GLABEL] = 1;
492  textflags[EMIT_GDRAW] = 0;
493  textflags[EMIT_GLABEL] = 0;
494 }
495 
496 typedef int (*putstrfn) (void *chan, const char *str);
497 typedef int (*flushfn) (void *chan);
498 static void dot_end_graph(GVJ_t *job)
499 {
500  graph_t *g = job->obj->u.g;
501  Agiodisc_t* io_save;
502  static Agiodisc_t io;
503 
504  if (io.afread == NULL) {
505  io.afread = AgIoDisc.afread;
506  io.putstr = (putstrfn)gvputs;
507  io.flush = (flushfn)gvflush;
508  }
509 
510  io_save = g->clos->disc.io;
511  g->clos->disc.io = &io;
512  switch (job->render.id) {
513  case FORMAT_PLAIN:
514  write_plain(job, g, (FILE*)job, FALSE);
515  break;
516  case FORMAT_PLAIN_EXT:
517  write_plain(job, g, (FILE*)job, TRUE);
518  break;
519  case FORMAT_DOT:
520  case FORMAT_CANON:
521  if (!(job->flags & OUTPUT_NOT_REQUIRED))
522  agwrite(g, (FILE*)job);
523  break;
524  case FORMAT_XDOT:
525  case FORMAT_XDOT12:
526  case FORMAT_XDOT14:
527  xdot_end_graph(g);
528  if (!(job->flags & OUTPUT_NOT_REQUIRED))
529  agwrite(g, (FILE*)job);
530  break;
531  }
532  g->clos->disc.io = io_save;
533 }
534 
535 static unsigned int flag_masks[] = { 0x1F, 0x3F, 0x7F };
536 
537 static void xdot_textspan(GVJ_t * job, pointf p, textspan_t * span)
538 {
539  emit_state_t emit_state = job->obj->emit_state;
540  int flags;
541  char buf[BUFSIZ];
542  int j;
543 
544  agxbput(xbufs[emit_state], "F ");
545  xdot_fmt_num (buf, span->font->size);
546  agxbput(xbufs[emit_state], buf);
547  xdot_str (job, "", span->font->name);
548  xdot_pencolor(job);
549 
550  switch (span->just) {
551  case 'l':
552  j = -1;
553  break;
554  case 'r':
555  j = 1;
556  break;
557  default:
558  case 'n':
559  j = 0;
560  break;
561  }
562  if (span->font)
563  flags = span->font->flags;
564  else
565  flags = 0;
566  if (xd->version >= 15) {
567  unsigned int mask = flag_masks[xd->version-15];
568  unsigned int bits = flags & mask;
569  if (textflags[emit_state] != bits) {
570  sprintf (buf, "t %u ", bits);
571  agxbput(xbufs[emit_state], buf);
572  textflags[emit_state] = bits;
573  }
574  }
575 
576  p.y += span->yoffset_centerline;
577  agxbput(xbufs[emit_state], "T ");
578  xdot_point(xbufs[emit_state], p);
579  sprintf(buf, "%d ", j);
580  agxbput(xbufs[emit_state], buf);
581  xdot_fmt_num (buf, span->size.x);
582  agxbput(xbufs[emit_state], buf);
583  xdot_str (job, "", span->str);
584 }
585 
586 static void xdot_color_stop (agxbuf* xb, float v, gvcolor_t* clr)
587 {
588  char buf[BUFSIZ];
589 
590  sprintf (buf, "%.03f", v);
591  xdot_trim_zeros (buf, 1);
592  xdot_str_xbuf (xb, buf, color2str (clr->u.rgba));
593 }
594 
595 static void xdot_gradient_fillcolor (GVJ_t* job, int filled, pointf* A, int n)
596 {
597  unsigned char buf0[BUFSIZ];
598  agxbuf xbuf;
599  obj_state_t* obj = job->obj;
600  float angle = obj->gradient_angle * M_PI / 180;
601  float r1,r2;
602  pointf G[2],c1,c2;
603 
604  if (xd->version < 14) {
605  xdot_fillcolor (job);
606  return;
607  }
608 
609  agxbinit(&xbuf, BUFSIZ, buf0);
610  if (filled == GRADIENT) {
611  get_gradient_points(A, G, n, angle, 2);
612  agxbputc (&xbuf, '[');
613  xdot_point (&xbuf, G[0]);
614  xdot_point (&xbuf, G[1]);
615  }
616  else {
617  get_gradient_points(A, G, n, 0, 3);
618  //r1 is inner radius, r2 is outer radius
619  r1 = G[1].x;
620  r2 = G[1].y;
621  if (angle == 0) {
622  c1.x = G[0].x;
623  c1.y = G[0].y;
624  }
625  else {
626  c1.x = G[0].x + (r2/4) * cos(angle);
627  c1.y = G[0].y + (r2/4) * sin(angle);
628  }
629  c2.x = G[0].x;
630  c2.y = G[0].y;
631  r1 = r2/4;
632  agxbputc(&xbuf, '(');
633  xdot_point (&xbuf, c1);
634  xdot_num (&xbuf, r1);
635  xdot_point (&xbuf, c2);
636  xdot_num (&xbuf, r2);
637  }
638 
639  agxbput(&xbuf, "2 ");
640  if (obj->gradient_frac > 0) {
641  xdot_color_stop (&xbuf, obj->gradient_frac, &obj->fillcolor);
642  xdot_color_stop (&xbuf, obj->gradient_frac, &obj->stopcolor);
643  }
644  else {
645  xdot_color_stop (&xbuf, 0, &obj->fillcolor);
646  xdot_color_stop (&xbuf, 1, &obj->stopcolor);
647  }
648  agxbpop(&xbuf);
649  if (filled == GRADIENT)
650  agxbputc(&xbuf, ']');
651  else
652  agxbputc(&xbuf, ')');
653  xdot_str (job, "C ", agxbuse(&xbuf));
654  agxbfree(&xbuf);
655 }
656 
657 static void xdot_ellipse(GVJ_t * job, pointf * A, int filled)
658 {
659  emit_state_t emit_state = job->obj->emit_state;
660 
661  char buf[BUFSIZ];
662 
663  xdot_style (job);
664  xdot_pencolor (job);
665  if (filled) {
666  if ((filled == GRADIENT) || (filled == RGRADIENT)) {
667  xdot_gradient_fillcolor (job, filled, A, 2);
668  }
669  else
670  xdot_fillcolor (job);
671  agxbput(xbufs[emit_state], "E ");
672  }
673  else
674  agxbput(xbufs[emit_state], "e ");
675  xdot_point(xbufs[emit_state], A[0]);
676  xdot_fmt_num (buf, A[1].x - A[0].x);
677  agxbput(xbufs[emit_state], buf);
678  xdot_fmt_num (buf, A[1].y - A[0].y);
679  agxbput(xbufs[emit_state], buf);
680 }
681 
682 static void xdot_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start, int arrow_at_end, int filled)
683 {
684  xdot_style (job);
685  xdot_pencolor (job);
686  if (filled) {
687  if ((filled == GRADIENT) || (filled == RGRADIENT)) {
688  xdot_gradient_fillcolor (job, filled, A, n);
689  }
690  else
691  xdot_fillcolor (job);
692  xdot_points(job, 'b', A, n); /* NB - 'B' & 'b' are reversed in comparison to the other items */
693  }
694  else
695  xdot_points(job, 'B', A, n);
696 }
697 
698 static void xdot_polygon(GVJ_t * job, pointf * A, int n, int filled)
699 {
700  xdot_style (job);
701  xdot_pencolor (job);
702  if (filled) {
703  if ((filled == GRADIENT) || (filled == RGRADIENT)) {
704  xdot_gradient_fillcolor (job, filled, A, n);
705  }
706  else
707  xdot_fillcolor (job);
708  xdot_points(job, 'P', A, n);
709  }
710  else
711  xdot_points(job, 'p', A, n);
712 }
713 
714 static void xdot_polyline(GVJ_t * job, pointf * A, int n)
715 {
716  xdot_style (job);
717  xdot_pencolor (job);
718  xdot_points(job, 'L', A, n);
719 }
720 
721 void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
722 {
723  emit_state_t emit_state = job->obj->emit_state;
724  char buf[BUFSIZ];
725 
726  agxbput(xbufs[emit_state], "I ");
727  xdot_point(xbufs[emit_state], b.LL);
728  xdot_fmt_num (buf, b.UR.x - b.LL.x);
729  agxbput(xbufs[emit_state], buf);
730  xdot_fmt_num (buf, b.UR.y - b.LL.y);
731  agxbput(xbufs[emit_state], buf);
732  xdot_str (job, "", (char*)(us->name));
733 }
734 
736  0, /* dot_begin_job */
737  0, /* dot_end_job */
738  dot_begin_graph,
739  dot_end_graph,
740  0, /* dot_begin_layer */
741  0, /* dot_end_layer */
742  0, /* dot_begin_page */
743  0, /* dot_end_page */
744  0, /* dot_begin_cluster */
745  0, /* dot_end_cluster */
746  0, /* dot_begin_nodes */
747  0, /* dot_end_nodes */
748  0, /* dot_begin_edges */
749  0, /* dot_end_edges */
750  0, /* dot_begin_node */
751  0, /* dot_end_node */
752  0, /* dot_begin_edge */
753  0, /* dot_end_edge */
754  0, /* dot_begin_anchor */
755  0, /* dot_end_anchor */
756  0, /* dot_begin_label */
757  0, /* dot_end_label */
758  0, /* dot_textspan */
759  0, /* dot_resolve_color */
760  0, /* dot_ellipse */
761  0, /* dot_polygon */
762  0, /* dot_bezier */
763  0, /* dot_polyline */
764  0, /* dot_comment */
765  0, /* dot_library_shape */
766 };
767 
769  0, /* xdot_begin_job */
770  0, /* xdot_end_job */
771  dot_begin_graph,
772  dot_end_graph,
773  0, /* xdot_begin_layer */
774  0, /* xdot_end_layer */
775  0, /* xdot_begin_page */
776  0, /* xdot_end_page */
777  0, /* xdot_begin_cluster */
778  xdot_end_cluster,
779  0, /* xdot_begin_nodes */
780  0, /* xdot_end_nodes */
781  0, /* xdot_begin_edges */
782  0, /* xdot_end_edges */
783  0, /* xdot_begin_node */
784  xdot_end_node,
785  0, /* xdot_begin_edge */
786  xdot_end_edge,
787 #ifdef NEW_XDOT
788  xdot_begin_anchor,
789  xdot_end_anchor,
790 #else
791  0, /* xdot_begin_anchor */
792  0, /* xdot_end_anchor */
793 #endif
794  0, /* xdot_begin_label */
795  0, /* xdot_end_label */
796  xdot_textspan,
797  0, /* xdot_resolve_color */
798  xdot_ellipse,
799  xdot_polygon,
800  xdot_bezier,
802  0, /* xdot_comment */
803  0, /* xdot_library_shape */
804 };
805 
807  GVRENDER_DOES_TRANSFORM, /* not really - uses raw graph coords */ /* flags */
808  0., /* default pad - graph units */
809  NULL, /* knowncolors */
810  0, /* sizeof knowncolors */
811  COLOR_STRING, /* color_type */
812 };
813 
815  GVRENDER_DOES_TRANSFORM /* not really - uses raw graph coords */
818  | GVRENDER_DOES_TOOLTIPS, /* flags */
819  0., /* default pad - graph units */
820  NULL, /* knowncolors */
821  0, /* sizeof knowncolors */
822  RGBA_BYTE, /* color_type */
823 };
824 
826  LAYOUT_NOT_REQUIRED, /* flags */
827  {0.,0.}, /* default margin - points */
828  {0.,0.}, /* default height, width - device units */
829  {72.,72.}, /* default dpi */
830 };
831 
833  0, /* flags */
834  {0.,0.}, /* default margin - points */
835  {0.,0.}, /* default page width, height - points */
836  {72.,72.}, /* default dpi */
837 };
838 
840  {FORMAT_DOT, "dot", 1, &dot_engine, &render_features_dot},
841  {FORMAT_XDOT, "xdot", 1, &xdot_engine, &render_features_xdot},
842  {0, NULL, 0, NULL, NULL}
843 };
844 
846  {FORMAT_DOT, "dot:dot", 1, NULL, &device_features_dot},
847  {FORMAT_DOT, "gv:dot", 1, NULL, &device_features_dot},
848  {FORMAT_CANON, "canon:dot", 1, NULL, &device_features_canon},
849  {FORMAT_PLAIN, "plain:dot", 1, NULL, &device_features_dot},
850  {FORMAT_PLAIN_EXT, "plain-ext:dot", 1, NULL, &device_features_dot},
851  {FORMAT_XDOT, "xdot:xdot", 1, NULL, &device_features_dot},
852  {FORMAT_XDOT12, "xdot1.2:xdot", 1, NULL, &device_features_dot},
853  {FORMAT_XDOT14, "xdot1.4:xdot", 1, NULL, &device_features_dot},
854  {0, NULL, 0, NULL, NULL}
855 };
#define GD_label(g)
Definition: types.h:381
unsigned short version
gvrender_engine_t xdot_engine
char ** rawstyle
Definition: gvcjob.h:209
pointf size
Definition: textspan.h:64
gvcolor_t stopcolor
Definition: gvcjob.h:203
union color_s::@10 u
#define GD_has_labels(g)
Definition: types.h:372
attrsym_t * safe_dcl(graph_t *g, int obj_kind, char *name, char *def)
Definition: utils.c:1333
attrsym_t * g_draw
gvrender_features_t render_features_dot
#define GRAPH_LABEL
Definition: const.h:187
#define LAYOUT_NOT_REQUIRED
Definition: gvcjob.h:110
#define agxbuse(X)
Definition: agxbuf.h:83
gvrender_engine_t dot_engine
CGRAPH_API Agiodisc_t AgIoDisc
Definition: cgraph.h:199
#define XDOTVERSION
#define GD_n_cluster(g)
Definition: types.h:396
emit_state_t
Definition: gvcjob.h:182
int agxset(void *obj, Agsym_t *sym, char *value)
Definition: attr.c:468
double size
Definition: textspan.h:52
void undoClusterEdges(graph_t *g)
Definition: utils.c:1295
Definition: geom.h:28
size_t agxbput(agxbuf *xb, const char *s)
Definition: agxbuf.c:84
Definition: color.h:34
unsigned char buf[NUMXBUFS][BUFSIZ]
CGRAPH_API int agwrite(Agraph_t *g, void *chan)
Definition: write.c:678
int agerr(agerrlevel_t level, const char *fmt,...)
Definition: agerror.c:141
int flags
Definition: gvcjob.h:308
gvcolor_t pencolor
Definition: gvcjob.h:203
Definition: gvcjob.h:271
char * name
Definition: textspan.h:49
attrsym_t * g_l_draw
#define GVRENDER_DOES_TRANSFORM
Definition: gvcjob.h:97
int(* flushfn)(void *chan)
Definition: cgraph.h:388
obj_state_t * obj
Definition: gvcjob.h:278
#define agxbputc(X, C)
Definition: agxbuf.h:77
char * agget(void *obj, char *name)
Definition: attr.c:428
int gvputs(GVJ_t *job, const char *s)
Definition: gvdevice.c:270
void write_plain(GVJ_t *job, graph_t *g, FILE *f, boolean extend)
Definition: output.c:113
Agdisc_t disc
Definition: cgraph.h:229
int agxbpop(agxbuf *xb)
Definition: agxbuf.c:103
void attach_attrs_and_arrows(graph_t *g, int *sp, int *ep)
Definition: output.c:232
#define agxblen(X)
Definition: agxbuf.h:95
char * str
Definition: textspan.h:59
attrsym_t * h_draw
#define GVRENDER_DOES_TARGETS
Definition: gvcjob.h:107
unsigned int flags
Definition: textspan.h:53
int
Definition: grammar.c:1264
#define GVRENDER_DOES_TOOLTIPS
Definition: gvcjob.h:106
#define TAIL_LABEL
Definition: const.h:186
gvplugin_active_render_t render
Definition: gvcjob.h:294
double y
Definition: geom.h:28
int(* flush)(void *chan)
Definition: cgraph.h:185
gvplugin_installed_t gvrender_dot_types[]
gvdevice_features_t device_features_canon
int(* afread)(void *chan, char *buf, int bufsize)
Definition: cgraph.h:183
double yoffset_centerline
Definition: textspan.h:63
double yDir(double y)
Definition: output.c:25
#define GRADIENT
Definition: const.h:254
void agxbinit(agxbuf *xb, unsigned int hint, unsigned char *init)
Definition: agxbuf.c:25
gvdevice_features_t device_features_dot
Definition: grammar.c:79
int gradient_angle
Definition: gvcjob.h:204
int agsafeset(void *obj, char *name, char *value, char *def)
Definition: attr.c:497
int(* putstrfn)(void *chan, const char *str)
#define AGNODE
Definition: cgraph.h:101
attrsym_t * e_l_draw
emit_state_t emit_state
Definition: gvcjob.h:201
graph_t * g
Definition: gvcjob.h:195
format_type
#define NUMXBUFS
#define GVRENDER_DOES_MAPS
Definition: gvcjob.h:100
#define NULL
Definition: logic.h:39
#define RGRADIENT
Definition: const.h:255
#define HEAD_LABEL
Definition: const.h:185
float gradient_frac
Definition: gvcjob.h:205
graph_t * sg
Definition: gvcjob.h:196
double x
Definition: geom.h:28
#define streq(s, t)
Definition: cghdr.h:52
#define GNEW(t)
attrsym_t * n_l_draw
char just
Definition: textspan.h:65
pointf LL
Definition: geom.h:35
Agiodisc_t * io
Definition: cgraph.h:192
union obj_state_s::@23 u
int gvflush(GVJ_t *job)
Definition: gvdevice.c:290
attrsym_t * e_draw
gvplugin_installed_t gvdevice_dot_types[]
#define EDGE_XLABEL
Definition: const.h:189
attrsym_t * tl_draw
edge_t * e
Definition: gvcjob.h:198
#define M_PI
Definition: arith.h:77
#define HAS_CLUST_EDGE(g)
Definition: macros.h:32
agxbuf * str
Definition: htmlparse.c:85
int(* putstr)(void *chan, const char *str)
Definition: cgraph.h:184
Definition: agxbuf.h:34
#define OUTPUT_NOT_REQUIRED
Definition: gvcjob.h:111
gvcolor_t fillcolor
Definition: gvcjob.h:203
gvrender_features_t render_features_xdot
node_t * n
Definition: gvcjob.h:197
double penwidth
Definition: gvcjob.h:208
attrsym_t * t_draw
Agclos_t * clos
Definition: cgraph.h:248
void core_loadimage_xdot(GVJ_t *, usershape_t *, boxf, boolean)
attrsym_t * n_draw
#define EDGE_LABEL
Definition: const.h:184
#define AGEDGE
Definition: cgraph.h:104
void attach_attrs(graph_t *g)
Definition: output.c:399
unsigned char rgba[4]
Definition: color.h:38
const char * name
Definition: usershape.h:53
pointf UR
Definition: geom.h:35
void agxbfree(agxbuf *xb)
Definition: agxbuf.c:94
Definition: geom.h:35
#define FALSE
Definition: cgraph.h:35
attrsym_t * hl_draw
textfont_t * font
Definition: textspan.h:60
void get_gradient_points(pointf *A, pointf *G, int n, float angle, int flags)
Definition: utils.c:1827
#define AGRAPH
Definition: cgraph.h:100
#define TRUE
Definition: cgraph.h:38