| 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 | |