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
22extern char *xml_string(char *str);
23extern char *xml_url_string(char *str);
24
25typedef enum { FORMAT_IMAP, FORMAT_ISMAP, FORMAT_CMAP, FORMAT_CMAPX, } format_type;
26
27static 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
150static 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
186static 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
208static 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
218static 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
226static void
227map_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
251static 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
260static 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
293static gvrender_features_t render_features_map = {
294 EMIT_CLUSTERS_LAST
295 | GVRENDER_Y_GOES_DOWN
296 | GVRENDER_DOES_MAPS
297 | GVRENDER_DOES_LABELS
298 | GVRENDER_DOES_TOOLTIPS
299 | GVRENDER_DOES_TARGETS
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
307static gvdevice_features_t device_features_map = {
308 GVRENDER_DOES_MAP_CIRCLE
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
315static 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
322gvplugin_installed_t gvrender_map_types[] = {
323 {FORMAT_ISMAP, "map", 1, &map_engine, &render_features_map},
324 {0, NULL, 0, NULL, NULL}
325};
326
327gvplugin_installed_t gvdevice_map_types[] = {
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};
336