Graphviz 13.0.0~dev.20250424.1043
Loading...
Searching...
No Matches
gvrender_core_map.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 <stdlib.h>
14
15#include <gvc/gvplugin_render.h>
16#include <gvc/gvplugin_device.h>
17#include <gvc/gvio.h>
18#include <util/unreachable.h>
19#include <util/xml.h>
20
22
24static int gvputs_wrapper(void *state, const char *s) {
25 return gvputs(state, s);
26}
27
28// wrapper around `gv_xml_escape` to set flags for URL escaping
29static void xml_url_puts(GVJ_t *job, const char *s) {
30 const xml_flags_t flags = {0};
31 (void)gv_xml_escape(s, flags, gvputs_wrapper, job);
32}
33
34static void map_output_shape(GVJ_t *job, map_shape_t map_shape, pointf *AF, size_t nump,
35 char* url, char *tooltip, char *target, char *id)
36{
37 if (!AF || !nump)
38 return;
39
40 if (job->render.id == FORMAT_IMAP && url && url[0]) {
41 switch (map_shape) {
42 case MAP_RECTANGLE:
43 /* Y_GOES_DOWN so need UL to LR */
44 gvprintf(job, "rect %s %.0f,%.0f %.0f,%.0f\n", url, AF[0].x,
45 AF[1].y, AF[1].x, AF[0].y);
46 break;
47 case MAP_CIRCLE:
48 gvprintf(job, "circle %s %.0f,%.0f,%.0f\n", url, AF[0].x, AF[0].y,
49 AF[1].x - AF[0].x);
50 break;
51 case MAP_POLYGON:
52 gvprintf(job, "poly %s", url);
53 for (size_t i = 0; i < nump; i++) {
54 gvprintf(job, " %.0f,%.0f", AF[i].x, AF[i].y);
55 }
56 gvputs(job, "\n");
57 break;
58 default:
60 }
61
62 } else if (job->render.id == FORMAT_ISMAP && url && url[0]) {
63 switch (map_shape) {
64 case MAP_RECTANGLE:
65 /* Y_GOES_DOWN so need UL to LR */
66 gvprintf(job, "rectangle (%.0f,%.0f) (%.0f,%.0f) %s %s\n",
67 AF[0].x, AF[1].y, AF[1].x, AF[0].y, url, tooltip);
68 break;
69 default:
71 }
72
73 } else if (job->render.id == FORMAT_CMAP || job->render.id == FORMAT_CMAPX) {
74 switch (map_shape) {
75 case MAP_CIRCLE:
76 gvputs(job, "<area shape=\"circle\"");
77 break;
78 case MAP_RECTANGLE:
79 gvputs(job, "<area shape=\"rect\"");
80 break;
81 case MAP_POLYGON:
82 gvputs(job, "<area shape=\"poly\"");
83 break;
84 default:
86 }
87 if (id && id[0]) {
88 gvputs(job, " id=\"");
89 xml_url_puts(job, id);
90 gvputs(job, "\"");
91 }
92 if (url && url[0]) {
93 gvputs(job, " href=\"");
94 xml_url_puts(job, url);
95 gvputs(job, "\"");
96 }
97 if (target && target[0]) {
98 gvputs(job, " target=\"");
99 gvputs_xml(job, target);
100 gvputs(job, "\"");
101 }
102 if (tooltip && tooltip[0]) {
103 gvputs(job, " title=\"");
104 gvputs_xml(job, tooltip);
105 gvputs(job, "\"");
106 }
107 // FIXME:
108 // - https://gitlab.com/graphviz/graphviz/-/issues/265
109 // - https://gitlab.com/graphviz/graphviz/-/issues/2220
110 gvputs(job, " alt=\"\"");
111
112 gvputs(job, " coords=\"");
113 switch (map_shape) {
114 case MAP_CIRCLE:
115 gvprintf(job, "%.0f,%.0f,%.0f", AF[0].x, AF[0].y,
116 AF[1].x - AF[0].x);
117 break;
118 case MAP_RECTANGLE:
119 /* Y_GOES_DOWN so need UL to LR */
120 gvprintf(job, "%.0f,%.0f,%.0f,%.0f", AF[0].x, AF[1].y, AF[1].x,
121 AF[0].y);
122 break;
123 case MAP_POLYGON:
124 gvprintf(job, "%.0f,%.0f", AF[0].x, AF[0].y);
125 for (size_t i = 1; i < nump; i++) {
126 gvprintf(job, ",%.0f,%.0f", AF[i].x, AF[i].y);
127 }
128 break;
129 default:
130 break;
131 }
132 if (job->render.id == FORMAT_CMAPX)
133 gvputs(job, "\"/>\n");
134 else
135 gvputs(job, "\">\n");
136 }
137}
138
139static void map_begin_page(GVJ_t * job)
140{
141 obj_state_t *obj = job->obj;
142
143 switch (job->render.id) {
144 case FORMAT_IMAP:
145 gvputs(job, "base referer\n");
146 if (obj->url && obj->url[0]) {
147 gvputs(job, "default ");
148 gvputs_xml(job, obj->url);
149 gvputs(job, "\n");
150 }
151 break;
152 case FORMAT_ISMAP:
153 if (obj->url && obj->url[0]) {
154 gvputs(job, "default ");
155 gvputs_xml(job, obj->url);
156 gvputs(job, " ");
157 gvputs_xml(job, agnameof(obj->u.g));
158 gvputs(job, "\n");
159 }
160 break;
161 case FORMAT_CMAPX:
162 gvputs(job, "<map id=\"");
163 gvputs_xml(job, agnameof(obj->u.g));
164 gvputs(job, "\" name=\"");
165 gvputs_xml(job, agnameof(obj->u.g));
166 gvputs(job, "\">\n");
167 break;
168 default:
169 break;
170 }
171}
172
173static void map_end_page(GVJ_t * job)
174{
175 obj_state_t *obj = job->obj;
176
177 switch (job->render.id) {
178 case FORMAT_CMAP:
180 obj->url_map_p,obj->url_map_n,
181 obj->url, obj->tooltip, obj->target, obj->id);
182 break;
183 case FORMAT_CMAPX:
185 obj->url_map_p,obj->url_map_n,
186 obj->url, obj->tooltip, obj->target, obj->id);
187 gvputs(job, "</map>\n");
188 break;
189 default:
190 break;
191 }
192}
193
194static void map_begin_anchor(GVJ_t * job, char *url, char *tooltip, char *target, char *id)
195{
196 obj_state_t *obj = job->obj;
197
199 obj->url_map_p, obj->url_map_n,
200 url, tooltip, target, id);
201}
202
204 0, /* map_begin_job */
205 0, /* map_end_job */
206 0, /* map_begin_graph */
207 0, /* map_end_graph */
208 0, /* map_begin_layer */
209 0, /* map_end_layer */
212 0, /* map_begin_cluster */
213 0, /* map_end_cluster */
214 0, /* map_begin_nodes */
215 0, /* map_end_nodes */
216 0, /* map_begin_edges */
217 0, /* map_end_edges */
218 0, /* map_begin_node */
219 0, /* map_end_node */
220 0, /* map_begin_edge */
221 0, /* map_end_edge */
223 0, /* map_end_anchor */
224 0, /* map_begin_label */
225 0, /* map_end_label */
226 0, /* map_textpara */
227 0, /* map_resolve_color */
228 0, /* map_ellipse */
229 0, /* map_polygon */
230 0, /* map_bezier */
231 0, /* map_polyline */
232 0, /* map_comment */
233 0, /* map_library_shape */
234};
235
243 | GVRENDER_DOES_MAP_RECTANGLE, /* flags */
244 4., /* default pad - graph units */
245 NULL, /* knowncolors */
246 0, /* sizeof knowncolors */
247 0, /* color_type */
248};
249
252 | GVRENDER_DOES_MAP_POLYGON, /* flags */
253 {0.,0.}, /* default margin - points */
254 {0.,0.}, /* default page width, height - points */
255 {96.,96.}, /* default dpi */
256};
257
259 0, /* flags */
260 {0.,0.}, /* default margin - points */
261 {0.,0.}, /* default page width, height - points */
262 {96.,96.}, /* default dpi */
263};
264
269
271 {FORMAT_ISMAP, "ismap:map", 1, NULL, &device_features_map_nopoly},
272 {FORMAT_CMAP, "cmap:map", 1, NULL, &device_features_map},
273 {FORMAT_IMAP, "imap:map", 1, NULL, &device_features_map},
274 {FORMAT_CMAPX, "cmapx:map", 1, NULL, &device_features_map},
275 {FORMAT_IMAP, "imap_np:map", 1, NULL, &device_features_map_nopoly},
276 {FORMAT_CMAPX, "cmapx_np:map", 1, NULL, &device_features_map_nopoly},
277 {0, NULL, 0, NULL, NULL}
278};
static int flags
Definition gc.c:61
node NULL
Definition grammar.y:163
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
#define EMIT_CLUSTERS_LAST
Definition gvcjob.h:84
#define GVRENDER_DOES_TOOLTIPS
Definition gvcjob.h:103
#define GVRENDER_DOES_LABELS
Definition gvcjob.h:96
map_shape_t
Definition gvcjob.h:166
@ MAP_CIRCLE
Definition gvcjob.h:166
@ MAP_POLYGON
Definition gvcjob.h:166
@ MAP_RECTANGLE
Definition gvcjob.h:166
#define GVRENDER_DOES_MAPS
Definition gvcjob.h:97
#define GVRENDER_DOES_TARGETS
Definition gvcjob.h:104
#define GVRENDER_Y_GOES_DOWN
Definition gvcjob.h:94
#define GVRENDER_DOES_MAP_POLYGON
Definition gvcjob.h:100
#define GVRENDER_DOES_MAP_RECTANGLE
Definition gvcjob.h:98
#define GVRENDER_DOES_MAP_CIRCLE
Definition gvcjob.h:99
int gvputs_xml(GVJ_t *job, const char *s)
Definition gvdevice.c:281
int gvputs(GVJ_t *job, const char *s)
Definition gvdevice.c:266
void gvprintf(GVJ_t *job, const char *format,...)
Definition gvdevice.c:402
static void map_begin_anchor(GVJ_t *job, char *url, char *tooltip, char *target, char *id)
static gvdevice_features_t device_features_map_nopoly
gvplugin_installed_t gvrender_map_types[]
static gvrender_engine_t map_engine
static void map_output_shape(GVJ_t *job, map_shape_t map_shape, pointf *AF, size_t nump, char *url, char *tooltip, char *target, char *id)
static void map_begin_page(GVJ_t *job)
static int gvputs_wrapper(void *state, const char *s)
wrap gvputs to offer a void * first parameter
@ FORMAT_IMAP
@ FORMAT_CMAP
@ FORMAT_ISMAP
@ FORMAT_CMAPX
static gvdevice_features_t device_features_map
gvplugin_installed_t gvdevice_map_types[]
static void map_end_page(GVJ_t *job)
static gvrender_features_t render_features_map
static void xml_url_puts(GVJ_t *job, const char *s)
obj_state_t * obj
Definition gvcjob.h:269
gvplugin_active_render_t render
Definition gvcjob.h:285
ingroup plugin_api
Definition gvplugin.h:35
graph_t * g
Definition gvcjob.h:186
pointf * url_map_p
Definition gvcjob.h:240
char * tooltip
Definition gvcjob.h:216
char * url
Definition gvcjob.h:210
char * target
Definition gvcjob.h:221
map_shape_t url_map_shape
Definition gvcjob.h:238
char * id
Definition gvcjob.h:211
size_t url_map_n
Definition gvcjob.h:239
union obj_state_s::@90 u
options to tweak the behavior of XML escaping
Definition xml.h:30
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30
int gv_xml_escape(const char *s, xml_flags_t flags, int(*cb)(void *state, const char *s), void *state)
Definition xml.c:178
XML escaping functionality.