|
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 #ifdef HAVE_CONFIG_H 00015 #include "config.h" 00016 #endif 00017 00018 #include <stdarg.h> 00019 #include <stdlib.h> 00020 #include <string.h> 00021 00022 #include "macros.h" 00023 #include "const.h" 00024 00025 #include "gvplugin_render.h" 00026 #include "gvplugin_device.h" 00027 #include "gvio.h" 00028 #include "memory.h" 00029 00030 typedef enum { FORMAT_VML, FORMAT_VMLZ, } format_type; 00031 00032 unsigned int graphHeight,graphWidth; 00033 00034 #ifndef HAVE_STRCASECMP 00035 extern int strcasecmp(const char *s1, const char *s2); 00036 #endif 00037 00038 /* this is a direct copy fromlib/common/labels.c */ 00039 static int xml_isentity(char *s) 00040 { 00041 s++; /* already known to be '&' */ 00042 if (*s == '#') { 00043 s++; 00044 if (*s == 'x' || *s == 'X') { 00045 s++; 00046 while ((*s >= '0' && *s <= '9') 00047 || (*s >= 'a' && *s <= 'f') 00048 || (*s >= 'A' && *s <= 'F')) 00049 s++; 00050 } else { 00051 while (*s >= '0' && *s <= '9') 00052 s++; 00053 } 00054 } else { 00055 while ((*s >= 'a' && *s <= 'z') 00056 || (*s >= 'A' && *s <= 'Z')) 00057 s++; 00058 } 00059 if (*s == ';') 00060 return 1; 00061 return 0; 00062 } 00063 00064 static void vml_bzptarray(GVJ_t * job, pointf * A, int n) 00065 { 00066 int i; 00067 char *c; 00068 00069 c = "m "; /* first point */ 00070 for (i = 0; i < n; i++) { 00071 /* integers only in path! */ 00072 gvprintf(job, "%s%.0f,%.0f ", c, A[i].x, graphHeight-A[i].y); 00073 if (i == 0) 00074 c = "c "; /* second point */ 00075 else 00076 c = ""; /* remaining points */ 00077 } 00078 gvputs(job, "\""); 00079 } 00080 00081 static void vml_print_color(GVJ_t * job, gvcolor_t color) 00082 { 00083 switch (color.type) { 00084 case COLOR_STRING: 00085 gvputs(job, color.u.string); 00086 break; 00087 case RGBA_BYTE: 00088 if (color.u.rgba[3] == 0) /* transparent */ 00089 gvputs(job, "none"); 00090 else 00091 gvprintf(job, "#%02x%02x%02x", 00092 color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]); 00093 break; 00094 default: 00095 assert(0); /* internal error */ 00096 } 00097 } 00098 00099 static void vml_grstroke(GVJ_t * job, int filled) 00100 { 00101 obj_state_t *obj = job->obj; 00102 00103 gvputs(job, "<v:stroke color=\""); 00104 vml_print_color(job, obj->pencolor); 00105 if (obj->penwidth != PENWIDTH_NORMAL) 00106 gvprintf(job, "\" weight=\"%.0fpt", obj->penwidth); 00107 if (obj->pen == PEN_DASHED) { 00108 gvputs(job, "\" dashstyle=\"dash"); 00109 } else if (obj->pen == PEN_DOTTED) { 00110 gvputs(job, "\" dashstyle=\"dot"); 00111 } 00112 gvputs(job, "\" />"); 00113 } 00114 00115 00116 static void vml_grfill(GVJ_t * job, int filled) 00117 { 00118 obj_state_t *obj = job->obj; 00119 00120 if (filled){ 00121 gvputs(job, " filled=\"true\" fillcolor=\""); 00122 vml_print_color(job, obj->fillcolor); 00123 gvputs(job, "\" "); 00124 }else{ 00125 gvputs(job, " filled=\"false\" "); 00126 } 00127 } 00128 00129 /* html_string is a modified version of xml_string */ 00130 char *html_string(char *s) 00131 { 00132 static char *buf = NULL; 00133 static int bufsize = 0; 00134 char *p, *sub, *prev = NULL; 00135 int len, pos = 0; 00136 int temp,cnt,remaining=0; 00137 char workstr[16]; 00138 long unsigned int charnum=0; 00139 unsigned char byte; 00140 unsigned char mask; 00141 00142 00143 if (!buf) { 00144 bufsize = 64; 00145 buf = gmalloc(bufsize); 00146 } 00147 p = buf; 00148 while (s && *s) { 00149 if (pos > (bufsize - 8)) { 00150 bufsize *= 2; 00151 buf = grealloc(buf, bufsize); 00152 p = buf + pos; 00153 } 00154 /* escape '&' only if not part of a legal entity sequence */ 00155 if (*s == '&' && !(xml_isentity(s))) { 00156 sub = "&"; 00157 len = 5; 00158 } 00159 /* '<' '>' are safe to substitute even if string is already UTF-8 coded 00160 * since UTF-8 strings won't contain '<' or '>' */ 00161 else if (*s == '<') { 00162 sub = "<"; 00163 len = 4; 00164 } 00165 else if (*s == '>') { 00166 sub = ">"; 00167 len = 4; 00168 } 00169 else if (*s == '-') { /* can't be used in xml comment strings */ 00170 sub = "-"; 00171 len = 5; 00172 } 00173 else if (*s == ' ' && prev && *prev == ' ') { 00174 /* substitute 2nd and subsequent spaces with required_spaces */ 00175 sub = " "; /* inkscape doesn't recognise */ 00176 len = 6; 00177 } 00178 else if (*s == '"') { 00179 sub = """; 00180 len = 6; 00181 } 00182 else if (*s == '\'') { 00183 sub = "'"; 00184 len = 5; 00185 } 00186 else if ((unsigned char)*s > 127) { 00187 byte=(unsigned char)*s; 00188 cnt=0; 00189 for (mask=127; mask < byte; mask=mask >>1){ 00190 cnt++; 00191 byte=byte & mask; 00192 } 00193 if (cnt>1){ 00194 charnum=byte; 00195 remaining=cnt-1; 00196 }else{ 00197 charnum=charnum<<6; 00198 charnum+=byte; 00199 remaining--; 00200 } 00201 if (remaining>0){ 00202 s++; 00203 continue; 00204 } 00205 /* we will build the html value right-to-left 00206 * (least significant-to-most) */ 00207 workstr[15]=';'; 00208 sub=&workstr[14]; 00209 len=3; /* &# + ; */ 00210 do { 00211 temp=charnum%10; 00212 *(sub--)=(char)((int)'0'+ temp); 00213 charnum/=10; 00214 len++; 00215 if (len>12){ /* 12 is arbitrary, but clearly in error */ 00216 fprintf(stderr, "Error during conversion to \"UTF-8\". Quiting.\n"); 00217 exit(1); 00218 } 00219 } while (charnum>0); 00220 *(sub--)='#'; 00221 *(sub)='&'; 00222 } 00223 else { 00224 sub = s; 00225 len = 1; 00226 } 00227 while (len--) { 00228 *p++ = *sub++; 00229 pos++; 00230 } 00231 prev = s; 00232 s++; 00233 } 00234 *p = '\0'; 00235 return buf; 00236 } 00237 static void vml_comment(GVJ_t * job, char *str) 00238 { 00239 gvputs(job, " <!-- "); 00240 gvputs(job, html_string(str)); 00241 gvputs(job, " -->\n"); 00242 } 00243 static void vml_begin_job(GVJ_t * job) 00244 { 00245 gvputs(job, "<HTML>\n"); 00246 gvputs(job, "\n<!-- Generated by "); 00247 gvputs(job, html_string(job->common->info[0])); 00248 gvputs(job, " version "); 00249 gvputs(job, html_string(job->common->info[1])); 00250 gvputs(job, " ("); 00251 gvputs(job, html_string(job->common->info[2])); 00252 gvputs(job, ")\n-->\n"); 00253 } 00254 00255 static void vml_begin_graph(GVJ_t * job) 00256 { 00257 obj_state_t *obj = job->obj; 00258 char *name; 00259 00260 graphHeight =(int)(job->bb.UR.y - job->bb.LL.y); 00261 graphWidth =(int)(job->bb.UR.x - job->bb.LL.x); 00262 00263 gvputs(job, "<HEAD>"); 00264 gvputs(job, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"); 00265 00266 00267 #ifndef WITH_CGRAPH 00268 name = obj->u.g->name; 00269 #else 00270 name = agnameof(obj->u.g); 00271 #endif 00272 if (name[0]) { 00273 gvputs(job, "<TITLE>"); 00274 gvputs(job, html_string(name)); 00275 gvputs(job, "</TITLE>"); 00276 } 00277 gvprintf(job, "<!-- Pages: %d -->\n", job->pagesArraySize.x * job->pagesArraySize.y); 00278 00279 /* the next chunk and all the "DIV" stuff is not required, 00280 * but it helps with non-IE browsers */ 00281 gvputs(job, " <SCRIPT LANGUAGE='Javascript'>\n"); 00282 gvputs(job, " function browsercheck()\n"); 00283 gvputs(job, " {\n"); 00284 gvputs(job, " var ua = window.navigator.userAgent\n"); 00285 gvputs(job, " var msie = ua.indexOf ( 'MSIE ' )\n"); 00286 gvputs(job, " var ievers;\n"); 00287 gvputs(job, " var item;\n"); 00288 gvputs(job, " var VMLyes=new Array('_VML1_','_VML2_');\n"); 00289 gvputs(job, " var VMLno=new Array('_notVML1_','_notVML2_');\n"); 00290 gvputs(job, " if ( msie > 0 ){ // If Internet Explorer, return version number\n"); 00291 gvputs(job, " ievers= parseInt (ua.substring (msie+5, ua.indexOf ('.', msie )))\n"); 00292 gvputs(job, " }\n"); 00293 gvputs(job, " if (ievers>=5){\n"); 00294 gvputs(job, " for (x in VMLyes){\n"); 00295 gvputs(job, " item = document.getElementById(VMLyes[x]);\n"); 00296 gvputs(job, " if (item) {\n"); 00297 gvputs(job, " item.style.visibility='visible';\n"); 00298 gvputs(job, " }\n"); 00299 gvputs(job, " }\n"); 00300 gvputs(job, " for (x in VMLno){\n"); 00301 gvputs(job, " item = document.getElementById(VMLno[x]);\n"); 00302 gvputs(job, " if (item) {\n"); 00303 gvputs(job, " item.style.visibility='hidden';\n"); 00304 gvputs(job, " }\n"); 00305 gvputs(job, " }\n"); 00306 gvputs(job, " }else{\n"); 00307 gvputs(job, " for (x in VMLyes){\n"); 00308 gvputs(job, " item = document.getElementById(VMLyes[x]);\n"); 00309 gvputs(job, " if (item) {\n"); 00310 gvputs(job, " item.style.visibility='hidden';\n"); 00311 gvputs(job, " }\n"); 00312 gvputs(job, " }\n"); 00313 gvputs(job, " for (x in VMLno){\n"); 00314 gvputs(job, " item = document.getElementById(VMLno[x]);\n"); 00315 gvputs(job, " if (item) {\n"); 00316 gvputs(job, " item.style.visibility='visible';\n"); 00317 gvputs(job, " }\n"); 00318 gvputs(job, " }\n"); 00319 gvputs(job, " }\n"); 00320 gvputs(job, " }\n"); 00321 gvputs(job, " </SCRIPT>\n"); 00322 00323 gvputs(job, "</HEAD>"); 00324 gvputs(job, "<BODY onload='browsercheck();'>\n"); 00325 /* add 10pt pad to the bottom of the graph */ 00326 gvputs(job, "<DIV id='_VML1_' style=\"position:relative; display:inline; visibility:hidden"); 00327 gvprintf(job, " width: %dpt; height: %dpt\">\n", graphWidth, 10+graphHeight); 00328 gvputs(job, "<STYLE>\n"); 00329 gvputs(job, "v\\:* { behavior: url(#default#VML);display:inline-block}\n"); 00330 gvputs(job, "</STYLE>\n"); 00331 gvputs(job, "<xml:namespace ns=\"urn:schemas-microsoft-com:vml\" prefix=\"v\" />\n"); 00332 00333 gvputs(job, " <v:group style=\"position:relative; "); 00334 gvprintf(job, " width: %dpt; height: %dpt\"", graphWidth, graphHeight); 00335 gvprintf(job, " coordorigin=\"0,0\" coordsize=\"%d,%d\" >", graphWidth, graphHeight); 00336 } 00337 00338 static void vml_end_graph(GVJ_t * job) 00339 { 00340 gvputs(job, "</v:group>\n"); 00341 gvputs(job, "</DIV>\n"); 00342 /* add 10pt pad to the bottom of the graph */ 00343 gvputs(job, "<DIV id='_VML2_' style=\"position:relative;visibility:hidden\">\n"); 00344 gvputs(job, "<!-- insert any other html content here -->\n"); 00345 gvputs(job, "</DIV>\n"); 00346 gvputs(job, "<DIV id='_notVML1_' style=\"position:relative;\">\n"); 00347 gvputs(job, "<!-- this should only display on NON-IE browsers -->\n"); 00348 gvputs(job, "<H2>Sorry, this diagram will only display correctly on Internet Explorer 5 (and up) browsers.</H2>\n"); 00349 gvputs(job, "</DIV>\n"); 00350 gvputs(job, "<DIV id='_notVML2_' style=\"position:relative;\">\n"); 00351 gvputs(job, "<!-- insert any other NON-IE html content here -->\n"); 00352 gvputs(job, "</DIV>\n"); 00353 00354 gvputs(job, "</BODY>\n</HTML>\n"); 00355 } 00356 00357 static void 00358 vml_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, char *id) 00359 { 00360 gvputs(job, "<a"); 00361 if (href && href[0]) 00362 gvprintf(job, " href=\"%s\"", html_string(href)); 00363 if (tooltip && tooltip[0]) 00364 gvprintf(job, " title=\"%s\"", html_string(tooltip)); 00365 if (target && target[0]) 00366 gvprintf(job, " target=\"%s\"", html_string(target)); 00367 gvputs(job, ">\n"); 00368 } 00369 00370 static void vml_end_anchor(GVJ_t * job) 00371 { 00372 gvputs(job, "</a>\n"); 00373 } 00374 00375 static void vml_textpara(GVJ_t * job, pointf p, textpara_t * para) 00376 { 00377 pointf p1,p2; 00378 obj_state_t *obj = job->obj; 00379 00380 switch (para->just) { 00381 case 'l': 00382 p1.x=p.x; 00383 break; 00384 case 'r': 00385 p1.x=p.x-para->width; 00386 break; 00387 default: 00388 case 'n': 00389 p1.x=p.x-(para->width/2); 00390 break; 00391 } 00392 p2.x=p1.x+para->width; 00393 if (para->height < para->fontsize){ 00394 para->height = 1 + (1.1*para->fontsize); 00395 } 00396 00397 p1.x-=8; /* vml textbox margin fudge factor */ 00398 p2.x+=8; /* vml textbox margin fudge factor */ 00399 p2.y=graphHeight-(p.y); 00400 p1.y=(p2.y-para->height); 00401 /* text "y" was too high 00402 * Graphviz uses "baseline", VML seems to use bottom of descenders - so we fudge a little 00403 * (heuristics - based on eyeballs) */ 00404 if (para->fontsize <12.){ /* see graphs/directed/arrows.gv */ 00405 p1.y+=1.4+para->fontsize/5; /* adjust by approx. descender */ 00406 p2.y+=1.4+para->fontsize/5; /* adjust by approx. descender */ 00407 }else{ 00408 p1.y+=2+para->fontsize/5; /* adjust by approx. descender */ 00409 p2.y+=2+para->fontsize/5; /* adjust by approx. descender */ 00410 } 00411 00412 gvprintf(job, "<v:rect style=\"position:absolute; "); 00413 gvprintf(job, " left: %.2f; top: %.2f;", p1.x, p1.y); 00414 gvprintf(job, " width: %.2f; height: %.2f\"", p2.x-p1.x, p2.y-p1.y); 00415 gvputs(job, " stroked=\"false\" filled=\"false\">\n"); 00416 gvputs(job, "<v:textbox inset=\"0,0,0,0\" style=\"position:absolute; v-text-wrapping:'false';padding:'0';"); 00417 00418 if (para->postscript_alias) { 00419 gvprintf(job, "font-family: '%s';", para->postscript_alias->family); 00420 if (para->postscript_alias->weight) 00421 gvprintf(job, "font-weight: %s;", para->postscript_alias->weight); 00422 if (para->postscript_alias->stretch) 00423 gvprintf(job, "font-stretch: %s;", para->postscript_alias->stretch); 00424 if (para->postscript_alias->style) 00425 gvprintf(job, "font-style: %s;", para->postscript_alias->style); 00426 } 00427 else { 00428 gvprintf(job, "font-family: \'%s\';", para->fontname); 00429 } 00430 gvprintf(job, " font-size: %.2fpt;", para->fontsize); 00431 switch (obj->pencolor.type) { 00432 case COLOR_STRING: 00433 if (strcasecmp(obj->pencolor.u.string, "black")) 00434 gvprintf(job, "color:%s;", obj->pencolor.u.string); 00435 break; 00436 case RGBA_BYTE: 00437 gvprintf(job, "color:#%02x%02x%02x;", 00438 obj->pencolor.u.rgba[0], obj->pencolor.u.rgba[1], obj->pencolor.u.rgba[2]); 00439 break; 00440 default: 00441 assert(0); /* internal error */ 00442 } 00443 gvputs(job, "\"><center>"); 00444 gvputs(job, html_string(para->str)); 00445 gvputs(job, "</center></v:textbox>\n"); 00446 gvputs(job, "</v:rect>\n"); 00447 } 00448 00449 static void vml_ellipse(GVJ_t * job, pointf * A, int filled) 00450 { 00451 double dx, dy, left, right, top, bottom; 00452 00453 /* A[] contains 2 points: the center and corner. */ 00454 gvputs(job, " <v:oval style=\"position:absolute;"); 00455 00456 dx=A[1].x-A[0].x; 00457 dy=A[1].y-A[0].y; 00458 00459 top=graphHeight-(A[0].y+dy); 00460 bottom=top+dy+dy; 00461 left=A[0].x - dx; 00462 right=A[1].x; 00463 gvprintf(job, " left: %.2f; top: %.2f;",left, top); 00464 gvprintf(job, " width: %.2f; height: %.2f\"", 2*dx, 2*dy); 00465 00466 vml_grfill(job, filled); 00467 gvputs(job, " >"); 00468 vml_grstroke(job, filled); 00469 gvputs(job, "</v:oval>\n"); 00470 } 00471 00472 static void 00473 vml_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start, 00474 int arrow_at_end, int filled) 00475 { 00476 gvputs(job, " <v:shape style=\"position:absolute; "); 00477 gvprintf(job, " width: %d; height: %d\"", graphWidth, graphHeight); 00478 00479 vml_grfill(job, filled); 00480 gvputs(job, " >"); 00481 vml_grstroke(job, filled); 00482 gvputs(job, "<v:path v=\""); 00483 vml_bzptarray(job, A, n); 00484 gvputs(job, "/></v:shape>\n"); 00485 } 00486 00487 static void vml_polygon(GVJ_t * job, pointf * A, int n, int filled) 00488 { 00489 int i; 00490 double px,py; 00491 00492 gvputs(job, " <v:shape style=\"position:absolute; "); 00493 gvprintf(job, " width: %d; height: %d\"", graphWidth, graphHeight); 00494 vml_grfill(job, filled); 00495 gvputs(job, " >"); 00496 vml_grstroke(job, filled); 00497 00498 gvputs(job, "<v:path v=\""); 00499 for (i = 0; i < n; i++) 00500 { 00501 px=A[i].x; 00502 py= (graphHeight-A[i].y); 00503 if (i==0){ 00504 gvputs(job, "m "); 00505 } 00506 /* integers only in path */ 00507 gvprintf(job, "%.0f %.0f ", px, py); 00508 if (i==0) gvputs(job, "l "); 00509 if (i==n-1) gvputs(job, "x e \"/>"); 00510 } 00511 gvputs(job, "</v:shape>\n"); 00512 } 00513 00514 static void vml_polyline(GVJ_t * job, pointf * A, int n) 00515 { 00516 int i; 00517 00518 gvputs(job, " <v:shape style=\"position:absolute; "); 00519 gvprintf(job, " width: %d; height: %d\" filled=\"false\">", graphWidth, graphHeight); 00520 gvputs(job, "<v:path v=\""); 00521 for (i = 0; i < n; i++) 00522 { 00523 if (i==0) gvputs(job, " m "); 00524 gvprintf(job, "%.0f,%.0f ", A[i].x, graphHeight-A[i].y); 00525 if (i==0) gvputs(job, " l "); 00526 if (i==n-1) gvputs(job, " e "); /* no x here for polyline */ 00527 } 00528 gvputs(job, "\"/>"); 00529 vml_grstroke(job, 0); /* no fill here for polyline */ 00530 gvputs(job, "</v:shape>\n"); 00531 } 00532 00533 /* color names from 00534 http://msdn.microsoft.com/en-us/library/bb250525(VS.85).aspx#t.color 00535 */ 00536 /* NB. List must be LANG_C sorted */ 00537 static char *vml_knowncolors[] = { 00538 "aqua", "black", "blue", "fuchsia", 00539 "gray", "green", "lime", "maroon", 00540 "navy", "olive", "purple", "red", 00541 "silver", "teal", "white", "yellow" 00542 }; 00543 00544 gvrender_engine_t vml_engine = { 00545 vml_begin_job, 00546 0, /* vml_end_job */ 00547 vml_begin_graph, 00548 vml_end_graph, 00549 0, /* vml_begin_layer */ 00550 0, /* vml_end_layer */ 00551 0, /* vml_begin_page */ 00552 0, /* vml_end_page */ 00553 0, /* vml_begin_cluster */ 00554 0, /* vml_end_cluster */ 00555 0, /* vml_begin_nodes */ 00556 0, /* vml_end_nodes */ 00557 0, /* vml_begin_edges */ 00558 0, /* vml_end_edges */ 00559 0, /* vml_begin_node */ 00560 0, /* vml_end_node */ 00561 0, /* vml_begin_edge */ 00562 0, /* vml_end_edge */ 00563 vml_begin_anchor, 00564 vml_end_anchor, 00565 0, /* vml_begin_label */ 00566 0, /* vml_end_label */ 00567 vml_textpara, 00568 0, /* vml_resolve_color */ 00569 vml_ellipse, 00570 vml_polygon, 00571 vml_bezier, 00572 vml_polyline, 00573 vml_comment, 00574 0, /* vml_library_shape */ 00575 }; 00576 00577 gvrender_features_t render_features_vml = { 00578 GVRENDER_Y_GOES_DOWN 00579 | GVRENDER_DOES_TRANSFORM 00580 | GVRENDER_DOES_LABELS 00581 | GVRENDER_DOES_MAPS 00582 | GVRENDER_DOES_TARGETS 00583 | GVRENDER_DOES_TOOLTIPS, /* flags */ 00584 0., /* default pad - graph units */ 00585 vml_knowncolors, /* knowncolors */ 00586 sizeof(vml_knowncolors) / sizeof(char *), /* sizeof knowncolors */ 00587 RGBA_BYTE, /* color_type */ 00588 }; 00589 00590 gvdevice_features_t device_features_vml = { 00591 GVDEVICE_DOES_TRUECOLOR, /* flags */ 00592 {0.,0.}, /* default margin - points */ 00593 {0.,0.}, /* default page width, height - points */ 00594 {96.,96.}, /* default dpi */ 00595 }; 00596 00597 gvdevice_features_t device_features_vmlz = { 00598 GVDEVICE_DOES_TRUECOLOR 00599 | GVDEVICE_COMPRESSED_FORMAT, /* flags */ 00600 {0.,0.}, /* default margin - points */ 00601 {0.,0.}, /* default page width, height - points */ 00602 {96.,96.}, /* default dpi */ 00603 }; 00604 00605 gvplugin_installed_t gvrender_vml_types[] = { 00606 {FORMAT_VML, "vml", 1, &vml_engine, &render_features_vml}, 00607 {0, NULL, 0, NULL, NULL} 00608 }; 00609 00610 gvplugin_installed_t gvdevice_vml_types[] = { 00611 {FORMAT_VML, "vml:vml", 1, NULL, &device_features_vml}, 00612 #if HAVE_LIBZ 00613 {FORMAT_VMLZ, "vmlz:vml", 1, NULL, &device_features_vmlz}, 00614 #endif 00615 {0, NULL, 0, NULL, NULL} 00616 }; 00617
1.7.5