| 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 |  | 
|---|