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