Graphviz  2.41.20170921.2350
gvrender_core_map.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 #include <stdlib.h>
17 
18 #include "gvplugin_render.h"
19 #include "gvplugin_device.h"
20 #include "gvio.h"
21 
22 extern char *xml_string(char *str);
23 extern char *xml_url_string(char *str);
24 
26 
27 static void map_output_shape (GVJ_t *job, map_shape_t map_shape, pointf * AF, int nump,
28  char* url, char *tooltip, char *target, char *id)
29 {
30  int i;
31 
32  static point *A;
33  static int size_A;
34 
35  if (!AF || !nump)
36  return;
37 
38  if (size_A < nump) {
39  size_A = nump + 10;
40  A = realloc(A, size_A * sizeof(point));
41  }
42  for (i = 0; i < nump; i++)
43  PF2P(AF[i], A[i]);
44 
45  if (job->render.id == FORMAT_IMAP && url && url[0]) {
46  switch (map_shape) {
47  case MAP_RECTANGLE:
48  /* Y_GOES_DOWN so need UL to LR */
49  gvprintf(job, "rect %s %d,%d %d,%d\n", url,
50  A[0].x, A[1].y, A[1].x, A[0].y);
51  break;
52  case MAP_CIRCLE:
53  gvprintf(job, "circle %s %d,%d,%d\n", url,
54  A[0].x, A[0].y, A[1].x-A[0].x);
55  break;
56  case MAP_POLYGON:
57  gvprintf(job, "poly %s", url);
58  for (i = 0; i < nump; i++)
59  gvprintf(job, " %d,%d", A[i].x, A[i].y);
60  gvputs(job, "\n");
61  break;
62  default:
63  assert(0);
64  break;
65  }
66 
67  } else if (job->render.id == FORMAT_ISMAP && url && url[0]) {
68  switch (map_shape) {
69  case MAP_RECTANGLE:
70  /* Y_GOES_DOWN so need UL to LR */
71  gvprintf(job, "rectangle (%d,%d) (%d,%d) %s %s\n",
72  A[0].x, A[1].y, A[1].x, A[0].y, url, tooltip);
73  break;
74  default:
75  assert(0);
76  break;
77  }
78 
79  } else if (job->render.id == FORMAT_CMAP || job->render.id == FORMAT_CMAPX) {
80  switch (map_shape) {
81  case MAP_CIRCLE:
82  gvputs(job, "<area shape=\"circle\"");
83  break;
84  case MAP_RECTANGLE:
85  gvputs(job, "<area shape=\"rect\"");
86  break;
87  case MAP_POLYGON:
88  gvputs(job, "<area shape=\"poly\"");
89  break;
90  default:
91  assert(0);
92  break;
93  }
94  if (id && id[0]) {
95  gvputs(job, " id=\"");
96  gvputs(job, xml_url_string(id));
97  gvputs(job, "\"");
98  }
99  if (url && url[0]) {
100  gvputs(job, " href=\"");
101  gvputs(job, xml_url_string(url));
102  gvputs(job, "\"");
103  }
104  if (target && target[0]) {
105  gvputs(job, " target=\"");
106  gvputs(job, xml_string(target));
107  gvputs(job, "\"");
108  }
109  if (tooltip && tooltip[0]) {
110  gvputs(job, " title=\"");
111  gvputs(job, xml_string(tooltip));
112  gvputs(job, "\"");
113  }
114  /*
115  * alt text is intended for the visually impaired, but such
116  * folk are not likely to be clicking around on a graph anyway.
117  * IE on the PC platform (but not on Macs) incorrectly
118  * uses (non-empty) alt strings instead of title strings for tooltips.
119  * To make tooltips work and avoid this IE issue,
120  * while still satisfying usability guidelines
121  * that require that there is always an alt string,
122  * we generate just an empty alt string.
123  */
124  gvputs(job, " alt=\"\"");
125 
126  gvputs(job, " coords=\"");
127  switch (map_shape) {
128  case MAP_CIRCLE:
129  gvprintf(job, "%d,%d,%d", A[0].x, A[0].y, A[1].x-A[0].x);
130  break;
131  case MAP_RECTANGLE:
132  /* Y_GOES_DOWN so need UL to LR */
133  gvprintf(job, "%d,%d,%d,%d", A[0].x, A[1].y, A[1].x, A[0].y);
134  break;
135  case MAP_POLYGON:
136  gvprintf(job, "%d,%d", A[0].x, A[0].y);
137  for (i = 1; i < nump; i++)
138  gvprintf(job, ",%d,%d", A[i].x, A[i].y);
139  break;
140  default:
141  break;
142  }
143  if (job->render.id == FORMAT_CMAPX)
144  gvputs(job, "\"/>\n");
145  else
146  gvputs(job, "\">\n");
147  }
148 }
149 
150 static void map_begin_page(GVJ_t * job)
151 {
152  obj_state_t *obj = job->obj;
153  char *s;
154 
155  switch (job->render.id) {
156  case FORMAT_IMAP:
157  gvputs(job, "base referer\n");
158  if (obj->url && obj->url[0]) {
159  gvputs(job, "default ");
160  gvputs(job, xml_string(obj->url));
161  gvputs(job, "\n");
162  }
163  break;
164  case FORMAT_ISMAP:
165  if (obj->url && obj->url[0]) {
166  gvputs(job, "default ");
167  gvputs(job, xml_string(obj->url));
168  gvputs(job, " ");
169  gvputs(job, xml_string(agnameof(obj->u.g)));
170  gvputs(job, "\n");
171  }
172  break;
173  case FORMAT_CMAPX:
174  s = xml_string(agnameof(obj->u.g));
175  gvputs(job, "<map id=\"");
176  gvputs(job, s);
177  gvputs(job, "\" name=\"");
178  gvputs(job, s);
179  gvputs(job, "\">\n");
180  break;
181  default:
182  break;
183  }
184 }
185 
186 static void map_end_page(GVJ_t * job)
187 {
188  obj_state_t *obj = job->obj;
189 
190  switch (job->render.id) {
191  case FORMAT_CMAP:
192  map_output_shape(job, obj->url_map_shape,
193  obj->url_map_p,obj->url_map_n,
194  obj->url, obj->tooltip, obj->target, obj->id);
195  break;
196  case FORMAT_CMAPX:
197  map_output_shape(job, obj->url_map_shape,
198  obj->url_map_p,obj->url_map_n,
199  obj->url, obj->tooltip, obj->target, obj->id);
200  gvputs(job, "</map>\n");
201  break;
202  default:
203  break;
204  }
205 }
206 
207 #if 0
208 static void map_begin_cluster(GVJ_t * job)
209 {
210  obj_state_t *obj = job->obj;
211 
212  gvprintf(job, "%% %s\n", obj->u.sg->name);
213 
214  map_output_shape(job, obj->url_map_shape, obj->url_map_p, obj->url_map_n,
215  obj->url, obj->tooltip, obj->target);
216 }
217 
218 static void map_begin_node(GVJ_t * job)
219 {
220  obj_state_t *obj = job->obj;
221 
222  map_output_shape(job, obj->url_map_shape, obj->url_map_p,obj->url_map_n,
223  obj->url, obj->tooltip, obj->target);
224 }
225 
226 static void
227 map_begin_edge(GVJ_t * job)
228 {
229  obj_state_t *obj = job->obj;
230  int i, j = 0;
231 
232  map_output_shape(job, obj->url_map_shape, obj->url_map_p, obj->url_map_n,
233  obj->url, obj->tooltip, obj->target);
234  map_output_shape(job, MAP_RECTANGLE, obj->tailurl_map_p, 2,
235  obj->tailurl, obj->tailtooltip, obj->tailtarget);
236  map_output_shape(job, MAP_RECTANGLE, obj->headurl_map_p, 2,
237  obj->headurl, obj->headtooltip, obj->headtarget);
238  map_output_shape(job, MAP_RECTANGLE, obj->tailendurl_map_p,2,
239  obj->url, obj->tooltip, obj->target);
240  map_output_shape(job, MAP_RECTANGLE, obj->headendurl_map_p, 2,
241  obj->url, obj->tooltip, obj->target);
242  for (i = 0; i < obj->url_bsplinemap_poly_n; i++) {
243  map_output_shape(job, MAP_POLYGON,
244  obj->url_bsplinemap_p+j, obj->url_bsplinemap_n[i],
245  obj->url, obj->tooltip, obj->target);
246  j += obj->url_bsplinemap_n[i];
247  }
248 }
249 #endif
250 
251 static void map_begin_anchor(GVJ_t * job, char *url, char *tooltip, char *target, char *id)
252 {
253  obj_state_t *obj = job->obj;
254 
255  map_output_shape(job, obj->url_map_shape,
256  obj->url_map_p, obj->url_map_n,
257  url, tooltip, target, id);
258 }
259 
260 static gvrender_engine_t map_engine = {
261  0, /* map_begin_job */
262  0, /* map_end_job */
263  0, /* map_begin_graph */
264  0, /* map_end_graph */
265  0, /* map_begin_layer */
266  0, /* map_end_layer */
267  map_begin_page,
268  map_end_page,
269  0, /* map_begin_cluster */
270  0, /* map_end_cluster */
271  0, /* map_begin_nodes */
272  0, /* map_end_nodes */
273  0, /* map_begin_edges */
274  0, /* map_end_edges */
275  0, /* map_begin_node */
276  0, /* map_end_node */
277  0, /* map_begin_edge */
278  0, /* map_end_edge */
279  map_begin_anchor,
280  0, /* map_end_anchor */
281  0, /* map_begin_label */
282  0, /* map_end_label */
283  0, /* map_textpara */
284  0, /* map_resolve_color */
285  0, /* map_ellipse */
286  0, /* map_polygon */
287  0, /* map_bezier */
288  0, /* map_polyline */
289  0, /* map_comment */
290  0, /* map_library_shape */
291 };
292 
293 static gvrender_features_t render_features_map = {
300  | GVRENDER_DOES_MAP_RECTANGLE, /* flags */
301  4., /* default pad - graph units */
302  NULL, /* knowncolors */
303  0, /* sizeof knowncolors */
304  0, /* color_type */
305 };
306 
307 static gvdevice_features_t device_features_map = {
309  | GVRENDER_DOES_MAP_POLYGON, /* flags */
310  {0.,0.}, /* default margin - points */
311  {0.,0.}, /* default page width, height - points */
312  {96.,96.}, /* default dpi */
313 };
314 
315 static gvdevice_features_t device_features_map_nopoly = {
316  0, /* flags */
317  {0.,0.}, /* default margin - points */
318  {0.,0.}, /* default page width, height - points */
319  {96.,96.}, /* default dpi */
320 };
321 
323  {FORMAT_ISMAP, "map", 1, &map_engine, &render_features_map},
324  {0, NULL, 0, NULL, NULL}
325 };
326 
328  {FORMAT_ISMAP, "ismap:map", 1, NULL, &device_features_map_nopoly},
329  {FORMAT_CMAP, "cmap:map", 1, NULL, &device_features_map},
330  {FORMAT_IMAP, "imap:map", 1, NULL, &device_features_map},
331  {FORMAT_CMAPX, "cmapx:map", 1, NULL, &device_features_map},
332  {FORMAT_IMAP, "imap_np:map", 1, NULL, &device_features_map_nopoly},
333  {FORMAT_CMAPX, "cmapx_np:map", 1, NULL, &device_features_map_nopoly},
334  {0, NULL, 0, NULL, NULL}
335 };
pointf * tailendurl_map_p
Definition: gvcjob.h:259
int url_map_n
Definition: gvcjob.h:248
char * xml_url_string(char *s)
Definition: labels.c:572
char * tailtooltip
Definition: gvcjob.h:227
#define GVRENDER_DOES_MAP_POLYGON
Definition: gvcjob.h:103
#define assert(x)
Definition: cghdr.h:47
Definition: geom.h:28
#define PF2P(pf, p)
Definition: geom.h:72
gvplugin_installed_t gvdevice_map_types[]
Definition: gvcjob.h:271
#define GVRENDER_DOES_MAP_RECTANGLE
Definition: gvcjob.h:101
obj_state_t * obj
Definition: gvcjob.h:278
#define GVRENDER_Y_GOES_DOWN
Definition: gvcjob.h:96
int gvputs(GVJ_t *job, const char *s)
Definition: gvdevice.c:270
char * tooltip
Definition: gvcjob.h:225
#define GVRENDER_DOES_TARGETS
Definition: gvcjob.h:107
#define GVRENDER_DOES_TOOLTIPS
Definition: gvcjob.h:106
#define GVRENDER_DOES_MAP_CIRCLE
Definition: gvcjob.h:102
char * tailtarget
Definition: gvcjob.h:232
gvplugin_active_render_t render
Definition: gvcjob.h:294
char * xml_string(char *s)
Definition: labels.c:485
pointf * url_map_p
Definition: gvcjob.h:249
CGRAPH_API char * agnameof(void *)
Definition: id.c:143
char * url
Definition: gvcjob.h:219
int * url_bsplinemap_n
Definition: gvcjob.h:254
pointf * url_bsplinemap_p
Definition: gvcjob.h:256
Definition: grammar.c:79
graph_t * g
Definition: gvcjob.h:195
char * headtarget
Definition: gvcjob.h:233
format_type
#define GVRENDER_DOES_MAPS
Definition: gvcjob.h:100
#define NULL
Definition: logic.h:39
graph_t * sg
Definition: gvcjob.h:196
Definition: geom.h:26
pointf * headendurl_map_p
Definition: gvcjob.h:262
int url_bsplinemap_poly_n
Definition: gvcjob.h:252
union obj_state_s::@23 u
char * target
Definition: gvcjob.h:230
map_shape_t
Definition: gvcjob.h:175
char * tailurl
Definition: gvcjob.h:222
#define GVRENDER_DOES_LABELS
Definition: gvcjob.h:99
agxbuf * str
Definition: htmlparse.c:85
char * id
Definition: gvcjob.h:220
#define EMIT_CLUSTERS_LAST
Definition: gvcjob.h:86
char * headtooltip
Definition: gvcjob.h:228
map_shape_t url_map_shape
Definition: gvcjob.h:247
gvplugin_installed_t gvrender_map_types[]
void gvprintf(GVJ_t *job, const char *format,...)
Definition: gvdevice.c:389
char * headurl
Definition: gvcjob.h:223