|
Graphviz
2.29.20120524.0446
|
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 /* Comments on the SVG coordinate system (SN 8 Dec 2006): 00015 The initial <svg> element defines the SVG coordinate system so 00016 that the graphviz canvas (in units of points) fits the intended 00017 absolute size in inches. After this, the situation should be 00018 that "px" = "pt" in SVG, so we can dispense with stating units. 00019 Also, the input units (such as fontsize) should be preserved 00020 without scaling in the output SVG (as long as the graph size 00021 was not constrained.) 00022 */ 00023 00024 #ifdef HAVE_CONFIG_H 00025 #include "config.h" 00026 #endif 00027 00028 #include <stdarg.h> 00029 #include <stdlib.h> 00030 #include <string.h> 00031 #include <ctype.h> 00032 00033 #include "macros.h" 00034 #include "const.h" 00035 00036 #include "gvplugin_render.h" 00037 #include "agxbuf.h" 00038 #include "utils.h" 00039 #include "gvplugin_device.h" 00040 #include "gvio.h" 00041 #include "gvcint.h" 00042 00043 typedef enum { FORMAT_SVG, FORMAT_SVGZ, } format_type; 00044 00045 /* SVG dash array */ 00046 static char *sdasharray = "5,2"; 00047 /* SVG dot array */ 00048 static char *sdotarray = "1,5"; 00049 00050 #ifndef HAVE_STRCASECMP 00051 extern int strcasecmp(const char *s1, const char *s2); 00052 #endif 00053 00054 static void svg_bzptarray(GVJ_t * job, pointf * A, int n) 00055 { 00056 int i; 00057 char c; 00058 00059 c = 'M'; /* first point */ 00060 for (i = 0; i < n; i++) { 00061 gvprintf(job, "%c%g,%g", c, A[i].x, -A[i].y); 00062 if (i == 0) 00063 c = 'C'; /* second point */ 00064 else 00065 c = ' '; /* remaining points */ 00066 } 00067 } 00068 00069 static void svg_print_color(GVJ_t * job, gvcolor_t color) 00070 { 00071 switch (color.type) { 00072 case COLOR_STRING: 00073 gvputs(job, color.u.string); 00074 break; 00075 case RGBA_BYTE: 00076 if (color.u.rgba[3] == 0) /* transparent */ 00077 gvputs(job, "none"); 00078 else 00079 gvprintf(job, "#%02x%02x%02x", 00080 color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]); 00081 break; 00082 default: 00083 assert(0); /* internal error */ 00084 } 00085 } 00086 00087 static void svg_grstyle(GVJ_t * job, int filled, int gid) 00088 { 00089 obj_state_t *obj = job->obj; 00090 00091 gvputs(job, " fill=\""); 00092 if (filled == GRADIENT) { 00093 gvprintf(job, "url(#l_%d)", gid); 00094 } else if (filled == RGRADIENT) { 00095 gvprintf(job, "url(#r_%d)", gid); 00096 } else if (filled) { 00097 svg_print_color(job, obj->fillcolor); 00098 if (obj->fillcolor.type == RGBA_BYTE 00099 && obj->fillcolor.u.rgba[3] > 0 00100 && obj->fillcolor.u.rgba[3] < 255) 00101 gvprintf(job, "\" fill-opacity=\"%f", 00102 ((float) obj->fillcolor.u.rgba[3] / 255.0)); 00103 } else { 00104 gvputs(job, "none"); 00105 } 00106 gvputs(job, "\" stroke=\""); 00107 svg_print_color(job, obj->pencolor); 00108 if (obj->penwidth != PENWIDTH_NORMAL) 00109 gvprintf(job, "\" stroke-width=\"%g", obj->penwidth); 00110 if (obj->pen == PEN_DASHED) { 00111 gvprintf(job, "\" stroke-dasharray=\"%s", sdasharray); 00112 } else if (obj->pen == PEN_DOTTED) { 00113 gvprintf(job, "\" stroke-dasharray=\"%s", sdotarray); 00114 } 00115 if (obj->pencolor.type == RGBA_BYTE && obj->pencolor.u.rgba[3] > 0 00116 && obj->pencolor.u.rgba[3] < 255) 00117 gvprintf(job, "\" stroke-opacity=\"%f", 00118 ((float) obj->pencolor.u.rgba[3] / 255.0)); 00119 00120 gvputs(job, "\""); 00121 } 00122 00123 static void svg_comment(GVJ_t * job, char *str) 00124 { 00125 gvputs(job, "<!-- "); 00126 gvputs(job, xml_string(str)); 00127 gvputs(job, " -->\n"); 00128 } 00129 00130 static void svg_begin_job(GVJ_t * job) 00131 { 00132 char *s; 00133 gvputs(job, 00134 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); 00135 if ((s = agget(job->gvc->g, "stylesheet")) && s[0]) { 00136 gvputs(job, "<?xml-stylesheet href=\""); 00137 gvputs(job, s); 00138 gvputs(job, "\" type=\"text/css\"?>\n"); 00139 } 00140 #if 0 00141 gvputs(job, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"); 00142 gvputs(job, 00143 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\""); 00144 /* This is to work around a bug in the SVG 1.0 DTD */ 00145 gvputs(job, 00146 " [\n <!ATTLIST svg xmlns:xlink CDATA #FIXED \"http://www.w3.org/1999/xlink\">\n]"); 00147 #else 00148 gvputs(job, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"); 00149 gvputs(job, 00150 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"); 00151 #endif 00152 00153 gvputs(job, "<!-- Generated by "); 00154 gvputs(job, xml_string(job->common->info[0])); 00155 gvputs(job, " version "); 00156 gvputs(job, xml_string(job->common->info[1])); 00157 gvputs(job, " ("); 00158 gvputs(job, xml_string(job->common->info[2])); 00159 gvputs(job, ")\n"); 00160 gvputs(job, " -->\n"); 00161 } 00162 00163 static void svg_begin_graph(GVJ_t * job) 00164 { 00165 obj_state_t *obj = job->obj; 00166 00167 gvputs(job, "<!--"); 00168 if (agnameof(obj->u.g)[0]) { 00169 gvputs(job, " Title: "); 00170 gvputs(job, xml_string(agnameof(obj->u.g))); 00171 } 00172 gvprintf(job, " Pages: %d -->\n", 00173 job->pagesArraySize.x * job->pagesArraySize.y); 00174 00175 gvprintf(job, "<svg width=\"%dpt\" height=\"%dpt\"\n", 00176 job->width, job->height); 00177 gvprintf(job, " viewBox=\"%.2f %.2f %.2f %.2f\"", 00178 job->canvasBox.LL.x, job->canvasBox.LL.y, 00179 job->canvasBox.UR.x, job->canvasBox.UR.y); 00180 /* namespace of svg */ 00181 gvputs(job, " xmlns=\"http://www.w3.org/2000/svg\""); 00182 /* namespace of xlink */ 00183 gvputs(job, " xmlns:xlink=\"http://www.w3.org/1999/xlink\""); 00184 gvputs(job, ">\n"); 00185 } 00186 00187 static void svg_end_graph(GVJ_t * job) 00188 { 00189 gvputs(job, "</svg>\n"); 00190 } 00191 00192 static void svg_begin_layer(GVJ_t * job, char *layername, int layerNum, 00193 int numLayers) 00194 { 00195 gvputs(job, "<g id=\""); 00196 gvputs(job, xml_string(layername)); 00197 gvputs(job, "\" class=\"layer\">\n"); 00198 } 00199 00200 static void svg_end_layer(GVJ_t * job) 00201 { 00202 gvputs(job, "</g>\n"); 00203 } 00204 00205 static void svg_begin_page(GVJ_t * job) 00206 { 00207 obj_state_t *obj = job->obj; 00208 00209 /* its really just a page of the graph, but its still a graph, 00210 * and it is the entire graph if we're not currently paging */ 00211 gvputs(job, "<g id=\""); 00212 gvputs(job, xml_string(obj->id)); 00213 gvputs(job, "\" class=\"graph\""); 00214 gvprintf(job, 00215 " transform=\"scale(%g %g) rotate(%d) translate(%g %g)\">\n", 00216 job->scale.x, job->scale.y, -job->rotation, 00217 job->translation.x, -job->translation.y); 00218 /* default style */ 00219 if (agnameof(obj->u.g)[0]) { 00220 gvputs(job, "<title>"); 00221 gvputs(job, xml_string(agnameof(obj->u.g))); 00222 gvputs(job, "</title>\n"); 00223 } 00224 } 00225 00226 static void svg_end_page(GVJ_t * job) 00227 { 00228 gvputs(job, "</g>\n"); 00229 } 00230 00231 static void svg_begin_cluster(GVJ_t * job) 00232 { 00233 obj_state_t *obj = job->obj; 00234 00235 gvputs(job, "<g id=\""); 00236 gvputs(job, xml_string(obj->id)); 00237 gvputs(job, "\" class=\"cluster\">"); 00238 gvputs(job, "<title>"); 00239 gvputs(job, xml_string(agnameof(obj->u.g))); 00240 gvputs(job, "</title>\n"); 00241 } 00242 00243 static void svg_end_cluster(GVJ_t * job) 00244 { 00245 gvputs(job, "</g>\n"); 00246 } 00247 00248 static void svg_begin_node(GVJ_t * job) 00249 { 00250 obj_state_t *obj = job->obj; 00251 00252 gvputs(job, "<g id=\""); 00253 gvputs(job, xml_string(obj->id)); 00254 gvputs(job, "\" class=\"node\">"); 00255 gvputs(job, "<title>"); 00256 gvputs(job, xml_string(agnameof(obj->u.n))); 00257 gvputs(job, "</title>\n"); 00258 } 00259 00260 static void svg_end_node(GVJ_t * job) 00261 { 00262 gvputs(job, "</g>\n"); 00263 } 00264 00265 static void svg_begin_edge(GVJ_t * job) 00266 { 00267 obj_state_t *obj = job->obj; 00268 char *ename; 00269 00270 gvputs(job, "<g id=\""); 00271 gvputs(job, xml_string(obj->id)); 00272 gvputs(job, "\" class=\"edge\">"); 00273 00274 gvputs(job, "<title>"); 00275 ename = strdup_and_subst_obj("\\E", (void *) (obj->u.e)); 00276 gvputs(job, xml_string(ename)); 00277 free(ename); 00278 gvputs(job, "</title>\n"); 00279 } 00280 00281 static void svg_end_edge(GVJ_t * job) 00282 { 00283 gvputs(job, "</g>\n"); 00284 } 00285 00286 static void 00287 svg_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, 00288 char *id) 00289 { 00290 gvputs(job, "<g"); 00291 if (id) { 00292 gvputs(job, " id=\""); 00293 gvputs(job, xml_string(id)); 00294 gvputs(job, "\""); 00295 } 00296 gvputs(job, ">"); 00297 00298 gvputs(job, "<a"); 00299 #if 0 00300 /* the svg spec implies this can be omitted: http://www.w3.org/TR/SVG/linking.html#Links */ 00301 gvputs(job, " xlink:type=\"simple\""); 00302 #endif 00303 if (href && href[0]) { 00304 gvputs(job, " xlink:href=\""); 00305 gvputs(job, xml_url_string(href)); 00306 gvputs(job, "\""); 00307 } 00308 #if 0 00309 /* linking to itself, just so that it can have a xlink:link in the anchor, seems wrong. 00310 * it changes the behavior in browsers, the link apears in the bottom information bar 00311 */ 00312 else { 00313 assert(id && id[0]); /* there should always be an id available */ 00314 gvputs(job, " xlink:href=\"#"); 00315 gvputs(job, xml_url_string(href)); 00316 gvputs(job, "\""); 00317 } 00318 #endif 00319 if (tooltip && tooltip[0]) { 00320 gvputs(job, " xlink:title=\""); 00321 gvputs(job, xml_string(tooltip)); 00322 gvputs(job, "\""); 00323 } 00324 if (target && target[0]) { 00325 gvputs(job, " target=\""); 00326 gvputs(job, xml_string(target)); 00327 gvputs(job, "\""); 00328 } 00329 gvputs(job, ">\n"); 00330 } 00331 00332 static void svg_end_anchor(GVJ_t * job) 00333 { 00334 gvputs(job, "</a>\n"); 00335 gvputs(job, "</g>\n"); 00336 } 00337 00338 static void svg_textpara(GVJ_t * job, pointf p, textpara_t * para) 00339 { 00340 obj_state_t *obj = job->obj; 00341 PostscriptAlias *pA; 00342 char *family = NULL, *weight = NULL, *stretch = NULL, *style = NULL; 00343 int flags; 00344 00345 gvputs(job, "<text"); 00346 switch (para->just) { 00347 case 'l': 00348 gvputs(job, " text-anchor=\"start\""); 00349 break; 00350 case 'r': 00351 gvputs(job, " text-anchor=\"end\""); 00352 break; 00353 default: 00354 case 'n': 00355 gvputs(job, " text-anchor=\"middle\""); 00356 break; 00357 } 00358 p.y += para->yoffset_centerline; 00359 gvprintf(job, " x=\"%g\" y=\"%g\"", p.x, -p.y); 00360 pA = para->postscript_alias; 00361 if (pA) { 00362 switch (GD_fontnames(job->gvc->g)) { 00363 case PSFONTS: 00364 family = pA->name; 00365 weight = pA->weight; 00366 style = pA->style; 00367 break; 00368 case SVGFONTS: 00369 family = pA->svg_font_family; 00370 weight = pA->svg_font_weight; 00371 style = pA->svg_font_style; 00372 break; 00373 default: 00374 case NATIVEFONTS: 00375 family = pA->family; 00376 weight = pA->weight; 00377 style = pA->style; 00378 break; 00379 } 00380 stretch = pA->stretch; 00381 00382 gvprintf(job, " font-family=\"%s", family); 00383 if (pA->svg_font_family) 00384 gvprintf(job, ",%s", pA->svg_font_family); 00385 gvputs(job, "\""); 00386 if (weight) 00387 gvprintf(job, " font-weight=\"%s\"", weight); 00388 if (stretch) 00389 gvprintf(job, " font-stretch=\"%s\"", stretch); 00390 if (style) 00391 gvprintf(job, " font-style=\"%s\"", style); 00392 } else 00393 gvprintf(job, " font-family=\"%s\"", para->fontname); 00394 if ((para->font) && (flags = para->font->flags)) { 00395 if ((flags & HTML_BF) && !weight) 00396 gvprintf(job, " font-weight=\"bold\""); 00397 if ((flags & HTML_IF) && !style) 00398 gvprintf(job, " font-style=\"italic\""); 00399 if ((flags & HTML_UL)) 00400 gvprintf(job, " text-decoration=\"underline\""); 00401 if ((flags & HTML_SUP)) 00402 gvprintf(job, " baseline-shift=\"super\""); 00403 if ((flags & HTML_SUB)) 00404 gvprintf(job, " baseline-shift=\"sub\""); 00405 } 00406 00407 gvprintf(job, " font-size=\"%.2f\"", para->fontsize); 00408 switch (obj->pencolor.type) { 00409 case COLOR_STRING: 00410 if (strcasecmp(obj->pencolor.u.string, "black")) 00411 gvprintf(job, " fill=\"%s\"", obj->pencolor.u.string); 00412 break; 00413 case RGBA_BYTE: 00414 gvprintf(job, " fill=\"#%02x%02x%02x\"", 00415 obj->pencolor.u.rgba[0], obj->pencolor.u.rgba[1], 00416 obj->pencolor.u.rgba[2]); 00417 break; 00418 default: 00419 assert(0); /* internal error */ 00420 } 00421 gvputs(job, ">"); 00422 gvputs(job, xml_string(para->str)); 00423 gvputs(job, "</text>\n"); 00424 } 00425 00426 static int gradId; 00427 00428 /* svg_gradstyle 00429 * Outputs the SVG statements that define the gradient pattern 00430 */ 00431 static int svg_gradstyle(GVJ_t * job, pointf * A, int n) 00432 { 00433 pointf G[2]; 00434 float angle; 00435 int id = gradId++; 00436 00437 obj_state_t *obj = job->obj; 00438 angle = obj->gradient_angle * M_PI / 180; //angle of gradient line 00439 G[0].x = G[0].y = G[1].x = G[1].y = 0.; 00440 get_gradient_points(A, G, n, angle, 0); //get points on gradient line 00441 00442 gvprintf(job, 00443 "<defs>\n<linearGradient id=\"l_%d\" gradientUnits=\"userSpaceOnUse\" ", id); 00444 gvprintf(job, "x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\" >\n", G[0].x, 00445 G[0].y, G[1].x, G[1].y); 00446 gvputs(job, "<stop offset=\"0\" style=\"stop-color:"); 00447 svg_print_color(job, obj->fillcolor); 00448 gvputs(job, ";stop-opacity:"); 00449 if (obj->fillcolor.type == RGBA_BYTE && obj->fillcolor.u.rgba[3] > 0 00450 && obj->fillcolor.u.rgba[3] < 255) 00451 gvprintf(job, "%f", ((float) obj->fillcolor.u.rgba[3] / 255.0)); 00452 else 00453 gvputs(job, "1."); 00454 gvputs(job, ";\"/>\n"); 00455 gvputs(job, "<stop offset=\"1\" style=\"stop-color:"); 00456 svg_print_color(job, obj->stopcolor); 00457 gvputs(job, ";stop-opacity:"); 00458 if (obj->stopcolor.type == RGBA_BYTE && obj->stopcolor.u.rgba[3] > 0 00459 && obj->stopcolor.u.rgba[3] < 255) 00460 gvprintf(job, "%f", ((float) obj->stopcolor.u.rgba[3] / 255.0)); 00461 else 00462 gvputs(job, "1."); 00463 gvputs(job, ";\"/>\n</linearGradient>\n</defs>\n"); 00464 return id; 00465 } 00466 00467 /* svg_rgradstyle 00468 * Outputs the SVG statements that define the radial gradient pattern 00469 */ 00470 static int svg_rgradstyle(GVJ_t * job, pointf * A, int n) 00471 { 00472 pointf G[2]; 00473 float angle; 00474 int ifx, ify; 00475 int id = gradId++; 00476 00477 obj_state_t *obj = job->obj; 00478 angle = obj->gradient_angle * M_PI / 180; //angle of gradient line 00479 G[0].x = G[0].y = G[1].x = G[1].y; 00480 get_gradient_points(A, G, n, 0, 1); 00481 if (angle == 0.) { 00482 ifx = ify = 50; 00483 } else { 00484 ifx = 50 * (1 + cos(angle)); 00485 ify = 50 * (1 - sin(angle)); 00486 } 00487 gvprintf(job, 00488 "<defs>\n<radialGradient id=\"r_%d\" cx=\"50%%\" cy=\"50%%\" r=\"75%%\" fx=\"%d%%\" fy=\"%d%%\">\n", 00489 id, ifx, ify); 00490 gvputs(job, "<stop offset=\"0\" style=\"stop-color:"); 00491 svg_print_color(job, obj->fillcolor); 00492 gvputs(job, ";stop-opacity:"); 00493 if (obj->fillcolor.type == RGBA_BYTE && obj->fillcolor.u.rgba[3] > 0 00494 && obj->fillcolor.u.rgba[3] < 255) 00495 gvprintf(job, "%f", ((float) obj->fillcolor.u.rgba[3] / 255.0)); 00496 else 00497 gvputs(job, "1."); 00498 gvputs(job, ";\"/>\n"); 00499 gvputs(job, "<stop offset=\"1\" style=\"stop-color:"); 00500 svg_print_color(job, obj->stopcolor); 00501 gvputs(job, ";stop-opacity:"); 00502 if (obj->stopcolor.type == RGBA_BYTE && obj->stopcolor.u.rgba[3] > 0 00503 && obj->stopcolor.u.rgba[3] < 255) 00504 gvprintf(job, "%f", ((float) obj->stopcolor.u.rgba[3] / 255.0)); 00505 else 00506 gvputs(job, "1."); 00507 gvputs(job, ";\"/>\n</radialGradient>\n</defs>\n"); 00508 return id; 00509 } 00510 00511 00512 static void svg_ellipse(GVJ_t * job, pointf * A, int filled) 00513 { 00514 int gid = 0; 00515 00516 /* A[] contains 2 points: the center and corner. */ 00517 if (filled == GRADIENT) { 00518 gid = svg_gradstyle(job, A, 2); 00519 } else if (filled == (RGRADIENT)) { 00520 gid = svg_rgradstyle(job, A, 2); 00521 } 00522 gvputs(job, "<ellipse"); 00523 svg_grstyle(job, filled, gid); 00524 gvprintf(job, " cx=\"%g\" cy=\"%g\"", A[0].x, -A[0].y); 00525 gvprintf(job, " rx=\"%g\" ry=\"%g\"", 00526 A[1].x - A[0].x, A[1].y - A[0].y); 00527 gvputs(job, "/>\n"); 00528 } 00529 00530 static void 00531 svg_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start, 00532 int arrow_at_end, int filled) 00533 { 00534 int gid = 0; 00535 00536 if (filled == GRADIENT) { 00537 gid = svg_gradstyle(job, A, n); 00538 } else if (filled == (RGRADIENT)) { 00539 gid = svg_rgradstyle(job, A, n); 00540 } 00541 gvputs(job, "<path"); 00542 svg_grstyle(job, filled, gid); 00543 gvputs(job, " d=\""); 00544 svg_bzptarray(job, A, n); 00545 gvputs(job, "\"/>\n"); 00546 } 00547 00548 static void svg_polygon(GVJ_t * job, pointf * A, int n, int filled) 00549 { 00550 int i, gid = 0; 00551 if (filled == GRADIENT) { 00552 gid = svg_gradstyle(job, A, n); 00553 } else if (filled == (RGRADIENT)) { 00554 gid = svg_rgradstyle(job, A, n); 00555 } 00556 gvputs(job, "<polygon"); 00557 svg_grstyle(job, filled, gid); 00558 gvputs(job, " points=\""); 00559 for (i = 0; i < n; i++) 00560 gvprintf(job, "%g,%g ", A[i].x, -A[i].y); 00561 gvprintf(job, "%g,%g", A[0].x, -A[0].y); /* because Adobe SVG is broken */ 00562 gvputs(job, "\"/>\n"); 00563 } 00564 00565 static void svg_polyline(GVJ_t * job, pointf * A, int n) 00566 { 00567 int i; 00568 00569 gvputs(job, "<polyline"); 00570 svg_grstyle(job, 0, 0); 00571 gvputs(job, " points=\""); 00572 for (i = 0; i < n; i++) 00573 gvprintf(job, "%g,%g ", A[i].x, -A[i].y); 00574 gvputs(job, "\"/>\n"); 00575 } 00576 00577 /* color names from http://www.w3.org/TR/SVG/types.html */ 00578 /* NB. List must be LANG_C sorted */ 00579 static char *svg_knowncolors[] = { 00580 "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", 00581 "beige", "bisque", "black", "blanchedalmond", "blue", 00582 "blueviolet", "brown", "burlywood", 00583 "cadetblue", "chartreuse", "chocolate", "coral", 00584 "cornflowerblue", "cornsilk", "crimson", "cyan", 00585 "darkblue", "darkcyan", "darkgoldenrod", "darkgray", 00586 "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", 00587 "darkolivegreen", "darkorange", "darkorchid", "darkred", 00588 "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", 00589 "darkslategrey", "darkturquoise", "darkviolet", "deeppink", 00590 "deepskyblue", "dimgray", "dimgrey", "dodgerblue", 00591 "firebrick", "floralwhite", "forestgreen", "fuchsia", 00592 "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", 00593 "green", "greenyellow", "grey", 00594 "honeydew", "hotpink", "indianred", 00595 "indigo", "ivory", "khaki", 00596 "lavender", "lavenderblush", "lawngreen", "lemonchiffon", 00597 "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", 00598 "lightgray", "lightgreen", "lightgrey", "lightpink", 00599 "lightsalmon", "lightseagreen", "lightskyblue", 00600 "lightslategray", "lightslategrey", "lightsteelblue", 00601 "lightyellow", "lime", "limegreen", "linen", 00602 "magenta", "maroon", "mediumaquamarine", "mediumblue", 00603 "mediumorchid", "mediumpurple", "mediumseagreen", 00604 "mediumslateblue", "mediumspringgreen", "mediumturquoise", 00605 "mediumvioletred", "midnightblue", "mintcream", 00606 "mistyrose", "moccasin", 00607 "navajowhite", "navy", "oldlace", 00608 "olive", "olivedrab", "orange", "orangered", "orchid", 00609 "palegoldenrod", "palegreen", "paleturquoise", 00610 "palevioletred", "papayawhip", "peachpuff", "peru", "pink", 00611 "plum", "powderblue", "purple", 00612 "red", "rosybrown", "royalblue", 00613 "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", 00614 "sienna", "silver", "skyblue", "slateblue", "slategray", 00615 "slategrey", "snow", "springgreen", "steelblue", 00616 "tan", "teal", "thistle", "tomato", "turquoise", 00617 "violet", 00618 "wheat", "white", "whitesmoke", 00619 "yellow", "yellowgreen" 00620 }; 00621 00622 gvrender_engine_t svg_engine = { 00623 svg_begin_job, 00624 0, /* svg_end_job */ 00625 svg_begin_graph, 00626 svg_end_graph, 00627 svg_begin_layer, 00628 svg_end_layer, 00629 svg_begin_page, 00630 svg_end_page, 00631 svg_begin_cluster, 00632 svg_end_cluster, 00633 0, /* svg_begin_nodes */ 00634 0, /* svg_end_nodes */ 00635 0, /* svg_begin_edges */ 00636 0, /* svg_end_edges */ 00637 svg_begin_node, 00638 svg_end_node, 00639 svg_begin_edge, 00640 svg_end_edge, 00641 svg_begin_anchor, 00642 svg_end_anchor, 00643 0, /* svg_begin_anchor */ 00644 0, /* svg_end_anchor */ 00645 svg_textpara, 00646 0, /* svg_resolve_color */ 00647 svg_ellipse, 00648 svg_polygon, 00649 svg_bezier, 00650 svg_polyline, 00651 svg_comment, 00652 0, /* svg_library_shape */ 00653 }; 00654 00655 gvrender_features_t render_features_svg = { 00656 GVRENDER_Y_GOES_DOWN | GVRENDER_DOES_TRANSFORM | GVRENDER_DOES_LABELS | GVRENDER_DOES_MAPS | GVRENDER_DOES_TARGETS | GVRENDER_DOES_TOOLTIPS, /* flags */ 00657 4., /* default pad - graph units */ 00658 svg_knowncolors, /* knowncolors */ 00659 sizeof(svg_knowncolors) / sizeof(char *), /* sizeof knowncolors */ 00660 RGBA_BYTE, /* color_type */ 00661 }; 00662 00663 gvdevice_features_t device_features_svg = { 00664 GVDEVICE_DOES_TRUECOLOR, /* flags */ 00665 {0., 0.}, /* default margin - points */ 00666 {0., 0.}, /* default page width, height - points */ 00667 {72., 72.}, /* default dpi */ 00668 }; 00669 00670 gvdevice_features_t device_features_svgz = { 00671 GVDEVICE_BINARY_FORMAT | GVDEVICE_COMPRESSED_FORMAT | GVDEVICE_DOES_TRUECOLOR, /* flags */ 00672 {0., 0.}, /* default margin - points */ 00673 {0., 0.}, /* default page width, height - points */ 00674 {72., 72.}, /* default dpi */ 00675 }; 00676 00677 gvplugin_installed_t gvrender_svg_types[] = { 00678 {FORMAT_SVG, "svg", 1, &svg_engine, &render_features_svg}, 00679 {0, NULL, 0, NULL, NULL} 00680 }; 00681 00682 gvplugin_installed_t gvdevice_svg_types[] = { 00683 {FORMAT_SVG, "svg:svg", 1, NULL, &device_features_svg}, 00684 #if HAVE_LIBZ 00685 {FORMAT_SVGZ, "svgz:svg", 1, NULL, &device_features_svgz}, 00686 #endif 00687 {0, NULL, 0, NULL, NULL} 00688 };
1.7.5