Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
gvgetfontlist_pango.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <ctype.h>
17#include <util/agxbuf.h>
18#include <util/alloc.h>
19#include <util/gv_ctype.h>
20#include <util/prisize_t.h>
21#include <util/strcasecmp.h>
22#include <util/strview.h>
23
24/* FIXME - the following declaration should be removed
25 * when configure is coordinated with flags passed to the
26 * compiler. On Linux, strcasestr is defined but needs a special
27 * preprocessor constant to be defined. Configure sets the
28 * HAVE_STRCASESTR, but the flag is not used during compilation,
29 * so strcasestr is undeclared.
30 */
31char* strcasestr (const char *str, const char *pat);
32#ifndef HAVE_STRCASESTR
33char* strcasestr (const char *str, const char *pat)
34{
35 int slen, plen;
36 char p0, pc;
37 const char *endp, *sp, *pp;
38 if (!(p0 = *pat)) return (char*)str;
39 plen = strlen (pat++);
40 slen = strlen (str);
41 if (slen < plen) return NULL;
42 endp = str + slen - plen;
43 p0 = toupper (p0);
44 do {
45 while (str <= endp && p0 != toupper(*str)) str++;
46 if (str > endp) return NULL;
47 pp = pat;
48 sp = ++str;
49 while ((pc = *pp++) && toupper(pc) == toupper(*sp)) sp++;
50 } while (pc);
51 return (char*)(str-1);
52}
53
54#endif
55
57#include <pango/pangocairo.h>
58#include "gvgetfontlist.h"
59#include <common/globals.h>
60
61#define FNT_BOLD 1<<0
62#define FNT_BOOK 1<<1
63#define FNT_CONDENSED 1<<2
64#define FNT_DEMI 1<<3
65#define FNT_EXTRALIGHT 1<<4
66#define FNT_ITALIC 1<<5
67#define FNT_LIGHT 1<<6
68#define FNT_MEDIUM 1<<7
69#define FNT_OBLIQUE 1<<8
70#define FNT_REGULAR 1<<9
71#define FNT_ROMAN 1<<9
72
73#define PS_AVANTGARDE "AvantGarde"
74#define PS_BOOKMAN "Bookman"
75#define PS_COURIER "Courier"
76#define PS_HELVETICA SAN_5
77#define PS_NEWCENTURYSCHLBK "NewCenturySchlbk"
78#define PS_PALATINO "Palatino"
79#define PS_SYMBOL "Symbol"
80#define PS_TIMES SER_3
81#define PS_CHANCERY "ZapfChancery"
82#define PS_DINGBATS "ZapfDingbats"
83
84#define FNT_BOLD_ST "BOLD"
85#define FNT_BOOK_ST "BOOK"
86#define FNT_CONDENSED_ST "CONDENSED"
87#define FNT_DEMI_ST "DEMI"
88#define FNT_EXTRALIGHT_ST "EXTRALIGHT"
89#define FNT_ITALIC_ST "ITALIC"
90#define FNT_LIGHT_ST "LIGHT"
91#define FNT_MEDIUM_ST "MEDIUM"
92#define FNT_OBLIQUE_ST "OBLIQUE"
93#define FNT_REGULAR_ST "REGULAR"
94#define FNT_ROMAN_ST "ROMAN"
95
96#define SAN_0 "sans"
97#define SAN_1 "URW Gothic L"
98#define SAN_2 "Charcoal"
99#define SAN_3 "Nimbus Sans L"
100#define SAN_4 "Verdana"
101#define SAN_5 "Helvetica"
102#define SAN_6 "Bitstream Vera Sans"
103#define SAN_7 "DejaVu Sans"
104#define SAN_8 "Liberation Sans"
105#define SAN_9 "Luxi Sans"
106#define SAN_10 "FreeSans"
107#define SAN_11 "Arial"
108
109#define SER_0 "serif"
110#define SER_1 "URW Bookman L"
111#define SER_2 "Times New Roman"
112#define SER_3 "Times"
113#define SER_4 "Nimbus Roman No9 L"
114#define SER_5 "Bitstream Vera Serif"
115#define SER_6 "DejaVu Serif"
116#define SER_7 "Liberation Serif"
117#define SER_8 "Luxi Serif"
118#define SER_9 "FreeSerif"
119#define SER_10 "Century Schoolbook L"
120#define SER_11 "Charcoal"
121#define SER_12 "Georgia"
122#define SER_13 "URW Palladio L"
123#define SER_14 "Norasi"
124#define SER_15 "Rekha"
125#define SER_16 "URW Chancery L"
126
127#define MON_0 "monospace"
128#define MON_1 "Nimbus Mono L"
129#define MON_2 "Inconsolata"
130#define MON_3 "Courier New"
131#define MON_4 "Bitstream Vera Sans Mono"
132#define MON_5 "DejaVu Sans Mono"
133#define MON_6 "Liberation Mono"
134#define MON_7 "Luxi Mono"
135#define MON_8 "FreeMono"
136
137#define SYM_0 "fantasy"
138#define SYM_1 "Impact"
139#define SYM_2 "Copperplate Gothic Std"
140#define SYM_3 "Cooper Std"
141#define SYM_4 "Bauhaus Std"
142
143#define DING_0 "fantasy"
144#define DING_1 "Dingbats"
145#define DING_2 "Impact"
146#define DING_3 "Copperplate Gothic Std"
147#define DING_4 "Cooper Std"
148#define DING_5 "Bauhaus Std"
149
150
151typedef struct {
152 int flag;
153 char* name;
154} face_t;
168#define FACELIST_SZ (sizeof(facelist)/sizeof(face_t))
169
170/* This is where the hierarchy of equivalent fonts is established. The order can be changed
171 here or new equivalent fonts can be added here. Each font family used by the Graphviz
172 PS fonts is set up.
173*/
174static const char *PS_AVANT_E[] = {
176};
177#define PS_AVANT_E_SZ (sizeof(PS_AVANT_E) / sizeof(char *))
178
179static const char *PS_BOOKMAN_E[] = {
181};
182#define PS_BOOKMAN_E_SZ (sizeof(PS_BOOKMAN_E) / sizeof(char *))
183
184static const char *PS_COURIER_E[] = {
186};
187#define PS_COURIER_E_SZ (sizeof(PS_COURIER_E) / sizeof(char *))
188
189static const char *PS_HELVETICA_E[] = {
191};
192#define PS_HELVETICA_E_SZ (sizeof(PS_HELVETICA_E) / sizeof(char *))
193
194static const char *PS_NEWCENT_E[] = {
196};
197#define PS_NEWCENT_E_SZ (sizeof(PS_NEWCENT_E) / sizeof(char *))
198
199static const char *PS_PALATINO_E[] = {
201};
202#define PS_PALATINO_E_SZ (sizeof(PS_PALATINO_E) / sizeof(char *))
203
204static const char *PS_TIMES_E[] = {
206};
207#define PS_TIMES_E_SZ (sizeof(PS_TIMES_E) / sizeof(char *))
208
209static const char *PS_SYMBOL_E[] = { SYM_1, SYM_2, SYM_3, SYM_4 };
210#define PS_SYMBOL_E_SZ (sizeof(PS_SYMBOL_E) / sizeof(char *))
211
212static const char *PS_CHANCERY_E[] = {
214};
215#define PS_CHANCERY_E_SZ (sizeof(PS_CHANCERY_E) / sizeof(char *))
216
217static const char *PS_DINGBATS_E[] = { DING_1, SYM_1, SYM_2, SYM_3, SYM_4 };
218#define PS_DINGBATS_E_SZ (sizeof(PS_DINGBATS_E) / sizeof(char *))
219
220typedef struct {
222 char *fontname;
223 int eq_sz;
224 const char **equiv;
225} fontdef_t;
226
227/* array of recognized Graphviz PS font names */
240#define GV_FONT_LIST_SIZE (sizeof(gv_ps_fontdefs)/sizeof(fontdef_t))
241
242typedef struct {
244 char *fontname;
245 int faces;
247
253typedef struct {
256
258#include "ps_font_equiv.h"
259};
260
261/* Frees memory used by the available system font definitions */
262static void gv_flist_free_af(availfonts_t gv_af_p) {
263 for (size_t i = 0; i < GV_FONT_LIST_SIZE; i++) {
264 free(gv_af_p.fonts[i].fontname);
265 }
266}
267
268static int get_faces(PangoFontFamily * family)
269{
270 PangoFontFace **faces;
271 PangoFontFace *face;
272 int i, n_faces;
273 const char *name;
274 int availfaces = 0;
275 /* Get the faces (Bold, Italic, etc.) for the current font family */
276 pango_font_family_list_faces(family, &faces, &n_faces);
277 for (i = 0; i < n_faces; i++) {
278 face = faces[i];
279 name = pango_font_face_get_face_name(face);
280
281 /* if the family face type is one of the known types, logically OR the known type value
282 to the available faces integer */
283 for (size_t j = 0; j < FACELIST_SZ; j++) {
284 if (strcasestr(name, facelist[j].name)) {
285 availfaces |= facelist[j].flag;
286 break;
287 }
288 }
289 }
290 g_free(faces);
291 return availfaces;
292}
293
294#ifdef DEBUG
295static void
296display_available_fonts(availfonts_t gv_af_p) {
297 int faces;
298
299/* Displays the Graphviz PS font name, system available font name and associated faces */
300 for (size_t j = 0; j < GV_FONT_LIST_SIZE; j++) {
301 if (gv_af_p.fonts[j].faces == 0 || gv_af_p.fonts[j].fontname == NULL) {
302 fprintf (stderr, "ps font = %s not available\n", gv_ps_fontdefs[j].fontname);
303 continue;
304 }
305 fprintf (stderr, "ps font = %s available %d font = %s\n",
306 gv_ps_fontdefs[j].fontname, gv_af_p.fonts[j].faces,
307 gv_af_p.fonts[j].fontname);
308 faces = gv_af_p.fonts[j].faces;
309 for (size_t i = 0; i < FACELIST_SZ; i++) {
310 if (faces & facelist[i].flag)
311 fprintf (stderr, "\t%s\n", facelist[i].name);
312 }
313 }
314}
315#endif
316
317/* Construct the list of font faces */
318static char *get_avail_faces(int faces, agxbuf* xb)
319{
320 for (size_t i = 0; i < FACELIST_SZ; i++) {
321 if (faces & facelist[i].flag) {
322 agxbprint (xb, "%s ", facelist[i].name);
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*/
334static availfonts_t gv_get_ps_fontlist(PangoFontMap *fontmap) {
335 PangoFontFamily **families;
336 PangoFontFamily *family;
337 fontdef_t* gv_ps_fontdef;
338 int n_families;
339 int i, k, array_sz, availfaces = 0;
340 const char *name;
341
342 /* Get a list of font families installed on the system */
343 pango_font_map_list_families(fontmap, &families, &n_families);
344
345 availfonts_t gv_af_p = {0};
346 for (size_t j = 0; j < GV_FONT_LIST_SIZE; j++) {
347 /* get the Graphviz PS font information and create the
348 available font definition structs */
349 availfont_t *gv_afs = &gv_af_p.fonts[j];
350 gv_ps_fontdef = gv_ps_fontdefs+j;
351 gv_afs->gv_ps_fontname = gv_ps_fontdef->fontname;
352 strview_t family_name = {0};
353 /* Search the installed system font families for the current
354 Graphvis PS font family name, i.e. AvantGarde */
355 for (i = 0; i < n_families; i++) {
356 family = families[i];
357 name = pango_font_family_get_name(family);
358 /* if a match is found get the installed font faces */
359 if (strcasecmp(gv_ps_fontdef->fontname, name) == 0) {
360 family_name = strview(name, '\0');
361 availfaces = get_faces(family);
362 break;
363 }
364 }
365 /* if a match is not found on the primary Graphviz font family,
366 search for a match on the equivalent font family names */
367 if (family_name.data == NULL) {
368 array_sz = gv_ps_fontdef->eq_sz;
369 for (k = 0; k < array_sz; k++) {
370 for (i = 0; i < n_families; i++) {
371 family = families[i];
372 name = pango_font_family_get_name(family);
373 if (strcasecmp(gv_ps_fontdef->equiv[k], name) == 0) {
374 family_name = strview(name, '\0');
375 availfaces = get_faces(family);
376 break;
377 }
378 }
379 if (family_name.data != NULL)
380 break;
381 }
382 }
383 /* if a match is not found on the equivalent font family names, search
384 for a match on the generic family name assigned to the Graphviz PS font */
385 if (family_name.data == NULL) {
386 for (i = 0; i < n_families; i++) {
387 family = families[i];
388 name = pango_font_family_get_name(family);
389 if (strcasecmp(gv_ps_fontdef->generic_name, name) == 0) {
390 family_name = strview(name, '\0');
391 availfaces = get_faces(family);
392 break;
393 }
394 }
395 }
396 /* if not match is found on the generic name, set the available font
397 name to NULL */
398 if (family_name.data != NULL && availfaces) {
399 gv_afs->fontname = strview_str(family_name);
400 gv_afs->faces = availfaces;
401 } else {
402 gv_afs->fontname = NULL;
403 gv_afs->faces = 0;
404 }
405 }
406 g_free(families);
407#ifdef DEBUG
408 display_available_fonts(gv_af_p);
409#endif
410 return gv_af_p;
411}
412
413static void copyUpper (agxbuf* xb, char* s)
414{
415 int c;
416
417 while ((c = *s++))
418 (void)agxbputc(xb, gv_toupper(c));
419}
420
421/* Returns the font corresponding to a Graphviz PS font.
422 AvantGarde-Book may return URW Gothic L, book
423 Returns NULL if no appropriate font found.
424*/
425static char *gv_get_font(availfonts_t gv_af_p,
426 PostscriptAlias * ps_alias, agxbuf* xb, agxbuf *xb2)
427{
428 char *avail_faces;
429
430 for (size_t i = 0; i < GV_FONT_LIST_SIZE; i++) {
431 /* Searches the array of available system fonts for the one that
432 corresponds to the current Graphviz PS font name. Sets up the
433 font string with the available font name and the installed font
434 faces that match what are required by the Graphviz PS font.
435 */
436 if (gv_af_p.fonts[i].faces &&
437 strstr(ps_alias->name, gv_af_p.fonts[i].gv_ps_fontname)) {
438 agxbprint(xb2, "%s, ", gv_af_p.fonts[i].fontname);
439 avail_faces = get_avail_faces(gv_af_p.fonts[i].faces, xb);
440 if (ps_alias->weight) {
441 if (strcasestr(avail_faces, ps_alias->weight)) {
442 agxbputc(xb2, ' ');
443 copyUpper(xb2, ps_alias->weight);
444 }
445 } else if (strcasestr(avail_faces, "REGULAR")) {
446 agxbput(xb2, " REGULAR");
447 } else if (strstr(avail_faces, "ROMAN")) {
448 agxbput(xb2, " ROMAN");
449 }
450 if (ps_alias->stretch) {
451 if (strcasestr(avail_faces, ps_alias->stretch)) {
452 agxbputc(xb2, ' ');
453 copyUpper(xb2, ps_alias->stretch);
454 }
455 }
456 if (ps_alias->style) {
457 if (strcasestr(avail_faces, ps_alias->style)) {
458 agxbputc(xb2, ' ');
459 copyUpper(xb2, ps_alias->style);
460 } else if (!strcasecmp(ps_alias->style, "ITALIC")) {
461 /* try to use ITALIC in place of OBLIQUE & visa versa */
462 if (strcasestr(avail_faces, "OBLIQUE")) {
463 agxbput(xb2, " OBLIQUE");
464 }
465 } else if (!strcasecmp(ps_alias->style, "OBLIQUE")) {
466 if (strcasestr(avail_faces, "ITALIC")) {
467 agxbput(xb2, " ITALIC");
468 }
469 }
470 }
471 return agxbdisown(xb2);
472 }
473 }
474 return NULL;
475}
476
477static void printFontMap(gv_font_map *gv_fmap, size_t sz) {
478 char* font;
479
480 for (size_t j = 0; j < sz; j++) {
481 font = gv_fmap[j].gv_font;
482 if (!font)
483 fprintf(stderr, " [%" PRISIZE_T "] %s => <Not available>\n", j,
484 gv_fmap[j].gv_ps_fontname);
485 else
486 fprintf(stderr, " [%" PRISIZE_T "] %s => \"%s\"\n", j,
487 gv_fmap[j].gv_ps_fontname, font);
488 }
489}
490
491/* Sets up a structure array that contains the Graphviz PS font name
492 and the corresponding installed font string.
493*/
494gv_font_map* get_font_mapping(PangoFontMap * fontmap)
495{
496 PostscriptAlias *ps_alias;
497 static const size_t ps_fontnames_sz =
498 sizeof(postscript_alias) / sizeof(PostscriptAlias);
499 gv_font_map* gv_fmap = gv_calloc(ps_fontnames_sz, sizeof(gv_font_map));
500 agxbuf xb = {0};
501 agxbuf xb2 = {0};
502 availfonts_t gv_af_p = gv_get_ps_fontlist(fontmap); // get the available installed fonts
503 /* add the Graphviz PS font name and available system font string to the array */
504 for (size_t j = 0; j < ps_fontnames_sz; j++) {
505 ps_alias = &postscript_alias[j];
506 gv_fmap[ps_alias->xfig_code].gv_ps_fontname = ps_alias->name;
507 gv_fmap[ps_alias->xfig_code].gv_font = gv_get_font(gv_af_p, ps_alias, &xb, &xb2);
508 }
509 gv_flist_free_af(gv_af_p);
510 agxbfree(&xb);
511 agxbfree(&xb2);
512 if (Verbose > 1) {
513 fprintf(stderr, "Verbose %d\n", Verbose);
514 printFontMap (gv_fmap, ps_fontnames_sz);
515 }
516 return gv_fmap;
517}
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:277
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:327
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static bool Verbose
Definition gml2gv.c:23
void free(void *)
node NULL
Definition grammar.y:163
replacements for ctype.h functions
static char gv_toupper(int c)
Definition gv_ctype.h:93
agxbput(xb, staging)
#define SAN_11
#define FNT_MEDIUM_ST
static char * get_avail_faces(int faces, agxbuf *xb)
#define DING_1
#define SER_8
static fontdef_t gv_ps_fontdefs[]
static void gv_flist_free_af(availfonts_t gv_af_p)
static const char * PS_TIMES_E[]
#define SER_15
#define SER_4
#define SER_6
#define PS_COURIER
#define PS_HELVETICA
#define MON_8
#define SAN_3
#define SER_2
#define SAN_4
#define MON_4
static const char * PS_BOOKMAN_E[]
#define FNT_DEMI
#define FNT_BOOK
#define MON_5
static PostscriptAlias postscript_alias[]
#define PS_NEWCENTURYSCHLBK
#define SAN_0
#define MON_0
#define PS_DINGBATS_E_SZ
#define SER_11
#define FNT_DEMI_ST
#define FNT_LIGHT
#define SAN_8
#define FNT_REGULAR_ST
static const char * PS_CHANCERY_E[]
static const char * PS_COURIER_E[]
#define GV_FONT_LIST_SIZE
#define PS_AVANT_E_SZ
static const char * PS_SYMBOL_E[]
static const char * PS_NEWCENT_E[]
#define FNT_ITALIC
#define FNT_LIGHT_ST
#define PS_PALATINO_E_SZ
#define PS_SYMBOL
#define SAN_2
#define DING_0
static const char * PS_HELVETICA_E[]
#define PS_PALATINO
static face_t facelist[]
#define SAN_7
#define MON_2
#define SER_3
static const char * PS_AVANT_E[]
#define FNT_ITALIC_ST
#define PS_HELVETICA_E_SZ
static const char * PS_PALATINO_E[]
#define PS_COURIER_E_SZ
#define SAN_5
#define SAN_1
#define PS_BOOKMAN_E_SZ
static char * gv_get_font(availfonts_t gv_af_p, PostscriptAlias *ps_alias, agxbuf *xb, agxbuf *xb2)
#define SER_16
#define SER_1
static int get_faces(PangoFontFamily *family)
#define SER_12
#define FNT_MEDIUM
#define PS_NEWCENT_E_SZ
#define SAN_10
#define FACELIST_SZ
#define SAN_6
#define FNT_REGULAR
#define MON_7
#define PS_DINGBATS
#define SYM_2
#define SER_9
#define FNT_BOOK_ST
#define SER_5
static const char * PS_DINGBATS_E[]
#define SYM_1
#define PS_BOOKMAN
#define SAN_9
#define PS_TIMES_E_SZ
#define FNT_BOLD_ST
static void copyUpper(agxbuf *xb, char *s)
static void printFontMap(gv_font_map *gv_fmap, size_t sz)
#define PS_CHANCERY_E_SZ
static availfonts_t gv_get_ps_fontlist(PangoFontMap *fontmap)
#define FNT_BOLD
#define FNT_CONDENSED_ST
#define MON_6
#define SYM_3
#define PS_SYMBOL_E_SZ
#define FNT_EXTRALIGHT_ST
#define FNT_ROMAN_ST
#define MON_1
#define PS_AVANTGARDE
#define SER_0
#define SYM_0
#define SYM_4
#define SER_10
#define PS_CHANCERY
#define PS_TIMES
#define SER_7
#define FNT_OBLIQUE_ST
#define SER_14
gv_font_map * get_font_mapping(PangoFontMap *fontmap)
#define MON_3
#define FNT_ROMAN
#define SER_13
char * strcasestr(const char *str, const char *pat)
#define FNT_CONDENSED
#define FNT_OBLIQUE
#define FNT_EXTRALIGHT
textitem scanner parser str
Definition htmlparse.y:224
$2 font
Definition htmlparse.y:300
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
platform abstraction for case-insensitive string functions
availfont_t fonts[GV_FONT_LIST_SIZE]
const char ** equiv
char * gv_ps_fontname
a non-owning string reference
Definition strview.h:20
const char * data
start of the pointed to string
Definition strview.h:21
Non-owning string references.
static char * strview_str(strview_t source)
make a heap-allocated string from this string view
Definition strview.h:41
static strview_t strview(const char *referent, char terminator)
create a string reference
Definition strview.h:26
Definition grammar.c:93