Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
gvrender_core_dot.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <assert.h>
14#include <math.h>
15#include <stdarg.h>
16#include <stdbool.h>
17#include <stdlib.h>
18#include <string.h>
19
20#include <common/macros.h>
21#include <common/const.h>
22
23#include <gvc/gvplugin_render.h>
24#include <gvc/gvplugin_device.h>
25#include <common/utils.h>
26#include <gvc/gvc.h>
27#include <gvc/gvio.h>
28#include <util/agxbuf.h>
29#include <util/alloc.h>
30#include <util/gv_ctype.h>
31#include <util/prisize_t.h>
32#include <util/streq.h>
33#include <util/unreachable.h>
34#include "core_loadimage_xdot.h"
35
45
46#define XDOTVERSION "1.7"
47
48#define NUMXBUFS (EMIT_HLABEL+1)
49/* There are as many xbufs as there are values of emit_state_t.
50 * However, only the first NUMXBUFS are distinct. Nodes, clusters, and
51 * edges are drawn atomically, so they share the DRAW and LABEL buffers
52 */
59static double penwidth [] = {
60 1, 1, 1, 1,
61 1, 1, 1, 1,
62 1, 1, 1, 1,
63};
64static unsigned int textflags[EMIT_ELABEL+1];
65
82
83static void xdot_str_xbuf (agxbuf* xb, char* pfx, const char* s)
84{
85 agxbprint (xb, "%s%" PRISIZE_T " -%s ", pfx, strlen(s), s);
86}
87
88static void xdot_str (GVJ_t *job, char* pfx, const char* s)
89{
90 emit_state_t emit_state = job->obj->emit_state;
91 xdot_str_xbuf (xbufs[emit_state], pfx, s);
92}
93
99static void xdot_str_color_xbuf(agxbuf *xb, const char *prefix,
100 const unsigned char rgba[4]) {
101 if (rgba[3] == 0xFF) {
102 agxbprint(xb, "%s%" PRISIZE_T " -#%02x%02x%02x ", prefix, strlen("#FFFFFF"),
103 rgba[0], rgba[1], rgba[2]);
104 } else {
105 agxbprint(xb, "%s%" PRISIZE_T " -#%02x%02x%02x%02x ", prefix,
106 strlen("#FFFFFFFF"), rgba[0], rgba[1], rgba[2], rgba[3]);
107 }
108}
109
115static void xdot_str_color(GVJ_t *job, const char *prefix,
116 const unsigned char rgba[4]) {
117 emit_state_t emit_state = job->obj->emit_state;
118 agxbuf *xb = xbufs[emit_state];
119 xdot_str_color_xbuf(xb, prefix, rgba);
120}
121
122/* xdot_fmt_num:
123 * Convert double to string with space at end.
124 * Trailing zeros are removed and decimal point, if possible.
125 */
126static void xdot_fmt_num(agxbuf *buf, double v) {
127 agxbprint(buf, "%.02f", v);
129 agxbputc(buf, ' ');
130}
131
132static void xdot_point(agxbuf *xb, pointf p)
133{
134 xdot_fmt_num(xb, p.x);
135 assert(xd != NULL);
136 xdot_fmt_num(xb, yDir(p.y, xd->yOff));
137}
138
139static void xdot_num(agxbuf *xb, double v)
140{
141 xdot_fmt_num(xb, v);
142}
143
144static void xdot_points(GVJ_t *job, char c, pointf *A, size_t n) {
145 emit_state_t emit_state = job->obj->emit_state;
146 agxbprint(xbufs[emit_state], "%c %" PRISIZE_T " ", c, n);
147 for (size_t i = 0; i < n; i++)
148 xdot_point(xbufs[emit_state], A[i]);
149}
150
151static void xdot_pencolor (GVJ_t *job)
152{
153 xdot_str_color(job, "c ", job->obj->pencolor.u.rgba);
154}
155
156static void xdot_fillcolor (GVJ_t *job)
157{
158 xdot_str_color(job, "C ", job->obj->fillcolor.u.rgba);
159}
160
161static void xdot_style (GVJ_t *job)
162{
163 agxbuf xb = {0};
164 char* p, **s;
165
166 /* First, check if penwidth state is correct */
167 if (fabs(job->obj->penwidth - penwidth[job->obj->emit_state]) >= 0.0005) {
168 penwidth[job->obj->emit_state] = job->obj->penwidth;
169 agxbput (&xb, "setlinewidth(");
170 agxbprint(&xb, "%.3f", job->obj->penwidth);
172 agxbputc(&xb, ')');
173 xdot_str (job, "S ", agxbuse(&xb));
174 }
175
176 /* now process raw style, if any */
177 s = job->obj->rawstyle;
178 if (!s) {
179 agxbfree(&xb);
180 return;
181 }
182
183 while ((p = *s++)) {
184 if (streq(p, "filled") || streq(p, "bold") || streq(p, "setlinewidth")) continue;
185 agxbput(&xb, p);
186 while (*p)
187 p++;
188 p++;
189 if (*p) { /* arguments */
190 agxbputc(&xb, '(');
191 for (const char *separator = ""; *p; separator = ",") {
192 agxbprint(&xb, "%s%s", separator, p);
193 while (*p) p++;
194 p++;
195 }
196 agxbputc(&xb, ')');
197 }
198 xdot_str (job, "S ", agxbuse(&xb));
199 }
200
201 agxbfree(&xb);
202
203}
204
218static void put_escaping_backslashes(Agobj_t* n, Agsym_t *sym, const char *value)
219{
220 agxbuf buf = {0};
221
222 /* print the given string to the buffer, escaping as we go */
223 for (; *value != '\0'; ++value) {
224 if (*value == '\\') {
225 agxbputc(&buf, '\\');
226 }
227 agxbputc(&buf, *value);
228 }
229
230 /* update the node's symbol to the escaped text */
231 agxset(n, sym, agxbuse(&buf));
232
233 /* discard the buffer */
234 agxbfree(&buf);
235}
236
249
279
280static void xdot_end_cluster(GVJ_t * job)
281{
282 Agraph_t* cluster_g = job->obj->u.sg;
283
284 agxset(cluster_g, xd->g_draw, agxbuse(xbufs[EMIT_CDRAW]));
285 if (GD_label(cluster_g))
286 agxset(cluster_g, xd->g_l_draw, agxbuse(xbufs[EMIT_CLABEL]));
287 penwidth[EMIT_CDRAW] = 1;
291}
292
293static unsigned short versionStr2Version(const char *str) {
294 unsigned short us = 0;
295 for (size_t i = 0; str[i] != '\0'; ++i) {
296 if (!gv_isdigit(str[i])) {
297 continue;
298 }
299 unsigned short digit = (unsigned short)(str[i] - '0');
300 if (us > (USHRT_MAX - digit) / 10) {
301 agwarningf("xdot version \"%s\" too long", str);
302 break;
303 }
304 us = (unsigned short)(us * 10 + digit);
305 }
306 return us;
307}
308
309/*
310 * John M. suggests:
311 * You might want to add four more:
312 *
313 * _ohdraw_ (optional head-end arrow for edges)
314 * _ohldraw_ (optional head-end label for edges)
315 * _otdraw_ (optional tail-end arrow for edges)
316 * _otldraw_ (optional tail-end label for edges)
317 *
318 * that would be generated when an additional option is supplied to
319 * dot, etc. and
320 * these would be the arrow/label positions to use if a user want to flip the
321 * direction of an edge (as sometimes is there want).
322 *
323 * N.B. John M. asks:
324 * By the way, I don't know if you ever plan to add other letters for
325 * the xdot spec, but could you reserve "a" and also "A" (for attribute),
326 * "n" and also "N" (for numeric), "w" (for sWitch), "s" (for string)
327 * and "t" (for tooltip) and "x" (for position). We use those letters in
328 * our drawing spec (and also "<" and ">"), so if you start generating
329 * output with them, it could break what we have.
330 *
331 * @param yOff ymax - ymin
332 */
333static void xdot_begin_graph(graph_t *g, bool s_arrows, bool e_arrows,
334 format_type id, double yOff) {
335 int i;
336 unsigned short us;
337 char* s;
338
339 xd = gv_alloc(sizeof(xdot_state_t));
340
341 if (id == FORMAT_XDOT14) {
342 xd->version = 14;
343 xd->version_s = "1.4";
344 }
345 else if (id == FORMAT_XDOT12) {
346 xd->version = 12;
347 xd->version_s = "1.2";
348 }
349 else if ((s = agget(g, "xdotversion")) && s[0] && ((us = versionStr2Version(s)) > 10)) {
350 xd->version = us;
351 xd->version_s = s;
352 }
353 else {
356 }
357
358 if (GD_n_cluster(g))
359 xd->g_draw = safe_dcl(g, AGRAPH, "_draw_", "");
360 else
361 xd->g_draw = NULL;
362 if (GD_has_labels(g) & GRAPH_LABEL)
363 xd->g_l_draw = safe_dcl(g, AGRAPH, "_ldraw_", "");
364 else
365 xd->g_l_draw = NULL;
366
367 xd->n_draw = safe_dcl(g, AGNODE, "_draw_", "");
368 xd->n_l_draw = safe_dcl(g, AGNODE, "_ldraw_", "");
369
370 xd->e_draw = safe_dcl(g, AGEDGE, "_draw_", "");
371 if (e_arrows)
372 xd->h_draw = safe_dcl(g, AGEDGE, "_hdraw_", "");
373 else
374 xd->h_draw = NULL;
375 if (s_arrows)
376 xd->t_draw = safe_dcl(g, AGEDGE, "_tdraw_", "");
377 else
378 xd->t_draw = NULL;
380 xd->e_l_draw = safe_dcl(g, AGEDGE, "_ldraw_", "");
381 else
382 xd->e_l_draw = NULL;
383 if (GD_has_labels(g) & HEAD_LABEL)
384 xd->hl_draw = safe_dcl(g, AGEDGE, "_hldraw_", "");
385 else
386 xd->hl_draw = NULL;
387 if (GD_has_labels(g) & TAIL_LABEL)
388 xd->tl_draw = safe_dcl(g, AGEDGE, "_tldraw_", "");
389 else
390 xd->tl_draw = NULL;
391
392 for (i = 0; i < NUMXBUFS; i++)
393 xbuf[i] = (agxbuf){0};
394
395 xd->yOff = yOff;
396}
397
398static void dot_begin_graph(GVJ_t *job)
399{
400 graph_t *g = job->obj->u.g;
401
402 switch (job->render.id) {
403 case FORMAT_DOT:
404 attach_attrs(g);
405 break;
406 case FORMAT_CANON:
407 if (HAS_CLUST_EDGE(g))
409 break;
410 case FORMAT_PLAIN:
411 case FORMAT_PLAIN_EXT:
412 break;
413 case FORMAT_XDOT:
414 case FORMAT_XDOT12:
415 case FORMAT_XDOT14: {
416 bool e_arrows; // graph has edges with end arrows
417 bool s_arrows; // graph has edges with start arrows
418 const double yOff = attach_attrs_and_arrows(g, &s_arrows, &e_arrows);
419 xdot_begin_graph(g, s_arrows, e_arrows, job->render.id, yOff);
420 break;
421 }
422 default:
423 UNREACHABLE();
424 }
425}
426
427static void xdot_end_graph(graph_t* g)
428{
429 int i;
430
431 if (agxblen(xbufs[EMIT_GDRAW])) {
432 if (!xd->g_draw)
433 xd->g_draw = safe_dcl(g, AGRAPH, "_draw_", "");
435 }
436 if (GD_label(g))
438 agsafeset (g, "xdotversion", xd->version_s, "");
439
440 for (i = 0; i < NUMXBUFS; i++)
441 agxbfree(xbuf+i);
442 free (xd);
443 penwidth[EMIT_GDRAW] = 1;
447}
448
449typedef int (*putstrfn) (void *chan, const char *str);
450typedef int (*flushfn) (void *chan);
451static void dot_end_graph(GVJ_t *job)
452{
453 graph_t *g = job->obj->u.g;
454 Agiodisc_t* io_save;
455 static Agiodisc_t io;
456
457 if (io.afread == NULL) {
459 io.putstr = (putstrfn)gvputs;
460 io.flush = (flushfn)gvflush;
461 }
462
463 io_save = g->clos->disc.io;
464 g->clos->disc.io = &io;
465 switch (job->render.id) {
466 case FORMAT_PLAIN:
467 write_plain(job, g, (FILE*)job, false);
468 break;
469 case FORMAT_PLAIN_EXT:
470 write_plain(job, g, (FILE*)job, true);
471 break;
472 case FORMAT_DOT:
473 case FORMAT_CANON:
474 if (!(job->flags & OUTPUT_NOT_REQUIRED))
475 agwrite(g, job);
476 break;
477 case FORMAT_XDOT:
478 case FORMAT_XDOT12:
479 case FORMAT_XDOT14:
481 if (!(job->flags & OUTPUT_NOT_REQUIRED))
482 agwrite(g, job);
483 break;
484 default:
485 UNREACHABLE();
486 }
487 g->clos->disc.io = io_save;
488}
489
490static const unsigned int flag_masks[] = {0x1F, 0x3F, 0x7F};
491
492static void xdot_textspan(GVJ_t * job, pointf p, textspan_t * span)
493{
494 emit_state_t emit_state = job->obj->emit_state;
495 unsigned flags;
496 int j;
497
498 agxbput(xbufs[emit_state], "F ");
499 xdot_fmt_num(xbufs[emit_state], span->font->size);
500 xdot_str (job, "", span->font->name);
501 xdot_pencolor(job);
502
503 switch (span->just) {
504 case 'l':
505 j = -1;
506 break;
507 case 'r':
508 j = 1;
509 break;
510 default:
511 case 'n':
512 j = 0;
513 break;
514 }
515 if (span->font)
516 flags = span->font->flags;
517 else
518 flags = 0;
519 const size_t flag_masks_size = sizeof(flag_masks) / sizeof(flag_masks[0]);
520 if (xd->version >= 15 && (size_t)xd->version - 15 < flag_masks_size) {
521 unsigned int mask = flag_masks[xd->version-15];
522 unsigned int bits = flags & mask;
523 if (textflags[emit_state] != bits) {
524 agxbprint(xbufs[emit_state], "t %u ", bits);
525 textflags[emit_state] = bits;
526 }
527 }
528
529 p.y += span->yoffset_centerline;
530 agxbput(xbufs[emit_state], "T ");
531 xdot_point(xbufs[emit_state], p);
532 agxbprint(xbufs[emit_state], "%d ", j);
533 xdot_fmt_num(xbufs[emit_state], span->size.x);
534 xdot_str (job, "", span->str);
535}
536
537static void xdot_color_stop(agxbuf *xb, double v, gvcolor_t *clr) {
538 agxbprint(xb, "%.03f", v);
540 agxbputc(xb, ' ');
541 xdot_str_color_xbuf(xb, "", clr->u.rgba);
542}
543
544static void xdot_gradient_fillcolor(GVJ_t *job, int filled, pointf *A, size_t n)
545{
546 obj_state_t* obj = job->obj;
547 double angle = obj->gradient_angle * M_PI / 180;
548 pointf G[2],c1,c2;
549
550 if (xd->version < 14) {
551 xdot_fillcolor (job);
552 return;
553 }
554
555 agxbuf xb = {0};
556 if (filled == GRADIENT) {
557 get_gradient_points(A, G, n, angle, 2);
558 agxbputc (&xb, '[');
559 xdot_point (&xb, G[0]);
560 xdot_point (&xb, G[1]);
561 }
562 else {
563 get_gradient_points(A, G, n, 0, 3);
564 // r2 is outer radius
565 double r2 = G[1].y;
566 if (obj->gradient_angle == 0) {
567 c1.x = G[0].x;
568 c1.y = G[0].y;
569 }
570 else {
571 c1.x = G[0].x + (r2/4) * cos(angle);
572 c1.y = G[0].y + (r2/4) * sin(angle);
573 }
574 c2.x = G[0].x;
575 c2.y = G[0].y;
576 double r1 = r2 / 4;
577 agxbputc(&xb, '(');
578 xdot_point (&xb, c1);
579 xdot_num (&xb, r1);
580 xdot_point (&xb, c2);
581 xdot_num (&xb, r2);
582 }
583
584 agxbput(&xb, "2 ");
585 if (obj->gradient_frac > 0) {
586 xdot_color_stop (&xb, obj->gradient_frac, &obj->fillcolor);
587 xdot_color_stop (&xb, obj->gradient_frac, &obj->stopcolor);
588 }
589 else {
590 xdot_color_stop (&xb, 0, &obj->fillcolor);
591 xdot_color_stop (&xb, 1, &obj->stopcolor);
592 }
593 agxbpop(&xb);
594 if (filled == GRADIENT)
595 agxbputc(&xb, ']');
596 else
597 agxbputc(&xb, ')');
598 xdot_str (job, "C ", agxbuse(&xb));
599 agxbfree(&xb);
600}
601
602static void xdot_ellipse(GVJ_t * job, pointf * A, int filled)
603{
604 emit_state_t emit_state = job->obj->emit_state;
605
606 xdot_style (job);
607 xdot_pencolor (job);
608 if (filled) {
609 if ((filled == GRADIENT) || (filled == RGRADIENT)) {
610 xdot_gradient_fillcolor (job, filled, A, 2);
611 }
612 else
613 xdot_fillcolor (job);
614 agxbput(xbufs[emit_state], "E ");
615 }
616 else
617 agxbput(xbufs[emit_state], "e ");
618 xdot_point(xbufs[emit_state], A[0]);
619 xdot_fmt_num(xbufs[emit_state], A[1].x - A[0].x);
620 xdot_fmt_num(xbufs[emit_state], A[1].y - A[0].y);
621}
622
623static void xdot_bezier(GVJ_t *job, pointf *A, size_t n, int filled) {
624 xdot_style (job);
625 xdot_pencolor (job);
626 if (filled) {
627 if ((filled == GRADIENT) || (filled == RGRADIENT)) {
628 xdot_gradient_fillcolor(job, filled, A, n);
629 }
630 else
631 xdot_fillcolor (job);
632 xdot_points(job, 'b', A, n); // NB - 'B' & 'b' are reversed in comparison to the other items
633 }
634 else
635 xdot_points(job, 'B', A, n);
636}
637
638static void xdot_polygon(GVJ_t *job, pointf *A, size_t n, int filled) {
639 xdot_style (job);
640 xdot_pencolor (job);
641 if (filled) {
642 if ((filled == GRADIENT) || (filled == RGRADIENT)) {
643 xdot_gradient_fillcolor(job, filled, A, n);
644 }
645 else
646 xdot_fillcolor (job);
647 xdot_points(job, 'P', A, n);
648 }
649 else
650 xdot_points(job, 'p', A, n);
651}
652
653static void xdot_polyline(GVJ_t *job, pointf *A, size_t n) {
654 xdot_style (job);
655 xdot_pencolor (job);
656 xdot_points(job, 'L', A, n);
657}
658
659void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, bool filled)
660{
661 (void)filled;
662
663 emit_state_t emit_state = job->obj->emit_state;
664
665 agxbput(xbufs[emit_state], "I ");
666 xdot_point(xbufs[emit_state], b.LL);
667 xdot_fmt_num(xbufs[emit_state], b.UR.x - b.LL.x);
668 xdot_fmt_num(xbufs[emit_state], b.UR.y - b.LL.y);
669 xdot_str (job, "", us->name);
670}
671
673 0, /* dot_begin_job */
674 0, /* dot_end_job */
677 0, /* dot_begin_layer */
678 0, /* dot_end_layer */
679 0, /* dot_begin_page */
680 0, /* dot_end_page */
681 0, /* dot_begin_cluster */
682 0, /* dot_end_cluster */
683 0, /* dot_begin_nodes */
684 0, /* dot_end_nodes */
685 0, /* dot_begin_edges */
686 0, /* dot_end_edges */
687 0, /* dot_begin_node */
688 0, /* dot_end_node */
689 0, /* dot_begin_edge */
690 0, /* dot_end_edge */
691 0, /* dot_begin_anchor */
692 0, /* dot_end_anchor */
693 0, /* dot_begin_label */
694 0, /* dot_end_label */
695 0, /* dot_textspan */
696 0, /* dot_resolve_color */
697 0, /* dot_ellipse */
698 0, /* dot_polygon */
699 0, /* dot_bezier */
700 0, /* dot_polyline */
701 0, /* dot_comment */
702 0, /* dot_library_shape */
703};
704
706 0, /* xdot_begin_job */
707 0, /* xdot_end_job */
710 0, /* xdot_begin_layer */
711 0, /* xdot_end_layer */
712 0, /* xdot_begin_page */
713 0, /* xdot_end_page */
714 0, /* xdot_begin_cluster */
716 0, /* xdot_begin_nodes */
717 0, /* xdot_end_nodes */
718 0, /* xdot_begin_edges */
719 0, /* xdot_end_edges */
720 0, /* xdot_begin_node */
722 0, /* xdot_begin_edge */
724 0, /* xdot_begin_anchor */
725 0, /* xdot_end_anchor */
726 0, /* xdot_begin_label */
727 0, /* xdot_end_label */
729 0, /* xdot_resolve_color */
734 0, /* xdot_comment */
735 0, /* xdot_library_shape */
736};
737
739 GVRENDER_DOES_TRANSFORM, /* not really - uses raw graph coords */ /* flags */
740 0., /* default pad - graph units */
741 NULL, /* knowncolors */
742 0, /* sizeof knowncolors */
743 COLOR_STRING, /* color_type */
744};
745
747 GVRENDER_DOES_TRANSFORM /* not really - uses raw graph coords */
750 | GVRENDER_DOES_TOOLTIPS, /* flags */
751 0., /* default pad - graph units */
752 NULL, /* knowncolors */
753 0, /* sizeof knowncolors */
754 RGBA_BYTE, /* color_type */
755};
756
758 LAYOUT_NOT_REQUIRED, /* flags */
759 {0.,0.}, /* default margin - points */
760 {0.,0.}, /* default height, width - device units */
761 {72.,72.}, /* default dpi */
762};
763
765 0, /* flags */
766 {0.,0.}, /* default margin - points */
767 {0.,0.}, /* default page width, height - points */
768 {72.,72.}, /* default dpi */
769};
770
776
778 {FORMAT_DOT, "dot:dot", 1, NULL, &device_features_dot},
779 {FORMAT_DOT, "gv:dot", 1, NULL, &device_features_dot},
780 {FORMAT_CANON, "canon:dot", 1, NULL, &device_features_canon},
781 {FORMAT_PLAIN, "plain:dot", 1, NULL, &device_features_dot},
782 {FORMAT_PLAIN_EXT, "plain-ext:dot", 1, NULL, &device_features_dot},
783 {FORMAT_XDOT, "xdot:xdot", 1, NULL, &device_features_dot},
784 {FORMAT_XDOT12, "xdot1.2:xdot", 1, NULL, &device_features_dot},
785 {FORMAT_XDOT14, "xdot1.4:xdot", 1, NULL, &device_features_dot},
786 {0, NULL, 0, NULL, NULL}
787};
static int agxbpop(agxbuf *xb)
removes last character added, if any
Definition agxbuf.h:111
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
static size_t agxblen(const agxbuf *xb)
return number of characters currently stored
Definition agxbuf.h:89
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:277
Memory allocation wrappers that exit on failure.
static void * gv_alloc(size_t size)
Definition alloc.h:47
#define M_PI
Definition arith.h:41
@ RGBA_BYTE
Definition color.h:26
@ COLOR_STRING
Definition color.h:27
void undoClusterEdges(graph_t *g)
Definition utils.c:1035
attrsym_t * safe_dcl(graph_t *g, int obj_kind, char *name, char *defaultValue)
Definition utils.c:1070
void get_gradient_points(pointf *A, pointf *G, size_t n, double angle, int flags)
Definition utils.c:1457
#define HEAD_LABEL
Definition const.h:177
#define EDGE_XLABEL
Definition const.h:181
#define GRAPH_LABEL
Definition const.h:179
#define TAIL_LABEL
Definition const.h:178
#define EDGE_LABEL
Definition const.h:176
#define GRADIENT
Definition const.h:232
#define RGRADIENT
Definition const.h:233
#define A(n, t)
Definition expr.h:76
static int flags
Definition gc.c:61
#define G
Definition gdefs.h:7
void free(void *)
require define api prefix
Definition gmlparse.y:17
node NULL
Definition grammar.y:163
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:478
char * agget(void *obj, char *name)
Definition attr.c:439
int agsafeset(void *obj, char *name, const char *value, const char *def)
ensures the given attribute is declared before setting it locally on an object
Definition attr.c:507
Agiodisc_t AgIoDisc
Definition io.c:39
void agwarningf(const char *fmt,...)
Definition agerror.c:173
#define GD_has_labels(g)
Definition types.h:368
#define GD_n_cluster(g)
Definition types.h:389
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:730
#define GD_label(g)
Definition types.h:374
@ AGEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
void attach_attrs(graph_t *g)
Definition output.c:394
replacements for ctype.h functions
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
Graphviz context library.
#define GVRENDER_DOES_TOOLTIPS
Definition gvcjob.h:103
#define OUTPUT_NOT_REQUIRED
Definition gvcjob.h:108
#define LAYOUT_NOT_REQUIRED
Definition gvcjob.h:107
emit_state_t
Definition gvcjob.h:173
@ EMIT_CDRAW
Definition gvcjob.h:174
@ EMIT_NDRAW
Definition gvcjob.h:176
@ EMIT_TDRAW
Definition gvcjob.h:174
@ EMIT_HDRAW
Definition gvcjob.h:174
@ EMIT_HLABEL
Definition gvcjob.h:175
@ EMIT_GDRAW
Definition gvcjob.h:174
@ EMIT_NLABEL
Definition gvcjob.h:176
@ EMIT_GLABEL
Definition gvcjob.h:175
@ EMIT_ELABEL
Definition gvcjob.h:176
@ EMIT_EDRAW
Definition gvcjob.h:176
@ EMIT_CLABEL
Definition gvcjob.h:175
@ EMIT_TLABEL
Definition gvcjob.h:175
#define GVRENDER_DOES_MAPS
Definition gvcjob.h:97
#define GVRENDER_DOES_TARGETS
Definition gvcjob.h:104
#define GVRENDER_DOES_TRANSFORM
Definition gvcjob.h:95
agxbput(xb, staging)
agxbuf_trim_zeros(xb)
int gvflush(GVJ_t *job)
Definition gvdevice.c:301
int gvputs(GVJ_t *job, const char *s)
Definition gvdevice.c:264
format_type
gvplugin_installed_t gvrender_dot_types[]
static void xdot_polygon(GVJ_t *job, pointf *A, size_t n, int filled)
int(* putstrfn)(void *chan, const char *str)
static void dot_end_graph(GVJ_t *job)
static void xdot_style(GVJ_t *job)
gvdevice_features_t device_features_canon
static void xdot_str_color(GVJ_t *job, const char *prefix, const unsigned char rgba[4])
static void xdot_end_cluster(GVJ_t *job)
static void xdot_fmt_num(agxbuf *buf, double v)
static void xdot_end_edge(GVJ_t *job)
void core_loadimage_xdot(GVJ_t *job, usershape_t *us, boxf b, bool filled)
static agxbuf * xbufs[]
static void xdot_str_color_xbuf(agxbuf *xb, const char *prefix, const unsigned char rgba[4])
static void xdot_pencolor(GVJ_t *job)
static void xdot_points(GVJ_t *job, char c, pointf *A, size_t n)
static void dot_begin_graph(GVJ_t *job)
static void xdot_fillcolor(GVJ_t *job)
gvrender_engine_t dot_engine
static void xdot_num(agxbuf *xb, double v)
gvrender_features_t render_features_dot
#define NUMXBUFS
static xdot_state_t * xd
static void xdot_str_xbuf(agxbuf *xb, char *pfx, const char *s)
static unsigned int textflags[EMIT_ELABEL+1]
gvplugin_installed_t gvdevice_dot_types[]
static void xdot_begin_graph(graph_t *g, bool s_arrows, bool e_arrows, format_type id, double yOff)
static double penwidth[]
static agxbuf xbuf[NUMXBUFS]
int(* flushfn)(void *chan)
static void xdot_textspan(GVJ_t *job, pointf p, textspan_t *span)
static unsigned short versionStr2Version(const char *str)
gvdevice_features_t device_features_dot
format_type
@ FORMAT_PLAIN
@ FORMAT_XDOT12
@ FORMAT_DOT
@ FORMAT_XDOT
@ FORMAT_PLAIN_EXT
@ FORMAT_XDOT14
@ FORMAT_CANON
static void xdot_ellipse(GVJ_t *job, pointf *A, int filled)
static void xdot_end_node(GVJ_t *job)
#define XDOTVERSION
static void xdot_str(GVJ_t *job, char *pfx, const char *s)
static const unsigned int flag_masks[]
static void xdot_end_graph(graph_t *g)
static void xdot_bezier(GVJ_t *job, pointf *A, size_t n, int filled)
gvrender_features_t render_features_xdot
gvrender_engine_t xdot_engine
static void put_escaping_backslashes(Agobj_t *n, Agsym_t *sym, const char *value)
static void xdot_gradient_fillcolor(GVJ_t *job, int filled, pointf *A, size_t n)
textitem scanner parser str
Definition htmlparse.y:224
#define HAS_CLUST_EDGE(g)
Definition macros.h:24
double attach_attrs_and_arrows(graph_t *g, bool *sp, bool *ep)
Definition output.c:232
double yDir(double y, double Y_off)
Definition output.c:32
void write_plain(GVJ_t *job, graph_t *g, FILE *f, bool extend)
Definition output.c:117
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
Agdisc_t disc
Definition cgraph.h:412
Agiodisc_t * io
Definition cgraph.h:339
Agobj_t base
Definition cgraph.h:269
IO services.
Definition cgraph.h:327
int(* afread)(void *chan, char *buf, int bufsize)
Definition cgraph.h:328
int(* flush)(void *chan)
Definition cgraph.h:330
int(* putstr)(void *chan, const char *str)
Definition cgraph.h:329
Agobj_t base
Definition cgraph.h:260
a generic header of Agraph_s, Agnode_s and Agedge_s
Definition cgraph.h:210
graph or subgraph
Definition cgraph.h:425
Agobj_t base
Definition cgraph.h:426
Agclos_t * clos
shared resources
Definition cgraph.h:435
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:637
obj_state_t * obj
Definition gvcjob.h:269
gvplugin_active_render_t render
Definition gvcjob.h:285
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
union color_s::@71 u
unsigned char rgba[4]
Definition color.h:34
ingroup plugin_api
Definition gvplugin.h:35
graph_t * g
Definition gvcjob.h:186
edge_t * e
Definition gvcjob.h:189
gvcolor_t fillcolor
Definition gvcjob.h:194
double gradient_frac
Definition gvcjob.h:196
union obj_state_s::@89 u
gvcolor_t stopcolor
Definition gvcjob.h:194
node_t * n
Definition gvcjob.h:188
graph_t * sg
Definition gvcjob.h:187
gvcolor_t pencolor
Definition gvcjob.h:194
char ** rawstyle
Definition gvcjob.h:200
int gradient_angle
Definition gvcjob.h:195
emit_state_t emit_state
Definition gvcjob.h:192
double penwidth
Definition gvcjob.h:199
double x
Definition geom.h:29
double y
Definition geom.h:29
char * name
Definition textspan.h:54
unsigned int flags
Definition textspan.h:58
double size
Definition textspan.h:57
char * str
Definition textspan.h:65
char just
'l' 'n' 'r'
Definition textspan.h:71
pointf size
Definition textspan.h:70
textfont_t * font
Definition textspan.h:66
double yoffset_centerline
Definition textspan.h:69
const char * name
Definition usershape.h:54
attrsym_t * n_l_draw
double yOff
ymin + ymax
attrsym_t * t_draw
attrsym_t * g_draw
attrsym_t * g_l_draw
attrsym_t * e_l_draw
attrsym_t * tl_draw
attrsym_t * n_draw
attrsym_t * h_draw
unsigned short version
attrsym_t * e_draw
attrsym_t * hl_draw
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30