Graphviz 15.1.1~dev.20260630.1303
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 v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.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, job, false);
468 break;
469 case FORMAT_PLAIN_EXT:
470 write_plain(job, g, 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 int j;
496
497 agxbput(xbufs[emit_state], "F ");
498 xdot_fmt_num(xbufs[emit_state], span->font->size);
499 xdot_str (job, "", span->font->name);
500 xdot_pencolor(job);
501
502 switch (span->just) {
503 case 'l':
504 j = -1;
505 break;
506 case 'r':
507 j = 1;
508 break;
509 default:
510 case 'n':
511 j = 0;
512 break;
513 }
514 const unsigned flags = span->font->flags;
515 const size_t flag_masks_size = sizeof(flag_masks) / sizeof(flag_masks[0]);
516 if (xd->version >= 15 && (size_t)xd->version - 15 < flag_masks_size) {
517 unsigned int mask = flag_masks[xd->version-15];
518 unsigned int bits = flags & mask;
519 if (textflags[emit_state] != bits) {
520 agxbprint(xbufs[emit_state], "t %u ", bits);
521 textflags[emit_state] = bits;
522 }
523 }
524
525 p.y += span->yoffset_centerline;
526 agxbput(xbufs[emit_state], "T ");
527 xdot_point(xbufs[emit_state], p);
528 agxbprint(xbufs[emit_state], "%d ", j);
529 xdot_fmt_num(xbufs[emit_state], span->size.x);
530 xdot_str (job, "", span->str);
531}
532
533static void xdot_color_stop(agxbuf *xb, double v, gvcolor_t *clr) {
534 agxbprint(xb, "%.03f", v);
536 agxbputc(xb, ' ');
537 xdot_str_color_xbuf(xb, "", clr->u.rgba);
538}
539
540static void xdot_gradient_fillcolor(GVJ_t *job, int filled, pointf *A, size_t n)
541{
542 obj_state_t* obj = job->obj;
543 double angle = obj->gradient_angle * M_PI / 180;
544 pointf G[2],c1,c2;
545
546 if (xd->version < 14) {
547 xdot_fillcolor (job);
548 return;
549 }
550
551 agxbuf xb = {0};
552 if (filled == GRADIENT) {
553 get_gradient_points(A, G, n, angle, 2);
554 agxbputc (&xb, '[');
555 xdot_point (&xb, G[0]);
556 xdot_point (&xb, G[1]);
557 }
558 else {
559 get_gradient_points(A, G, n, 0, 3);
560 // r2 is outer radius
561 double r2 = G[1].y;
562 if (obj->gradient_angle == 0) {
563 c1.x = G[0].x;
564 c1.y = G[0].y;
565 }
566 else {
567 c1.x = G[0].x + r2 / 4 * cos(angle);
568 c1.y = G[0].y + r2 / 4 * sin(angle);
569 }
570 c2.x = G[0].x;
571 c2.y = G[0].y;
572 double r1 = r2 / 4;
573 agxbputc(&xb, '(');
574 xdot_point (&xb, c1);
575 xdot_num (&xb, r1);
576 xdot_point (&xb, c2);
577 xdot_num (&xb, r2);
578 }
579
580 agxbput(&xb, "2 ");
581 if (obj->gradient_frac > 0) {
582 xdot_color_stop (&xb, obj->gradient_frac, &obj->fillcolor);
583 xdot_color_stop (&xb, obj->gradient_frac, &obj->stopcolor);
584 }
585 else {
586 xdot_color_stop (&xb, 0, &obj->fillcolor);
587 xdot_color_stop (&xb, 1, &obj->stopcolor);
588 }
589 agxbpop(&xb);
590 if (filled == GRADIENT)
591 agxbputc(&xb, ']');
592 else
593 agxbputc(&xb, ')');
594 xdot_str (job, "C ", agxbuse(&xb));
595 agxbfree(&xb);
596}
597
598static void xdot_ellipse(GVJ_t * job, pointf * A, int filled)
599{
600 emit_state_t emit_state = job->obj->emit_state;
601
602 xdot_style (job);
603 xdot_pencolor (job);
604 if (filled) {
605 if (filled == GRADIENT || filled == RGRADIENT) {
606 xdot_gradient_fillcolor (job, filled, A, 2);
607 }
608 else
609 xdot_fillcolor (job);
610 agxbput(xbufs[emit_state], "E ");
611 }
612 else
613 agxbput(xbufs[emit_state], "e ");
614 xdot_point(xbufs[emit_state], A[0]);
615 xdot_fmt_num(xbufs[emit_state], A[1].x - A[0].x);
616 xdot_fmt_num(xbufs[emit_state], A[1].y - A[0].y);
617}
618
619static void xdot_bezier(GVJ_t *job, pointf *A, size_t n, int filled) {
620 xdot_style (job);
621 xdot_pencolor (job);
622 if (filled) {
623 if (filled == GRADIENT || filled == RGRADIENT) {
624 xdot_gradient_fillcolor(job, filled, A, n);
625 }
626 else
627 xdot_fillcolor (job);
628 xdot_points(job, 'b', A, n); // NB - 'B' & 'b' are reversed in comparison to the other items
629 }
630 else
631 xdot_points(job, 'B', A, n);
632}
633
634static void xdot_polygon(GVJ_t *job, pointf *A, size_t n, int filled) {
635 xdot_style (job);
636 xdot_pencolor (job);
637 if (filled) {
638 if (filled == GRADIENT || filled == RGRADIENT) {
639 xdot_gradient_fillcolor(job, filled, A, n);
640 }
641 else
642 xdot_fillcolor (job);
643 xdot_points(job, 'P', A, n);
644 }
645 else
646 xdot_points(job, 'p', A, n);
647}
648
649static void xdot_polyline(GVJ_t *job, pointf *A, size_t n) {
650 xdot_style (job);
651 xdot_pencolor (job);
652 xdot_points(job, 'L', A, n);
653}
654
655void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, bool filled)
656{
657 (void)filled;
658
659 emit_state_t emit_state = job->obj->emit_state;
660
661 agxbput(xbufs[emit_state], "I ");
662 xdot_point(xbufs[emit_state], b.LL);
663 xdot_fmt_num(xbufs[emit_state], b.UR.x - b.LL.x);
664 xdot_fmt_num(xbufs[emit_state], b.UR.y - b.LL.y);
665 xdot_str (job, "", us->name);
666}
667
669 0, /* dot_begin_job */
670 0, /* dot_end_job */
673 0, /* dot_begin_layer */
674 0, /* dot_end_layer */
675 0, /* dot_begin_page */
676 0, /* dot_end_page */
677 0, /* dot_begin_cluster */
678 0, /* dot_end_cluster */
679 0, /* dot_begin_nodes */
680 0, /* dot_end_nodes */
681 0, /* dot_begin_edges */
682 0, /* dot_end_edges */
683 0, /* dot_begin_node */
684 0, /* dot_end_node */
685 0, /* dot_begin_edge */
686 0, /* dot_end_edge */
687 0, /* dot_begin_anchor */
688 0, /* dot_end_anchor */
689 0, /* dot_begin_label */
690 0, /* dot_end_label */
691 0, /* dot_textspan */
692 0, /* dot_resolve_color */
693 0, /* dot_ellipse */
694 0, /* dot_polygon */
695 0, /* dot_bezier */
696 0, /* dot_polyline */
697 0, /* dot_comment */
698 0, /* dot_library_shape */
699};
700
702 0, /* xdot_begin_job */
703 0, /* xdot_end_job */
706 0, /* xdot_begin_layer */
707 0, /* xdot_end_layer */
708 0, /* xdot_begin_page */
709 0, /* xdot_end_page */
710 0, /* xdot_begin_cluster */
712 0, /* xdot_begin_nodes */
713 0, /* xdot_end_nodes */
714 0, /* xdot_begin_edges */
715 0, /* xdot_end_edges */
716 0, /* xdot_begin_node */
718 0, /* xdot_begin_edge */
720 0, /* xdot_begin_anchor */
721 0, /* xdot_end_anchor */
722 0, /* xdot_begin_label */
723 0, /* xdot_end_label */
725 0, /* xdot_resolve_color */
730 0, /* xdot_comment */
731 0, /* xdot_library_shape */
732};
733
735 GVRENDER_DOES_TRANSFORM, /* not really - uses raw graph coords */ /* flags */
736 0., /* default pad - graph units */
737 NULL, /* knowncolors */
738 0, /* sizeof knowncolors */
739 COLOR_STRING, /* color_type */
740};
741
743 GVRENDER_DOES_TRANSFORM /* not really - uses raw graph coords */
746 | GVRENDER_DOES_TOOLTIPS, /* flags */
747 0., /* default pad - graph units */
748 NULL, /* knowncolors */
749 0, /* sizeof knowncolors */
750 RGBA_BYTE, /* color_type */
751};
752
754 LAYOUT_NOT_REQUIRED, /* flags */
755 {0.,0.}, /* default margin - points */
756 {0.,0.}, /* default height, width - device units */
757 {72.,72.}, /* default dpi */
758};
759
761 0, /* flags */
762 {0.,0.}, /* default margin - points */
763 {0.,0.}, /* default page width, height - points */
764 {72.,72.}, /* default dpi */
765};
766
772
774 {FORMAT_DOT, "dot:dot", 1, NULL, &device_features_dot},
775 {FORMAT_DOT, "gv:dot", 1, NULL, &device_features_dot},
776 {FORMAT_CANON, "canon:dot", 1, NULL, &device_features_canon},
777 {FORMAT_PLAIN, "plain:dot", 1, NULL, &device_features_dot},
778 {FORMAT_PLAIN_EXT, "plain-ext:dot", 1, NULL, &device_features_dot},
779 {FORMAT_XDOT, "xdot:xdot", 1, NULL, &device_features_dot},
780 {FORMAT_XDOT12, "xdot1.2:xdot", 1, NULL, &device_features_dot},
781 {FORMAT_XDOT14, "xdot1.4:xdot", 1, NULL, &device_features_dot},
782 {0, NULL, 0, NULL, NULL}
783};
Dynamically expanding string buffers.
static int agxbpop(agxbuf *xb)
removes last character added, if any
Definition agxbuf.h:130
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
static size_t agxblen(const agxbuf *xb)
return number of characters currently stored
Definition agxbuf.h:108
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:295
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:1030
attrsym_t * safe_dcl(graph_t *g, int obj_kind, char *name, char *defaultValue)
Definition utils.c:1065
void get_gradient_points(pointf *A, pointf *G, size_t n, double angle, int flags)
Definition utils.c:1446
#define HEAD_LABEL
Definition const.h:168
#define EDGE_XLABEL
Definition const.h:172
#define GRAPH_LABEL
Definition const.h:170
#define TAIL_LABEL
Definition const.h:169
#define EDGE_LABEL
Definition const.h:167
#define GRADIENT
Definition const.h:223
#define RGRADIENT
Definition const.h:224
#define A(n, t)
Definition expr.h:76
static int flags
Definition gc.c:63
#define G
Definition gdefs.h:7
void free(void *)
require define api prefix
Definition gmlparse.y:17
node NULL
Definition grammar.y:181
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:521
char * agget(void *obj, char *name)
Definition attr.c:447
int agsafeset(void *obj, char *name, const char *value, const char *def)
set an attribute’s value and default, ensuring it is declared before setting it locally
Definition attr.c:559
Agiodisc_t AgIoDisc
Definition io.c:41
void agwarningf(const char *fmt,...)
Definition agerror.c:175
#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:669
#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:416
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:308
int gvputs(GVJ_t *job, const char *s)
Definition gvdevice.c:266
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)
static 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)
static gvrender_engine_t dot_engine
static void xdot_num(agxbuf *xb, double v)
static 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)
static 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)
static gvrender_features_t render_features_xdot
static 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:218
#define HAS_CLUST_EDGE(g)
Definition macros.h:24
void write_plain(GVJ_t *job, graph_t *g, void *f, bool extend)
Definition output.c:129
double attach_attrs_and_arrows(graph_t *g, bool *sp, bool *ep)
Definition output.c:254
double yDir(double y, double Y_off)
Definition output.c:35
#define PRISIZE_T
Definition prisize_t.h:25
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
Agdisc_t disc
Definition cgraph.h:411
Agiodisc_t * io
Definition cgraph.h:338
Agobj_t base
Definition cgraph.h:269
IO services.
Definition cgraph.h:326
int(* afread)(void *chan, char *buf, int bufsize)
Definition cgraph.h:327
int(* flush)(void *chan)
Definition cgraph.h:329
int(* putstr)(void *chan, const char *str)
Definition cgraph.h:328
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:424
Agobj_t base
Definition cgraph.h:425
Agclos_t * clos
shared resources
Definition cgraph.h:434
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:640
int flags
Definition gvcjob.h:299
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::@40 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
gvcolor_t stopcolor
Definition gvcjob.h:194
node_t * n
Definition gvcjob.h:188
union obj_state_s::@65 u
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:90
#define UNREACHABLE()
Definition unreachable.h:30