Graphviz  2.29.20120524.0446
plugin/core/gvrender_core_map.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #include <stdlib.h>
00019 
00020 #include "gvplugin_render.h"
00021 #include "gvplugin_device.h"
00022 #include "gvio.h"
00023 
00024 extern char *xml_string(char *str);
00025 extern char *xml_url_string(char *str);
00026 
00027 typedef enum { FORMAT_IMAP, FORMAT_ISMAP, FORMAT_CMAP, FORMAT_CMAPX, } format_type;
00028 
00029 static void map_output_shape (GVJ_t *job, map_shape_t map_shape, pointf * AF, int nump,
00030                 char* url, char *tooltip, char *target, char *id)
00031 {
00032     int i;
00033 
00034     static point *A;
00035     static int size_A;
00036 
00037     if (!AF || !nump)
00038         return;
00039 
00040     if (size_A < nump) {
00041         size_A = nump + 10;
00042         A = realloc(A, size_A * sizeof(point));
00043     }
00044     for (i = 0; i < nump; i++)
00045         PF2P(AF[i], A[i]);
00046 
00047     if (job->render.id == FORMAT_IMAP && url && url[0]) {
00048         switch (map_shape) {
00049         case MAP_RECTANGLE:
00050             /* Y_GOES_DOWN so need UL to LR */
00051             gvprintf(job, "rect %s %d,%d %d,%d\n", url,
00052                 A[0].x, A[1].y, A[1].x, A[0].y);
00053             break;
00054         case MAP_CIRCLE:
00055             gvprintf(job, "circle %s %d,%d,%d\n", url,
00056                 A[0].x, A[0].y, A[1].x-A[0].x);
00057             break;
00058         case MAP_POLYGON:
00059             gvprintf(job, "poly %s", url);
00060             for (i = 0; i < nump; i++)
00061                 gvprintf(job, " %d,%d", A[i].x, A[i].y);
00062             gvputs(job, "\n");
00063             break;
00064         default:
00065             assert(0);
00066             break;
00067         }
00068 
00069     } else if (job->render.id == FORMAT_ISMAP && url && url[0]) {
00070         switch (map_shape) {
00071         case MAP_RECTANGLE:
00072             /* Y_GOES_DOWN so need UL to LR */
00073             gvprintf(job, "rectangle (%d,%d) (%d,%d) %s %s\n",
00074                 A[0].x, A[1].y, A[1].x, A[0].y, url, tooltip);
00075             break;
00076         default:
00077             assert(0);
00078             break;
00079         }
00080 
00081     } else if (job->render.id == FORMAT_CMAP || job->render.id == FORMAT_CMAPX) {
00082         switch (map_shape) {
00083         case MAP_CIRCLE:
00084             gvputs(job, "<area shape=\"circle\"");
00085             break;
00086         case MAP_RECTANGLE:
00087             gvputs(job, "<area shape=\"rect\"");
00088             break;
00089         case MAP_POLYGON:
00090             gvputs(job, "<area shape=\"poly\"");
00091             break;
00092         default:
00093             assert(0);
00094             break;
00095         }
00096         if (id && id[0]) {
00097             gvputs(job, " id=\"");
00098             gvputs(job, xml_url_string(id));
00099             gvputs(job, "\"");
00100         }
00101         if (url && url[0]) {
00102             gvputs(job, " href=\"");
00103             gvputs(job, xml_url_string(url));
00104             gvputs(job, "\"");
00105         }
00106         if (target && target[0]) {
00107             gvputs(job, " target=\"");
00108             gvputs(job, xml_string(target));
00109             gvputs(job, "\"");
00110         }
00111         if (tooltip && tooltip[0]) {
00112             gvputs(job, " title=\"");
00113             gvputs(job, xml_string(tooltip));
00114             gvputs(job, "\"");
00115         }
00116         /*
00117          * alt text is intended for the visually impaired, but such
00118          * folk are not likely to be clicking around on a graph anyway.
00119          * IE on the PC platform (but not on Macs) incorrectly
00120          * uses (non-empty) alt strings instead of title strings for tooltips.
00121          * To make tooltips work and avoid this IE issue,
00122          * while still satisfying usability guidelines
00123          * that require that there is always an alt string,
00124          * we generate just an empty alt string.
00125          */
00126         gvputs(job, " alt=\"\"");
00127 
00128         gvputs(job, " coords=\"");
00129         switch (map_shape) {
00130         case MAP_CIRCLE:
00131             gvprintf(job, "%d,%d,%d", A[0].x, A[0].y, A[1].x-A[0].x);
00132             break;
00133         case MAP_RECTANGLE:
00134             /* Y_GOES_DOWN so need UL to LR */
00135             gvprintf(job, "%d,%d,%d,%d", A[0].x, A[1].y, A[1].x, A[0].y);  
00136             break;
00137         case MAP_POLYGON:
00138             gvprintf(job, "%d,%d", A[0].x, A[0].y);
00139             for (i = 1; i < nump; i++)
00140                 gvprintf(job, ",%d,%d", A[i].x, A[i].y);
00141             break;
00142         default:
00143             break;
00144         }
00145         if (job->render.id == FORMAT_CMAPX)
00146             gvputs(job, "\"/>\n");
00147         else
00148             gvputs(job, "\">\n");
00149     }
00150 }
00151 
00152 static void map_begin_page(GVJ_t * job)
00153 {
00154     obj_state_t *obj = job->obj;
00155     char *s;
00156 
00157     switch (job->render.id) {
00158     case FORMAT_IMAP:
00159         gvputs(job, "base referer\n");
00160         if (obj->url && obj->url[0]) {
00161             gvputs(job, "default ");
00162             gvputs(job, xml_string(obj->url));
00163             gvputs(job, "\n");
00164         }
00165         break;
00166     case FORMAT_ISMAP:
00167         if (obj->url && obj->url[0]) {
00168             gvputs(job, "default ");
00169             gvputs(job, xml_string(obj->url));
00170             gvputs(job, " ");
00171             gvputs(job, xml_string(agnameof(obj->u.g)));
00172             gvputs(job, "\n");
00173         }
00174         break;
00175     case FORMAT_CMAPX:
00176         s = xml_string(agnameof(obj->u.g));
00177         gvputs(job, "<map id=\"");
00178         gvputs(job, s);
00179         gvputs(job, "\" name=\"");
00180         gvputs(job, s);
00181         gvputs(job, "\">\n");
00182         break;
00183     default:
00184         break;
00185     }
00186 }
00187 
00188 static void map_end_page(GVJ_t * job)
00189 {
00190     obj_state_t *obj = job->obj;
00191 
00192     switch (job->render.id) {
00193     case FORMAT_CMAP:
00194         map_output_shape(job, obj->url_map_shape,
00195                 obj->url_map_p,obj->url_map_n,
00196                 obj->url, obj->tooltip, obj->target, obj->id);
00197         break;
00198     case FORMAT_CMAPX:
00199         map_output_shape(job, obj->url_map_shape,
00200                 obj->url_map_p,obj->url_map_n,
00201                 obj->url, obj->tooltip, obj->target, obj->id);
00202         gvputs(job, "</map>\n");
00203         break;
00204     default:
00205         break;
00206     }
00207 }
00208 
00209 #if 0
00210 static void map_begin_cluster(GVJ_t * job)
00211 {
00212     obj_state_t *obj = job->obj;
00213 
00214     gvprintf(job, "%% %s\n", obj->u.sg->name);
00215 
00216     map_output_shape(job, obj->url_map_shape, obj->url_map_p, obj->url_map_n,
00217                 obj->url, obj->tooltip, obj->target);
00218 }
00219 
00220 static void map_begin_node(GVJ_t * job)
00221 {
00222     obj_state_t *obj = job->obj;
00223 
00224     map_output_shape(job, obj->url_map_shape, obj->url_map_p,obj->url_map_n,
00225                 obj->url, obj->tooltip, obj->target);
00226 }
00227 
00228 static void
00229 map_begin_edge(GVJ_t * job)
00230 {
00231     obj_state_t *obj = job->obj;
00232     int i, j = 0;
00233 
00234     map_output_shape(job, obj->url_map_shape, obj->url_map_p, obj->url_map_n,
00235                 obj->url, obj->tooltip, obj->target);
00236     map_output_shape(job, MAP_RECTANGLE, obj->tailurl_map_p, 2,
00237                 obj->tailurl, obj->tailtooltip, obj->tailtarget);
00238     map_output_shape(job, MAP_RECTANGLE, obj->headurl_map_p, 2,
00239                 obj->headurl, obj->headtooltip, obj->headtarget);
00240     map_output_shape(job, MAP_RECTANGLE, obj->tailendurl_map_p,2, 
00241                 obj->url, obj->tooltip, obj->target);
00242     map_output_shape(job, MAP_RECTANGLE, obj->headendurl_map_p, 2,
00243                 obj->url, obj->tooltip, obj->target);
00244     for (i = 0; i < obj->url_bsplinemap_poly_n; i++) {
00245         map_output_shape(job, MAP_POLYGON,
00246                 obj->url_bsplinemap_p+j, obj->url_bsplinemap_n[i],
00247                 obj->url, obj->tooltip, obj->target);
00248         j += obj->url_bsplinemap_n[i];
00249     }
00250 }
00251 #endif
00252 
00253 static void map_begin_anchor(GVJ_t * job, char *url, char *tooltip, char *target, char *id)
00254 {
00255     obj_state_t *obj = job->obj;
00256 
00257     map_output_shape(job, obj->url_map_shape,
00258                 obj->url_map_p, obj->url_map_n, 
00259                 url, tooltip, target, id);
00260 }
00261 
00262 static gvrender_engine_t map_engine = {
00263     0,                          /* map_begin_job */
00264     0,                          /* map_end_job */
00265     0,                          /* map_begin_graph */
00266     0,                          /* map_end_graph */
00267     0,                          /* map_begin_layer */
00268     0,                          /* map_end_layer */
00269     map_begin_page,
00270     map_end_page,
00271     0,                          /* map_begin_cluster */
00272     0,                          /* map_end_cluster */
00273     0,                          /* map_begin_nodes */
00274     0,                          /* map_end_nodes */
00275     0,                          /* map_begin_edges */
00276     0,                          /* map_end_edges */
00277     0,                          /* map_begin_node */
00278     0,                          /* map_end_node */
00279     0,                          /* map_begin_edge */
00280     0,                          /* map_end_edge */
00281     map_begin_anchor,
00282     0,                          /* map_end_anchor */
00283     0,                          /* map_begin_label */
00284     0,                          /* map_end_label */
00285     0,                          /* map_textpara */
00286     0,                          /* map_resolve_color */
00287     0,                          /* map_ellipse */
00288     0,                          /* map_polygon */
00289     0,                          /* map_bezier */
00290     0,                          /* map_polyline */
00291     0,                          /* map_comment */
00292     0,                          /* map_library_shape */
00293 };
00294 
00295 static gvrender_features_t render_features_map = {
00296     EMIT_CLUSTERS_LAST
00297         | GVRENDER_Y_GOES_DOWN
00298         | GVRENDER_DOES_MAPS
00299         | GVRENDER_DOES_LABELS
00300         | GVRENDER_DOES_TOOLTIPS
00301         | GVRENDER_DOES_TARGETS
00302         | GVRENDER_DOES_MAP_RECTANGLE, /* flags */
00303     4.,                         /* default pad - graph units */
00304     NULL,                       /* knowncolors */
00305     0,                          /* sizeof knowncolors */
00306     0,                          /* color_type */
00307 };
00308 
00309 static gvdevice_features_t device_features_map = {
00310     GVRENDER_DOES_MAP_CIRCLE
00311         | GVRENDER_DOES_MAP_POLYGON, /* flags */
00312     {0.,0.},                    /* default margin - points */
00313     {0.,0.},                    /* default page width, height - points */
00314     {96.,96.},                  /* default dpi */
00315 };
00316 
00317 static gvdevice_features_t device_features_map_nopoly = {
00318     0,                          /* flags */
00319     {0.,0.},                    /* default margin - points */
00320     {0.,0.},                    /* default page width, height - points */
00321     {96.,96.},                  /* default dpi */
00322 };
00323 
00324 gvplugin_installed_t gvrender_map_types[] = {
00325     {FORMAT_ISMAP, "map", 1, &map_engine, &render_features_map},
00326     {0, NULL, 0, NULL, NULL}
00327 };
00328 
00329 gvplugin_installed_t gvdevice_map_types[] = {
00330     {FORMAT_ISMAP, "ismap:map", 1, NULL, &device_features_map_nopoly},
00331     {FORMAT_CMAP, "cmap:map", 1, NULL, &device_features_map},
00332     {FORMAT_IMAP, "imap:map", 1, NULL, &device_features_map},
00333     {FORMAT_CMAPX, "cmapx:map", 1, NULL, &device_features_map},
00334     {FORMAT_IMAP, "imap_np:map", 1, NULL, &device_features_map_nopoly},
00335     {FORMAT_CMAPX, "cmapx_np:map", 1, NULL, &device_features_map_nopoly},
00336     {0, NULL, 0, NULL, NULL}
00337 };