00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020
00021 #include <stdarg.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024
00025 #include "macros.h"
00026 #include "const.h"
00027
00028 #include "gvplugin_render.h"
00029 #include "graph.h"
00030
00031 typedef enum { FORMAT_VML, FORMAT_VMLZ, } format_type;
00032
00033 extern char *xml_string(char *str);
00034
00035 char graphcoords[256];
00036
00037 #if defined(WIN32) && !defined(__MINGW32_VERSION)
00038 static int
00039 snprintf (char *str, int n, char *fmt, ...)
00040 {
00041 int ret;
00042 va_list a;
00043 va_start (a, fmt);
00044 ret = _vsnprintf (str, n, fmt, a);
00045 va_end (a);
00046 return ret;
00047 }
00048 #endif
00049
00050 static void vml_bzptarray(GVJ_t * job, pointf * A, int n)
00051 {
00052 int i;
00053 char *c;
00054
00055 c = "m ";
00056 for (i = 0; i < n; i++) {
00057 gvdevice_printf(job, "%s%.0f,%.0f ", c, A[i].x, -A[i].y);
00058 if (i == 0)
00059 c = "c ";
00060 else
00061 c = "";
00062 }
00063 }
00064
00065 static void vml_print_color(GVJ_t * job, gvcolor_t color)
00066 {
00067 switch (color.type) {
00068 case COLOR_STRING:
00069 gvdevice_fputs(job, color.u.string);
00070 break;
00071 case RGBA_BYTE:
00072 if (color.u.rgba[3] == 0)
00073 gvdevice_fputs(job, "none");
00074 else
00075 gvdevice_printf(job, "#%02x%02x%02x",
00076 color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
00077 break;
00078 default:
00079 assert(0);
00080 }
00081 }
00082
00083 static void vml_grstroke(GVJ_t * job, int filled)
00084 {
00085 obj_state_t *obj = job->obj;
00086
00087 gvdevice_fputs(job, "<v:stroke fillcolor=\"");
00088 if (filled)
00089 vml_print_color(job, obj->fillcolor);
00090 else
00091 gvdevice_fputs(job, "none");
00092 gvdevice_fputs(job, "\" strokecolor=\"");
00093 vml_print_color(job, obj->pencolor);
00094 if (obj->penwidth != PENWIDTH_NORMAL)
00095 gvdevice_printf(job, "\" stroke-weight=\"%g", obj->penwidth);
00096 if (obj->pen == PEN_DASHED) {
00097 gvdevice_fputs(job, "\" dashstyle=\"dash");
00098 } else if (obj->pen == PEN_DOTTED) {
00099 gvdevice_fputs(job, "\" dashstyle=\"dot");
00100 }
00101 gvdevice_fputs(job, "\" />");
00102 }
00103
00104 static void vml_grstrokeattr(GVJ_t * job)
00105 {
00106 obj_state_t *obj = job->obj;
00107
00108 gvdevice_fputs(job, " strokecolor=\"");
00109 vml_print_color(job, obj->pencolor);
00110 if (obj->penwidth != PENWIDTH_NORMAL)
00111 gvdevice_printf(job, "\" stroke-weight=\"%g", obj->penwidth);
00112 if (obj->pen == PEN_DASHED) {
00113 gvdevice_fputs(job, "\" dashstyle=\"dash");
00114 } else if (obj->pen == PEN_DOTTED) {
00115 gvdevice_fputs(job, "\" dashstyle=\"dot");
00116 }
00117 gvdevice_fputs(job, "\"");
00118 }
00119
00120 static void vml_grfill(GVJ_t * job, int filled)
00121 {
00122 obj_state_t *obj = job->obj;
00123
00124 gvdevice_fputs(job, "<v:fill color=\"");
00125 if (filled)
00126 vml_print_color(job, obj->fillcolor);
00127 else
00128 gvdevice_fputs(job, "none");
00129 gvdevice_fputs(job, "\" />");
00130 }
00131
00132 static void vml_comment(GVJ_t * job, char *str)
00133 {
00134 gvdevice_fputs(job, " <!-- ");
00135 gvdevice_fputs(job, xml_string(str));
00136 gvdevice_fputs(job, " -->\n");
00137 }
00138
00139 static void vml_begin_job(GVJ_t * job)
00140 {
00141 gvdevice_fputs(job, "<?xml version=\"1.1\" encoding=\"UTF-8\" ?>\n");
00142
00143 gvdevice_fputs(job, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" ");
00144 gvdevice_fputs(job, "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n");
00145 gvdevice_fputs(job, "<html xml:lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" ");
00146 gvdevice_fputs(job, "xmlns:v=\"urn:schemas-microsoft-com:vml\"");
00147 gvdevice_fputs(job, ">");
00148
00149 gvdevice_fputs(job, "\n<!-- Generated by ");
00150 gvdevice_fputs(job, xml_string(job->common->info[0]));
00151 gvdevice_fputs(job, " version ");
00152 gvdevice_fputs(job, xml_string(job->common->info[1]));
00153 gvdevice_fputs(job, " (");
00154 gvdevice_fputs(job, xml_string(job->common->info[2]));
00155 gvdevice_fputs(job, ")\n For user: ");
00156 gvdevice_fputs(job, xml_string(job->common->user));
00157 gvdevice_fputs(job, " -->\n");
00158 }
00159
00160 static void vml_begin_graph(GVJ_t * job)
00161 {
00162 obj_state_t *obj = job->obj;
00163
00164 gvdevice_fputs(job, "<head>");
00165 if (obj->u.g->name[0]) {
00166 gvdevice_fputs(job, "<title>");
00167 gvdevice_fputs(job, xml_string(obj->u.g->name));
00168 gvdevice_fputs(job, "</title>");
00169 }
00170 gvdevice_printf(job, "<!-- Pages: %d -->\n</head>\n", job->pagesArraySize.x * job->pagesArraySize.y);
00171
00172 snprintf(graphcoords, sizeof(graphcoords), "style=\"width: %.0fpt; height: %.0fpt\" coordsize=\"%.0f,%.0f\" coordorigin=\"-4,-%.0f\"",
00173 job->width*.75, job->height*.75,
00174 job->width*.75, job->height*.75,
00175 job->height*.75 - 4);
00176
00177 gvdevice_printf(job, "<body>\n<div class=\"graph\" %s>\n", graphcoords);
00178 gvdevice_fputs(job, "<style type=\"text/css\">\nv\\:* {\nbehavior: url(#default#VML);display:inline-block;position: absolute; left: 0px; top: 0px;\n}\n</style>\n");
00179
00180
00181 }
00182
00183 static void vml_end_graph(GVJ_t * job)
00184 {
00185 gvdevice_fputs(job, "</div>\n</body>\n");
00186 }
00187
00188 static void
00189 vml_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target)
00190 {
00191 gvdevice_fputs(job, " <a");
00192 if (href && href[0])
00193 gvdevice_printf(job, " href=\"%s\"", xml_string(href));
00194 if (tooltip && tooltip[0])
00195 gvdevice_printf(job, " title=\"%s\"", xml_string(tooltip));
00196 if (target && target[0])
00197 gvdevice_printf(job, " target=\"%s\"", xml_string(target));
00198 gvdevice_fputs(job, ">\n");
00199 }
00200
00201 static void vml_end_anchor(GVJ_t * job)
00202 {
00203 gvdevice_fputs(job, " </a>\n");
00204 }
00205
00206 static void vml_textpara(GVJ_t * job, pointf p, textpara_t * para)
00207 {
00208 obj_state_t *obj = job->obj;
00209
00210 gvdevice_fputs(job, " <div");
00211 switch (para->just) {
00212 case 'l':
00213 gvdevice_fputs(job, " style=\"text-align: left; ");
00214 break;
00215 case 'r':
00216 gvdevice_fputs(job, " style=\"text-align: right; ");
00217 break;
00218 default:
00219 case 'n':
00220 gvdevice_fputs(job, " style=\"text-align: center; ");
00221 break;
00222 }
00223 gvdevice_printf(job, "position: absolute; left: %gpx; top: %gpx;", p.x/.75, job->height - p.y/.75 - 14);
00224 if (para->postscript_alias) {
00225 gvdevice_printf(job, " font-family: '%s';", para->postscript_alias->family);
00226 if (para->postscript_alias->weight)
00227 gvdevice_printf(job, " font-weight: %s;", para->postscript_alias->weight);
00228 if (para->postscript_alias->stretch)
00229 gvdevice_printf(job, " font-stretch: %s;", para->postscript_alias->stretch);
00230 if (para->postscript_alias->style)
00231 gvdevice_printf(job, " font-style: %s;", para->postscript_alias->style);
00232 }
00233 else {
00234 gvdevice_printf(job, " font-family: \'%s\';", para->fontname);
00235 }
00236
00237 gvdevice_printf(job, " font-size: %.2fpt;", para->fontsize * 0.81);
00238 switch (obj->pencolor.type) {
00239 case COLOR_STRING:
00240 if (strcasecmp(obj->pencolor.u.string, "black"))
00241 gvdevice_printf(job, "color:%s;", obj->pencolor.u.string);
00242 break;
00243 case RGBA_BYTE:
00244 gvdevice_printf(job, "color:#%02x%02x%02x;",
00245 obj->pencolor.u.rgba[0], obj->pencolor.u.rgba[1], obj->pencolor.u.rgba[2]);
00246 break;
00247 default:
00248 assert(0);
00249 }
00250 gvdevice_fputs(job, "\">");
00251 gvdevice_fputs(job, xml_string(para->str));
00252 gvdevice_fputs(job, "</div>\n");
00253 }
00254
00255 static void vml_ellipse(GVJ_t * job, pointf * A, int filled)
00256 {
00257
00258
00259 gvdevice_fputs(job, " <v:oval");
00260
00261 vml_grstrokeattr(job);
00262
00263 gvdevice_fputs(job, " style=\"position: absolute;");
00264
00265 gvdevice_printf(job, " left: %gpt; top: %gpt;", 2*A[0].x - A[1].x+4, job->height*.75 - A[1].y-4);
00266 gvdevice_printf(job, " width: %gpt; height: %gpt;", 2*(A[1].x - A[0].x), 2*(A[1].y - A[0].y));
00267 gvdevice_fputs(job, "\">");
00268 vml_grstroke(job, filled);
00269 vml_grfill(job, filled);
00270 gvdevice_fputs(job, "</v:oval>\n");
00271 }
00272
00273 static void
00274 vml_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00275 int arrow_at_end, int filled)
00276 {
00277 gvdevice_printf(job, " <v:shape %s><!-- bezier --><v:path", graphcoords);
00278 gvdevice_fputs(job, " v=\"");
00279 vml_bzptarray(job, A, n);
00280 gvdevice_fputs(job, "\" />");
00281 vml_grstroke(job, filled);
00282 gvdevice_fputs(job, "</v:path>");
00283 vml_grfill(job, filled);
00284 gvdevice_fputs(job, "</v:shape>\n");
00285 }
00286
00287 static void vml_polygon(GVJ_t * job, pointf * A, int n, int filled)
00288 {
00289 int i;
00290
00291 gvdevice_fputs(job, " <v:shape");
00292 vml_grstrokeattr(job);
00293 gvdevice_printf(job, " %s><!-- polygon --><v:path", graphcoords);
00294 gvdevice_fputs(job, " v=\"");
00295 for (i = 0; i < n; i++)
00296 {
00297 if (i==0) gvdevice_fputs(job, "m ");
00298 gvdevice_printf(job, "%.0f,%.0f ", A[i].x, -A[i].y);
00299 if (i==0) gvdevice_fputs(job, "l ");
00300 if (i==n-1) gvdevice_fputs(job, "x e ");
00301 }
00302 gvdevice_fputs(job, "\">");
00303 vml_grstroke(job, filled);
00304 gvdevice_fputs(job, "</v:path>");
00305 vml_grfill(job, filled);
00306 gvdevice_fputs(job, "</v:shape>\n");
00307 }
00308
00309 static void vml_polyline(GVJ_t * job, pointf * A, int n)
00310 {
00311 int i;
00312
00313 gvdevice_printf(job, " <v:shape %s><!-- polyline --><v:path", graphcoords);
00314 gvdevice_fputs(job, " v=\"");
00315 for (i = 0; i < n; i++)
00316 {
00317 if (i==0) gvdevice_fputs(job, " m ");
00318 gvdevice_printf(job, "%.0f,%.0f ", A[i].x, -A[i].y);
00319 if (i==0) gvdevice_fputs(job, " l ");
00320 if (i==n-1) gvdevice_fputs(job, " e ");
00321 }
00322 gvdevice_fputs(job, "\">");
00323 vml_grstroke(job, 0);
00324 gvdevice_fputs(job, "</v:path>");
00325 gvdevice_fputs(job, "</v:shape>\n");
00326
00327 }
00328
00329
00330
00331 static char *vml_knowncolors[] = {
00332 "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
00333 "beige", "bisque", "black", "blanchedalmond", "blue",
00334 "blueviolet", "brown", "burlywood",
00335 "cadetblue", "chartreuse", "chocolate", "coral",
00336 "cornflowerblue", "cornsilk", "crimson", "cyan",
00337 "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
00338 "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
00339 "darkolivegreen", "darkorange", "darkorchid", "darkred",
00340 "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
00341 "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
00342 "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
00343 "firebrick", "floralwhite", "forestgreen", "fuchsia",
00344 "gainsboro", "ghostwhite", "gold", "goldenrod", "gray",
00345 "green", "greenyellow", "grey",
00346 "honeydew", "hotpink", "indianred",
00347 "indigo", "ivory", "khaki",
00348 "lavender", "lavenderblush", "lawngreen", "lemonchiffon",
00349 "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
00350 "lightgray", "lightgreen", "lightgrey", "lightpink",
00351 "lightsalmon", "lightseagreen", "lightskyblue",
00352 "lightslategray", "lightslategrey", "lightsteelblue",
00353 "lightyellow", "lime", "limegreen", "linen",
00354 "magenta", "maroon", "mediumaquamarine", "mediumblue",
00355 "mediumorchid", "mediumpurple", "mediumseagreen",
00356 "mediumslateblue", "mediumspringgreen", "mediumturquoise",
00357 "mediumvioletred", "midnightblue", "mintcream",
00358 "mistyrose", "moccasin",
00359 "navajowhite", "navy", "oldlace",
00360 "olive", "olivedrab", "orange", "orangered", "orchid",
00361 "palegoldenrod", "palegreen", "paleturquoise",
00362 "palevioletred", "papayawhip", "peachpuff", "peru", "pink",
00363 "plum", "powderblue", "purple",
00364 "red", "rosybrown", "royalblue",
00365 "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell",
00366 "sienna", "silver", "skyblue", "slateblue", "slategray",
00367 "slategrey", "snow", "springgreen", "steelblue",
00368 "tan", "teal", "thistle", "tomato", "turquoise",
00369 "violet",
00370 "wheat", "white", "whitesmoke",
00371 "yellow", "yellowgreen"
00372 };
00373
00374 gvrender_engine_t vml_engine = {
00375 vml_begin_job,
00376 0,
00377 vml_begin_graph,
00378 vml_end_graph,
00379 0,
00380 0,
00381 0,
00382 0,
00383 0,
00384 0,
00385 0,
00386 0,
00387 0,
00388 0,
00389 0,
00390 0,
00391 0,
00392 0,
00393 vml_begin_anchor,
00394 vml_end_anchor,
00395 vml_textpara,
00396 0,
00397 vml_ellipse,
00398 vml_polygon,
00399 vml_bezier,
00400 vml_polyline,
00401 vml_comment,
00402 0,
00403 };
00404
00405 gvrender_features_t render_features_vml = {
00406 GVRENDER_Y_GOES_DOWN
00407 | GVRENDER_DOES_TRANSFORM
00408 | GVRENDER_DOES_LABELS
00409 | GVRENDER_DOES_MAPS
00410 | GVRENDER_DOES_TARGETS
00411 | GVRENDER_DOES_TOOLTIPS,
00412 4.,
00413 vml_knowncolors,
00414 sizeof(vml_knowncolors) / sizeof(char *),
00415 RGBA_BYTE,
00416 };
00417
00418 gvdevice_features_t device_features_vml = {
00419 GVDEVICE_DOES_TRUECOLOR,
00420 {0.,0.},
00421 {0.,0.},
00422 {96.,96.},
00423 };
00424
00425 gvdevice_features_t device_features_vmlz = {
00426 GVDEVICE_DOES_TRUECOLOR
00427 | GVDEVICE_COMPRESSED_FORMAT,
00428 {0.,0.},
00429 {0.,0.},
00430 {96.,96.},
00431 };
00432
00433 gvplugin_installed_t gvrender_vml_types[] = {
00434 {FORMAT_VML, "vml", 1, &vml_engine, &render_features_vml},
00435 {0, NULL, 0, NULL, NULL}
00436 };
00437
00438 gvplugin_installed_t gvdevice_vml_types[] = {
00439 {FORMAT_VML, "vml:vml", 1, NULL, &device_features_vml},
00440 #if HAVE_LIBZ
00441 {FORMAT_VMLZ, "vmlz:vml", 1, NULL, &device_features_vmlz},
00442 #endif
00443 {0, NULL, 0, NULL, NULL}
00444 };