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 | |
25 | typedef enum { FORMAT_IMAP, FORMAT_ISMAP, FORMAT_CMAP, FORMAT_CMAPX, } format_type; |
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 = { |
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 | |
307 | static 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 | |
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 | |
322 | gvplugin_installed_t gvrender_map_types[] = { |
323 | {FORMAT_ISMAP, "map" , 1, &map_engine, &render_features_map}, |
324 | {0, NULL, 0, NULL, NULL} |
325 | }; |
326 | |
327 | gvplugin_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 | |