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