| 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 <stdio.h> | 
| 17 | #include <stdlib.h> | 
| 18 | #include <string.h> | 
| 19 | #include <ctype.h> | 
| 20 |  | 
| 21 | /* FIXME - the following declaration should be removed | 
| 22 |  * when configure is coordinated with flags passed to the | 
| 23 |  * compiler. On Linux, strcasestr is defined but needs a special | 
| 24 |  * preprocessor constant to be defined. Configure sets the | 
| 25 |  * HAVE_STRCASESTR, but the flag is not used during compilation, | 
| 26 |  * so strcasestr is undeclared. | 
| 27 |  */ | 
| 28 | char* strcasestr (const char *str, const char *pat); | 
| 29 | #ifndef HAVE_STRCASESTR | 
| 30 | char* strcasestr (const char *str, const char *pat) | 
| 31 | { | 
| 32 |     int slen, plen; | 
| 33 |     char p0, pc; | 
| 34 |     const char *endp, *sp, *pp; | 
| 35 |     if (!(p0 = *pat)) return (char*)str; | 
| 36 |     plen = strlen (pat++); | 
| 37 |     slen = strlen (str); | 
| 38 |     if (slen < plen) return NULL; | 
| 39 |     endp = str + slen - plen; | 
| 40 |     p0 = toupper (p0); | 
| 41 |     do { | 
| 42 |         while ((str <= endp) && (p0 != toupper(*str))) str++; | 
| 43 |         if (str > endp) return NULL; | 
| 44 |         pp = pat; | 
| 45 |         sp = ++str; | 
| 46 |         while ((pc = *pp++) && (toupper(pc) == toupper(*sp))) sp++; | 
| 47 |     } while (pc); | 
| 48 |     return (char*)(str-1); | 
| 49 | } | 
| 50 |  | 
| 51 | #endif | 
| 52 |  | 
| 53 | #include "agxbuf.h" | 
| 54 | #include "gvplugin_textlayout.h" | 
| 55 | #include <pango/pangocairo.h> | 
| 56 | #include "gvgetfontlist.h" | 
| 57 |  | 
| 58 | extern unsigned char Verbose; | 
| 59 |  | 
| 60 | #define FNT_BOLD	1<<0 | 
| 61 | #define FNT_BOOK	1<<1 | 
| 62 | #define FNT_CONDENSED	1<<2 | 
| 63 | #define FNT_DEMI	1<<3 | 
| 64 | #define 	1<<4 | 
| 65 | #define FNT_ITALIC	1<<5 | 
| 66 | #define FNT_LIGHT	1<<6 | 
| 67 | #define FNT_MEDIUM	1<<7 | 
| 68 | #define FNT_OBLIQUE	1<<8 | 
| 69 | #define FNT_REGULAR	1<<9 | 
| 70 | #define FNT_ROMAN	1<<9 | 
| 71 |  | 
| 72 | #define PS_AVANTGARDE "AvantGarde" | 
| 73 | #define PS_BOOKMAN "Bookman" | 
| 74 | #define PS_COURIER "Courier" | 
| 75 | #define PS_HELVETICA SAN_5 | 
| 76 | #define PS_NEWCENTURYSCHLBK "NewCenturySchlbk" | 
| 77 | #define PS_PALATINO "Palatino" | 
| 78 | #define PS_SYMBOL "Symbol" | 
| 79 | #define PS_TIMES SER_3 | 
| 80 | #define PS_CHANCERY "ZapfChancery" | 
| 81 | #define PS_DINGBATS "ZapfDingbats" | 
| 82 |  | 
| 83 | #define FNT_BOLD_ST	"BOLD" | 
| 84 | #define FNT_BOOK_ST	"BOOK" | 
| 85 | #define FNT_CONDENSED_ST	"CONDENSED" | 
| 86 | #define FNT_DEMI_ST	"DEMI" | 
| 87 | #define 	"EXTRALIGHT" | 
| 88 | #define FNT_ITALIC_ST	"ITALIC" | 
| 89 | #define FNT_LIGHT_ST	"LIGHT" | 
| 90 | #define FNT_MEDIUM_ST	"MEDIUM" | 
| 91 | #define FNT_OBLIQUE_ST	"OBLIQUE" | 
| 92 | #define FNT_REGULAR_ST	"REGULAR" | 
| 93 | #define FNT_ROMAN_ST	"ROMAN" | 
| 94 |  | 
| 95 | #define SAN_0		"sans" | 
| 96 | #define SAN_1		"URW Gothic L" | 
| 97 | #define SAN_2		"Charcoal" | 
| 98 | #define SAN_3		"Nimbus Sans L" | 
| 99 | #define SAN_4		"Verdana" | 
| 100 | #define SAN_5		"Helvetica" | 
| 101 | #define SAN_6		"Bitstream Vera Sans" | 
| 102 | #define SAN_7		"DejaVu Sans" | 
| 103 | #define SAN_8		"Liberation Sans" | 
| 104 | #define SAN_9		"Luxi Sans" | 
| 105 | #define SAN_10		"FreeSans" | 
| 106 | #define SAN_11		"Arial" | 
| 107 |  | 
| 108 | #define SER_0		"serif" | 
| 109 | #define SER_1		"URW Bookman L" | 
| 110 | #define SER_2		"Times New Roman" | 
| 111 | #define SER_3		"Times" | 
| 112 | #define SER_4		"Nimbus Roman No9 L" | 
| 113 | #define SER_5		"Bitstream Vera Serif" | 
| 114 | #define SER_6		"DejaVu Serif" | 
| 115 | #define SER_7		"Liberation Serif" | 
| 116 | #define SER_8		"Luxi Serif" | 
| 117 | #define SER_9		"FreeSerif" | 
| 118 | #define SER_10		"Century Schoolbook L" | 
| 119 | #define SER_11		"Charcoal" | 
| 120 | #define SER_12		"Georgia" | 
| 121 | #define SER_13		"URW Palladio L" | 
| 122 | #define SER_14		"Norasi" | 
| 123 | #define SER_15		"Rekha" | 
| 124 | #define SER_16		"URW Chancery L" | 
| 125 |  | 
| 126 | #define MON_0		"monospace" | 
| 127 | #define MON_1		"Nimbus Mono L" | 
| 128 | #define MON_2		"Inconsolata" | 
| 129 | #define MON_3		"Courier New" | 
| 130 | #define MON_4		"Bitstream Vera Sans Mono" | 
| 131 | #define MON_5		"DejaVu Sans Mono" | 
| 132 | #define MON_6		"Liberation Mono" | 
| 133 | #define MON_7		"Luxi Mono" | 
| 134 | #define MON_8		"FreeMono" | 
| 135 |  | 
| 136 | #define SYM_0		"fantasy" | 
| 137 | #define SYM_1		"Impact" | 
| 138 | #define SYM_2		"Copperplate Gothic Std" | 
| 139 | #define SYM_3		"Cooper Std" | 
| 140 | #define SYM_4		"Bauhaus Std" | 
| 141 |  | 
| 142 | #define DING_0		"fantasy" | 
| 143 | #define DING_1		"Dingbats" | 
| 144 | #define DING_2		"Impact" | 
| 145 | #define DING_3		"Copperplate Gothic Std" | 
| 146 | #define DING_4		"Cooper Std" | 
| 147 | #define DING_5		"Bauhaus Std" | 
| 148 |  | 
| 149 |  | 
| 150 | typedef struct { | 
| 151 |     int flag; | 
| 152 |     char* name; | 
| 153 | } face_t; | 
| 154 | static face_t facelist[] = { | 
| 155 |     { FNT_BOLD, FNT_BOLD_ST}, | 
| 156 |     { FNT_BOOK, FNT_BOOK_ST}, | 
| 157 |     { FNT_CONDENSED, FNT_CONDENSED_ST}, | 
| 158 |     { FNT_DEMI, FNT_DEMI_ST}, | 
| 159 |     { FNT_EXTRALIGHT, FNT_EXTRALIGHT_ST}, | 
| 160 |     { FNT_ITALIC, FNT_ITALIC_ST}, | 
| 161 |     { FNT_LIGHT, FNT_LIGHT_ST}, | 
| 162 |     { FNT_MEDIUM, FNT_MEDIUM_ST}, | 
| 163 |     { FNT_OBLIQUE, FNT_OBLIQUE_ST}, | 
| 164 |     { FNT_REGULAR, FNT_REGULAR_ST}, | 
| 165 |     { FNT_ROMAN, FNT_ROMAN_ST}, | 
| 166 | }; | 
| 167 | #define FACELIST_SZ (sizeof(facelist)/sizeof(face_t)) | 
| 168 |  | 
| 169 | /* This is where the hierarchy of equivalent fonts is established. The order can be changed | 
| 170 |    here or new equivalent fonts can be added here. Each font family used by the Graphviz | 
| 171 |    PS fonts is set up. | 
| 172 | */ | 
| 173 | static const char *PS_AVANT_E[] = { | 
| 174 |     SAN_1, SAN_2, SAN_3, SAN_4, SAN_5, SAN_6, SAN_7, SAN_8, SAN_9, SAN_10 | 
| 175 | }; | 
| 176 | #define PS_AVANT_E_SZ  (sizeof(PS_AVANT_E) / sizeof(char *)) | 
| 177 |  | 
| 178 | static const char *PS_BOOKMAN_E[] = { | 
| 179 |     SER_1, SER_2, SER_3, SER_4, SER_5, SER_6, SER_7, SER_8, SER_9 | 
| 180 | }; | 
| 181 | #define PS_BOOKMAN_E_SZ (sizeof(PS_BOOKMAN_E) / sizeof(char *)) | 
| 182 |  | 
| 183 | static const char *PS_COURIER_E[] = { | 
| 184 |     MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8 | 
| 185 | }; | 
| 186 | #define PS_COURIER_E_SZ (sizeof(PS_COURIER_E) / sizeof(char *)) | 
| 187 |  | 
| 188 | static const char *PS_HELVETICA_E[] = { | 
| 189 |     SAN_3, SAN_11, SAN_4, SAN_6, SAN_7, SAN_8, SAN_9, SAN_10 | 
| 190 | }; | 
| 191 | #define PS_HELVETICA_E_SZ (sizeof(PS_HELVETICA_E) / sizeof(char *)) | 
| 192 |  | 
| 193 | static const char *PS_NEWCENT_E[] = { | 
| 194 |     SER_10, SER_2, SER_3, SER_4, SER_12, SER_5, SER_6, SER_7, SER_8, SER_9 | 
| 195 | }; | 
| 196 | #define PS_NEWCENT_E_SZ (sizeof(PS_NEWCENT_E) / sizeof(char *)) | 
| 197 |  | 
| 198 | static const char *PS_PALATINO_E[] = { | 
| 199 |     SER_13, SER_2, SER_3, SER_4, SER_14, SER_15, SER_5, SER_6, SER_7, SER_8, SER_9 | 
| 200 | }; | 
| 201 | #define PS_PALATINO_E_SZ (sizeof(PS_PALATINO_E) / sizeof(char *)) | 
| 202 |  | 
| 203 | static const char *PS_TIMES_E[] = { | 
| 204 |     SER_4, SER_2, SER_11, SER_5, SER_6, SER_7, SER_8, SER_9 | 
| 205 | }; | 
| 206 | #define PS_TIMES_E_SZ (sizeof(PS_TIMES_E) / sizeof(char *)) | 
| 207 |  | 
| 208 | static const char *PS_SYMBOL_E[] = { SYM_1, SYM_2, SYM_3, SYM_4 }; | 
| 209 | #define PS_SYMBOL_E_SZ (sizeof(PS_SYMBOL_E) / sizeof(char *)) | 
| 210 |  | 
| 211 | static const char *PS_CHANCERY_E[] = { | 
| 212 |     SER_16, SER_11, SER_2, SER_3, SER_4, SER_5, SER_6, SER_7, SER_8, SER_9 | 
| 213 | }; | 
| 214 | #define PS_CHANCERY_E_SZ (sizeof(PS_CHANCERY_E) / sizeof(char *)) | 
| 215 |  | 
| 216 | static const char *PS_DINGBATS_E[] = { DING_1, SYM_1, SYM_2, SYM_3, SYM_4 }; | 
| 217 | #define PS_DINGBATS_E_SZ (sizeof(PS_DINGBATS_E) / sizeof(char *)) | 
| 218 |  | 
| 219 | typedef struct { | 
| 220 |     char *generic_name; | 
| 221 |     char *fontname; | 
| 222 |     int eq_sz; | 
| 223 |     const char **equiv; | 
| 224 | } fontdef_t; | 
| 225 |  | 
| 226 | /* array of recognized Graphviz PS font names */ | 
| 227 | static fontdef_t gv_ps_fontdefs[] = { | 
| 228 |   { SAN_0, PS_AVANTGARDE, PS_AVANT_E_SZ, PS_AVANT_E}, | 
| 229 |   { SER_0, PS_BOOKMAN, PS_BOOKMAN_E_SZ, PS_BOOKMAN_E}, | 
| 230 |   { MON_0, PS_COURIER, PS_COURIER_E_SZ, PS_COURIER_E}, | 
| 231 |   { SAN_0, PS_HELVETICA, PS_HELVETICA_E_SZ, PS_HELVETICA_E}, | 
| 232 |   { SER_0, PS_NEWCENTURYSCHLBK, PS_NEWCENT_E_SZ, PS_NEWCENT_E}, | 
| 233 |   { SER_0, PS_PALATINO, PS_PALATINO_E_SZ, PS_PALATINO_E}, | 
| 234 |   { SYM_0, PS_SYMBOL, PS_SYMBOL_E_SZ, PS_SYMBOL_E}, | 
| 235 |   { SER_0, PS_TIMES, PS_TIMES_E_SZ, PS_TIMES_E}, | 
| 236 |   { SER_0, PS_CHANCERY, PS_CHANCERY_E_SZ, PS_CHANCERY_E}, | 
| 237 |   { DING_0, PS_DINGBATS, PS_DINGBATS_E_SZ, PS_DINGBATS_E}, | 
| 238 | }; | 
| 239 | #define GV_FONT_LIST_SIZE (sizeof(gv_ps_fontdefs)/sizeof(fontdef_t)) | 
| 240 |  | 
| 241 | typedef struct { | 
| 242 |     char *gv_ps_fontname; | 
| 243 |     char *fontname; | 
| 244 |     int faces; | 
| 245 | } availfont_t; | 
| 246 |  | 
| 247 | #define NEW(t)          (t*)malloc(sizeof(t)) | 
| 248 | #define N_NEW(n,t)      (t*)malloc((n)*sizeof(t)) | 
| 249 |  | 
| 250 | static PostscriptAlias postscript_alias[] = { | 
| 251 | #include "ps_font_equiv.h" | 
| 252 | }; | 
| 253 |  | 
| 254 | /* Frees memory used by the available system font definitions */ | 
| 255 | static void gv_flist_free_af(availfont_t* gv_af_p) | 
| 256 | { | 
| 257 |     int i; | 
| 258 |  | 
| 259 |     for (i = 0; i < GV_FONT_LIST_SIZE; i++) { | 
| 260 | 	if (gv_af_p[i].fontname) | 
| 261 | 	    free(gv_af_p[i].fontname); | 
| 262 |     } | 
| 263 |     free(gv_af_p); | 
| 264 | } | 
| 265 |  | 
| 266 | static int get_faces(PangoFontFamily * family) | 
| 267 | { | 
| 268 |     PangoFontFace **faces; | 
| 269 |     PangoFontFace *face; | 
| 270 |     int i, j, n_faces; | 
| 271 |     const char *name; | 
| 272 |     int availfaces = 0; | 
| 273 |     /* Get the faces (Bold, Italic, etc.) for the current font family */ | 
| 274 |     pango_font_family_list_faces(family, &faces, &n_faces); | 
| 275 |     for (i = 0; i < n_faces; i++) { | 
| 276 | 	face = faces[i]; | 
| 277 | 	name = pango_font_face_get_face_name(face); | 
| 278 |  | 
| 279 | 	/* if the family face type is one of the known types, logically OR the known type value | 
| 280 | 	   to the available faces integer */ | 
| 281 | 	for (j = 0; j < FACELIST_SZ; j++) { | 
| 282 | 	    if (strcasestr(name, facelist[j].name)) { | 
| 283 | 		availfaces |= facelist[j].flag; | 
| 284 | 		break; | 
| 285 | 	    } | 
| 286 | 	} | 
| 287 |     } | 
| 288 |     g_free(faces); | 
| 289 |     return availfaces; | 
| 290 | } | 
| 291 |  | 
| 292 | #ifdef DEBUG | 
| 293 | static void | 
| 294 | display_available_fonts(availfont_t* gv_af_p) | 
| 295 | { | 
| 296 |     int i, j, faces; | 
| 297 |  | 
| 298 | /* Displays the Graphviz PS font name, system available font name and associated faces */ | 
| 299 |     for (j = 0; j < GV_FONT_LIST_SIZE; j++) { | 
| 300 | 	if ((gv_af_p[j].faces == 0) || (gv_af_p[j].fontname == NULL)) { | 
| 301 | 	    fprintf (stderr, "ps font = %s not available\n" , gv_ps_fontdefs[j].fontname); | 
| 302 | 	    continue; | 
| 303 | 	} | 
| 304 | 	fprintf (stderr, "ps font = %s available %d font = %s\n" , | 
| 305 | 	    gv_ps_fontdefs[j].fontname, gv_af_p[j].faces, gv_af_p[j].fontname); | 
| 306 | 	faces = gv_af_p[j].faces; | 
| 307 | 	for (i = 0; i < FACELIST_SZ; i++) { | 
| 308 | 	    if (faces & facelist[i].flag) | 
| 309 | 		fprintf (stderr, "\t%s\n" , facelist[i].name); | 
| 310 | 	} | 
| 311 |     } | 
| 312 | } | 
| 313 | #endif | 
| 314 |  | 
| 315 | /* Construct the list of font faces */ | 
| 316 | static char *get_avail_faces(int faces, agxbuf* xb) | 
| 317 | { | 
| 318 |     int i; | 
| 319 |     for (i = 0; i < FACELIST_SZ; i++) { | 
| 320 | 	if (faces & facelist[i].flag) { | 
| 321 | 	    agxbput (xb, facelist[i].name); | 
| 322 | 	    agxbputc(xb, ' '); | 
| 323 | 	} | 
| 324 |     } | 
| 325 |     return agxbuse (xb); | 
| 326 | } | 
| 327 |  | 
| 328 |  | 
| 329 | /* This function creates an array of font definitions. Each entry corresponds to one of | 
| 330 |    the Graphviz PS fonts.  The font definitions contain the generic font name and a list | 
| 331 |    of equivalent fonts that can be used in place of the PS font if the PS font is not | 
| 332 |    available on the system | 
| 333 | */ | 
| 334 | static availfont_t *gv_get_ps_fontlist(PangoFontMap * fontmap) | 
| 335 | { | 
| 336 |     PangoFontFamily **families; | 
| 337 |     PangoFontFamily *family; | 
| 338 |     fontdef_t* gv_ps_fontdef; | 
| 339 |     int n_families; | 
| 340 |     int i, j, k, array_sz, availfaces; | 
| 341 |     availfont_t *gv_af_p, *gv_afs; | 
| 342 |     const char *name; | 
| 343 |     char *family_name; | 
| 344 |  | 
| 345 |     /* Get a list of font families installed on the system */ | 
| 346 |     pango_font_map_list_families(fontmap, &families, &n_families); | 
| 347 |  | 
| 348 |     /* Setup a pointer to available font structs */ | 
| 349 |     gv_af_p = N_NEW(GV_FONT_LIST_SIZE, availfont_t); | 
| 350 |  | 
| 351 |     for (j = 0; j < GV_FONT_LIST_SIZE; j++) { | 
| 352 | 	/* get the Graphviz PS font information and create the | 
| 353 | 	   available font definition structs */ | 
| 354 | 	gv_afs = gv_af_p+j; | 
| 355 | 	gv_ps_fontdef = gv_ps_fontdefs+j; | 
| 356 | 	gv_afs->gv_ps_fontname = gv_ps_fontdef->fontname; | 
| 357 | 	family_name = NULL; | 
| 358 | 	/* Search the installed system font families for the current | 
| 359 | 	   Graphvis PS font family name, i.e. AvantGarde */ | 
| 360 | 	for (i = 0; i < n_families; i++) { | 
| 361 | 	    family = families[i]; | 
| 362 | 	    name = pango_font_family_get_name(family); | 
| 363 | 	    /* if a match is found get the installed font faces */ | 
| 364 | 	    if (strcasecmp(gv_ps_fontdef->fontname, name) == 0) { | 
| 365 | 		family_name = strdup(name); | 
| 366 | 		availfaces = get_faces(family); | 
| 367 | 	    } | 
| 368 | 	    if (family_name) | 
| 369 | 		break; | 
| 370 | 	} | 
| 371 | 	/* if a match is not found on the primary Graphviz font family, | 
| 372 | 	   search for a match on the equivalent font family names */ | 
| 373 | 	if (!family_name) { | 
| 374 | 	    array_sz = gv_ps_fontdef->eq_sz; | 
| 375 | 	    for (k = 0; k < array_sz; k++) { | 
| 376 | 		for (i = 0; i < n_families; i++) { | 
| 377 | 		    family = families[i]; | 
| 378 | 		    name = pango_font_family_get_name(family); | 
| 379 | 		    if (strcasecmp(gv_ps_fontdef->equiv[k], name) == 0) { | 
| 380 | 			family_name = strdup(name); | 
| 381 | 			availfaces = get_faces(family); | 
| 382 | 			break; | 
| 383 | 		    } | 
| 384 | 		} | 
| 385 | 		if (family_name) | 
| 386 | 		    break; | 
| 387 | 	    } | 
| 388 | 	} | 
| 389 | 	/* if a match is not found on the equivalent font family names, search | 
| 390 | 	   for a match on the generic family name assigned to the Graphviz PS font */ | 
| 391 | 	if (!family_name) { | 
| 392 | 	    for (i = 0; i < n_families; i++) { | 
| 393 | 		family = families[i]; | 
| 394 | 		name = pango_font_family_get_name(family); | 
| 395 | 		if (strcasecmp(gv_ps_fontdef->generic_name, name) == 0) { | 
| 396 | 		    family_name = strdup(name); | 
| 397 | 		    availfaces = get_faces(family); | 
| 398 | 		    break; | 
| 399 | 		} | 
| 400 | 	    } | 
| 401 | 	} | 
| 402 | 	/* if not match is found on the generic name, set the available font | 
| 403 | 	   name to NULL */ | 
| 404 | 	if (family_name && availfaces) { | 
| 405 | 	    gv_afs->fontname = family_name; | 
| 406 | 	    gv_afs->faces = availfaces; | 
| 407 | 	} else { | 
| 408 | 	    gv_afs->fontname = NULL; | 
| 409 | 	    gv_afs->faces = 0; | 
| 410 | 	} | 
| 411 |     } | 
| 412 |     g_free(families); | 
| 413 | #ifdef DEBUG | 
| 414 |     display_available_fonts(gv_af_p); | 
| 415 | #endif | 
| 416 | /* Free the Graphviz PS font definitions */ | 
| 417 |     return (gv_af_p); | 
| 418 | } | 
| 419 |  | 
| 420 | static void copyUpper (agxbuf* xb, char* s) | 
| 421 | { | 
| 422 |     int c; | 
| 423 |  | 
| 424 |     while ((c = *s++)) | 
| 425 | 	(void)agxbputc (xb, toupper(c)); | 
| 426 | } | 
| 427 |  | 
| 428 | /* Returns the font corresponding to a Graphviz PS font. | 
| 429 |    AvantGarde-Book may return URW Gothic L, book | 
| 430 |    Returns NULL if no appropriate font found. | 
| 431 | */ | 
| 432 | static char *gv_get_font(availfont_t* gv_af_p, | 
| 433 | 		  PostscriptAlias * ps_alias, agxbuf* xb, agxbuf *xb2) | 
| 434 | { | 
| 435 |     char *avail_faces; | 
| 436 |     int i; | 
| 437 |  | 
| 438 |     for (i = 0; i < GV_FONT_LIST_SIZE; i++) { | 
| 439 | 	/* Searches the array of available system fonts for the one that | 
| 440 | 	   corresponds to the current Graphviz PS font name. Sets up the | 
| 441 | 	   font string with the available font name and the installed font | 
| 442 | 	   faces that match what are required by the Graphviz PS font. | 
| 443 | 	 */ | 
| 444 | 	if (gv_af_p[i].faces && strstr(ps_alias->name, gv_af_p[i].gv_ps_fontname)) { | 
| 445 | 	    agxbput(xb2, gv_af_p[i].fontname); | 
| 446 | 	    agxbput(xb2, ", " ); | 
| 447 | 	    avail_faces = get_avail_faces(gv_af_p[i].faces, xb); | 
| 448 | 	    if (ps_alias->weight) { | 
| 449 | 		if (strcasestr(avail_faces, ps_alias->weight)) { | 
| 450 | 		    agxbputc(xb2, ' '); | 
| 451 | 		    copyUpper(xb2, ps_alias->weight); | 
| 452 | 		} | 
| 453 | 	    } else if (strcasestr(avail_faces, "REGULAR" )) { | 
| 454 | 		agxbputc(xb2, ' '); | 
| 455 | 		agxbput(xb2, "REGULAR" ); | 
| 456 | 	    } else if (strstr(avail_faces, "ROMAN" )) { | 
| 457 | 		agxbputc(xb2, ' '); | 
| 458 | 		agxbput(xb2, "ROMAN" ); | 
| 459 | 	    } | 
| 460 | 	    if (ps_alias->stretch) { | 
| 461 | 		if (strcasestr(avail_faces, ps_alias->stretch)) { | 
| 462 | 		    agxbputc(xb2, ' '); | 
| 463 | 		    copyUpper(xb2, ps_alias->stretch); | 
| 464 | 		} | 
| 465 | 	    } | 
| 466 | 	    if (ps_alias->style) { | 
| 467 | 		if (strcasestr(avail_faces, ps_alias->style)) { | 
| 468 | 		    agxbputc(xb2, ' '); | 
| 469 | 		    copyUpper(xb2, ps_alias->style); | 
| 470 | 		} else if (!strcasecmp(ps_alias->style, "ITALIC" )) { | 
| 471 |                     /* try to use ITALIC in place of OBLIQUE & visa versa */ | 
| 472 | 		    if (strcasestr(avail_faces, "OBLIQUE" )) { | 
| 473 | 			agxbputc(xb2, ' '); | 
| 474 | 			agxbput(xb2, "OBLIQUE" ); | 
| 475 | 		    } | 
| 476 | 		} else if (!strcasecmp(ps_alias->style, "OBLIQUE" )) { | 
| 477 | 		    if (strcasestr(avail_faces, "ITALIC" )) { | 
| 478 | 			agxbputc(xb2, ' '); | 
| 479 | 			agxbput(xb2, "ITALIC" ); | 
| 480 | 		    } | 
| 481 | 		} | 
| 482 | 	    } | 
| 483 | 	    return strdup(agxbuse(xb2)); | 
| 484 | 	} | 
| 485 |     } | 
| 486 |     return NULL; | 
| 487 | } | 
| 488 |  | 
| 489 | static void | 
| 490 | printFontMap (gv_font_map*gv_fmap, int sz) | 
| 491 | { | 
| 492 |     int j; | 
| 493 |     char* font; | 
| 494 |  | 
| 495 |     for (j = 0; j < sz; j++) { | 
| 496 | 	font = gv_fmap[j].gv_font; | 
| 497 | 	if (!font) | 
| 498 | 	    fprintf (stderr, " [%d] %s => <Not available>\n" , j, gv_fmap[j].gv_ps_fontname); | 
| 499 | 	else | 
| 500 | 	    fprintf (stderr, " [%d] %s => \"%s\"\n" , j, gv_fmap[j].gv_ps_fontname, font); | 
| 501 |     } | 
| 502 | } | 
| 503 |  | 
| 504 | /* Sets up a structure array that contains the Graphviz PS font name | 
| 505 |    and the corresponding installed font string. | 
| 506 | */ | 
| 507 | gv_font_map* get_font_mapping(PangoFontMap * fontmap) | 
| 508 | { | 
| 509 |     PostscriptAlias *ps_alias; | 
| 510 |     availfont_t *gv_af_p; | 
| 511 |     int j, ps_fontnames_sz = sizeof(postscript_alias) / sizeof(PostscriptAlias); | 
| 512 |     gv_font_map* gv_fmap = N_NEW(ps_fontnames_sz, gv_font_map); | 
| 513 |     agxbuf xb; | 
| 514 |     agxbuf xb2; | 
| 515 |     unsigned char buf[BUFSIZ]; | 
| 516 |     unsigned char buf2[BUFSIZ]; | 
| 517 |  | 
| 518 |     agxbinit(&xb, BUFSIZ, buf); | 
| 519 |     agxbinit(&xb2, BUFSIZ, buf2); | 
| 520 |     gv_af_p = gv_get_ps_fontlist(fontmap);	// get the available installed fonts | 
| 521 |     /* add the Graphviz PS font name and available system font string to the array */ | 
| 522 |     for (j = 0; j < ps_fontnames_sz; j++) { | 
| 523 | 	ps_alias = &postscript_alias[j]; | 
| 524 | 	gv_fmap[ps_alias->xfig_code].gv_ps_fontname = ps_alias->name; | 
| 525 | 	gv_fmap[ps_alias->xfig_code].gv_font = gv_get_font(gv_af_p, ps_alias, &xb, &xb2); | 
| 526 |     } | 
| 527 |     gv_flist_free_af(gv_af_p); | 
| 528 |     agxbfree(&xb); | 
| 529 |     agxbfree(&xb2); | 
| 530 | #ifndef _WIN32 | 
| 531 |     if (Verbose > 1) { | 
| 532 | 	fprintf(stderr, "Verbose %d\n" , Verbose); | 
| 533 | 	printFontMap (gv_fmap, ps_fontnames_sz); | 
| 534 |     } | 
| 535 | #endif | 
| 536 |     return gv_fmap; | 
| 537 | } | 
| 538 |  | 
| 539 | /* Returns a list of the fonts that are available for use | 
| 540 |  | 
| 541 | */ | 
| 542 |  | 
| 543 | void get_font_list(char **fonts[], int *cnt){ | 
| 544 |  | 
| 545 | PangoFontMap *fontmap; | 
| 546 | availfont_t *gv_af_p; | 
| 547 | int j, i; | 
| 548 | char **fontlist; | 
| 549 | fontlist = N_NEW(GV_FONT_LIST_SIZE,char *); | 
| 550 | fontmap = pango_cairo_font_map_new(); | 
| 551 | gv_af_p = gv_get_ps_fontlist(fontmap);	// get the available installed fonts | 
| 552 | g_object_unref(fontmap); | 
| 553 | /* load array with available font names */ | 
| 554 | i=0; | 
| 555 | for (j = 0; j < GV_FONT_LIST_SIZE; j++) { | 
| 556 | 	*(fontlist + j) = 0; | 
| 557 | 	if ((gv_af_p[j].faces == 0) || (gv_af_p[j].fontname == NULL)) { | 
| 558 | 	    continue; | 
| 559 | 	} | 
| 560 | 	*(fontlist + i++) = strdup(gv_af_p[j].fontname); | 
| 561 | } | 
| 562 | /* Free unused array elements */ | 
| 563 | for(j=i;j<GV_FONT_LIST_SIZE;j++){ | 
| 564 |     free(*(fontlist + j)); | 
| 565 | } | 
| 566 | /* Free available fonts structure */ | 
| 567 | gv_flist_free_af(gv_af_p); | 
| 568 |  | 
| 569 | *cnt = i; | 
| 570 | *fonts = fontlist; | 
| 571 | return; | 
| 572 | } | 
| 573 |  |