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