Graphviz 12.0.1~dev.20240716.0800
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 <cgraph/alloc.h>
18#include <cgraph/gv_ctype.h>
19#include <cgraph/strcasecmp.h>
20#include <cgraph/strview.h>
21
22/* FIXME - the following declaration should be removed
23 * when configure is coordinated with flags passed to the
24 * compiler. On Linux, strcasestr is defined but needs a special
25 * preprocessor constant to be defined. Configure sets the
26 * HAVE_STRCASESTR, but the flag is not used during compilation,
27 * so strcasestr is undeclared.
28 */
29char* strcasestr (const char *str, const char *pat);
30#ifndef HAVE_STRCASESTR
31char* strcasestr (const char *str, const char *pat)
32{
33 int slen, plen;
34 char p0, pc;
35 const char *endp, *sp, *pp;
36 if (!(p0 = *pat)) return (char*)str;
37 plen = strlen (pat++);
38 slen = strlen (str);
39 if (slen < plen) return NULL;
40 endp = str + slen - plen;
41 p0 = toupper (p0);
42 do {
43 while (str <= endp && p0 != toupper(*str)) str++;
44 if (str > endp) return NULL;
45 pp = pat;
46 sp = ++str;
47 while ((pc = *pp++) && toupper(pc) == toupper(*sp)) sp++;
48 } while (pc);
49 return (char*)(str-1);
50}
51
52#endif
53
54#include <cgraph/agxbuf.h>
56#include <pango/pangocairo.h>
57#include "gvgetfontlist.h"
58#include <common/globals.h>
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 FNT_EXTRALIGHT 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 FNT_EXTRALIGHT_ST "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
150typedef struct {
151 int flag;
152 char* name;
153} face_t;
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*/
173static const char *PS_AVANT_E[] = {
175};
176#define PS_AVANT_E_SZ (sizeof(PS_AVANT_E) / sizeof(char *))
177
178static const char *PS_BOOKMAN_E[] = {
180};
181#define PS_BOOKMAN_E_SZ (sizeof(PS_BOOKMAN_E) / sizeof(char *))
182
183static const char *PS_COURIER_E[] = {
185};
186#define PS_COURIER_E_SZ (sizeof(PS_COURIER_E) / sizeof(char *))
187
188static const char *PS_HELVETICA_E[] = {
190};
191#define PS_HELVETICA_E_SZ (sizeof(PS_HELVETICA_E) / sizeof(char *))
192
193static const char *PS_NEWCENT_E[] = {
195};
196#define PS_NEWCENT_E_SZ (sizeof(PS_NEWCENT_E) / sizeof(char *))
197
198static const char *PS_PALATINO_E[] = {
200};
201#define PS_PALATINO_E_SZ (sizeof(PS_PALATINO_E) / sizeof(char *))
202
203static const char *PS_TIMES_E[] = {
205};
206#define PS_TIMES_E_SZ (sizeof(PS_TIMES_E) / sizeof(char *))
207
208static 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
211static const char *PS_CHANCERY_E[] = {
213};
214#define PS_CHANCERY_E_SZ (sizeof(PS_CHANCERY_E) / sizeof(char *))
215
216static 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
219typedef struct {
221 char *fontname;
222 int eq_sz;
223 const char **equiv;
224} fontdef_t;
225
226/* array of recognized Graphviz PS font names */
239#define GV_FONT_LIST_SIZE (sizeof(gv_ps_fontdefs)/sizeof(fontdef_t))
240
241typedef struct {
243 char *fontname;
244 int faces;
246
252typedef struct {
255
257#include "ps_font_equiv.h"
258};
259
260/* Frees memory used by the available system font definitions */
261static void gv_flist_free_af(availfonts_t gv_af_p) {
262 for (size_t i = 0; i < GV_FONT_LIST_SIZE; i++) {
263 free(gv_af_p.fonts[i].fontname);
264 }
265}
266
267static int get_faces(PangoFontFamily * family)
268{
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 type value
281 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
295display_available_fonts(availfonts_t gv_af_p) {
296 int faces;
297
298/* Displays the Graphviz PS font name, system available font name and 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", 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.fonts[j].faces,
306 gv_af_p.fonts[j].fontname);
307 faces = gv_af_p.fonts[j].faces;
308 for (size_t i = 0; i < FACELIST_SZ; i++) {
309 if (faces & facelist[i].flag)
310 fprintf (stderr, "\t%s\n", facelist[i].name);
311 }
312 }
313}
314#endif
315
316/* Construct the list of font faces */
317static char *get_avail_faces(int faces, agxbuf* xb)
318{
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
328/* This function creates an array of font definitions. Each entry corresponds to one of
329 the Graphviz PS fonts. The font definitions contain the generic font name and a list
330 of equivalent fonts that can be used in place of the PS font if the PS font is not
331 available on the system
332*/
333static availfonts_t gv_get_ps_fontlist(PangoFontMap *fontmap) {
334 PangoFontFamily **families;
335 PangoFontFamily *family;
336 fontdef_t* gv_ps_fontdef;
337 int n_families;
338 int i, k, array_sz, availfaces = 0;
339 const char *name;
340
341 /* Get a list of font families installed on the system */
342 pango_font_map_list_families(fontmap, &families, &n_families);
343
344 availfonts_t gv_af_p = {0};
345 for (size_t j = 0; j < GV_FONT_LIST_SIZE; j++) {
346 /* get the Graphviz PS font information and create the
347 available font definition structs */
348 availfont_t *gv_afs = &gv_af_p.fonts[j];
349 gv_ps_fontdef = gv_ps_fontdefs+j;
350 gv_afs->gv_ps_fontname = gv_ps_fontdef->fontname;
351 strview_t family_name = {0};
352 /* Search the installed system font families for the current
353 Graphvis PS font family name, i.e. AvantGarde */
354 for (i = 0; i < n_families; i++) {
355 family = families[i];
356 name = pango_font_family_get_name(family);
357 /* if a match is found get the installed font faces */
358 if (strcasecmp(gv_ps_fontdef->fontname, name) == 0) {
359 family_name = strview(name, '\0');
360 availfaces = get_faces(family);
361 }
362 if (family_name.data != NULL)
363 break;
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/* Free the Graphviz PS font definitions */
411 return gv_af_p;
412}
413
414static void copyUpper (agxbuf* xb, char* s)
415{
416 int c;
417
418 while ((c = *s++))
419 (void)agxbputc(xb, gv_toupper(c));
420}
421
422/* Returns the font corresponding to a Graphviz PS font.
423 AvantGarde-Book may return URW Gothic L, book
424 Returns NULL if no appropriate font found.
425*/
426static char *gv_get_font(availfonts_t gv_af_p,
427 PostscriptAlias * ps_alias, agxbuf* xb, agxbuf *xb2)
428{
429 char *avail_faces;
430
431 for (size_t i = 0; i < GV_FONT_LIST_SIZE; i++) {
432 /* Searches the array of available system fonts for the one that
433 corresponds to the current Graphviz PS font name. Sets up the
434 font string with the available font name and the installed font
435 faces that match what are required by the Graphviz PS font.
436 */
437 if (gv_af_p.fonts[i].faces &&
438 strstr(ps_alias->name, gv_af_p.fonts[i].gv_ps_fontname)) {
439 agxbprint(xb2, "%s, ", gv_af_p.fonts[i].fontname);
440 avail_faces = get_avail_faces(gv_af_p.fonts[i].faces, xb);
441 if (ps_alias->weight) {
442 if (strcasestr(avail_faces, ps_alias->weight)) {
443 agxbputc(xb2, ' ');
444 copyUpper(xb2, ps_alias->weight);
445 }
446 } else if (strcasestr(avail_faces, "REGULAR")) {
447 agxbput(xb2, " REGULAR");
448 } else if (strstr(avail_faces, "ROMAN")) {
449 agxbput(xb2, " ROMAN");
450 }
451 if (ps_alias->stretch) {
452 if (strcasestr(avail_faces, ps_alias->stretch)) {
453 agxbputc(xb2, ' ');
454 copyUpper(xb2, ps_alias->stretch);
455 }
456 }
457 if (ps_alias->style) {
458 if (strcasestr(avail_faces, ps_alias->style)) {
459 agxbputc(xb2, ' ');
460 copyUpper(xb2, ps_alias->style);
461 } else if (!strcasecmp(ps_alias->style, "ITALIC")) {
462 /* try to use ITALIC in place of OBLIQUE & visa versa */
463 if (strcasestr(avail_faces, "OBLIQUE")) {
464 agxbput(xb2, " OBLIQUE");
465 }
466 } else if (!strcasecmp(ps_alias->style, "OBLIQUE")) {
467 if (strcasestr(avail_faces, "ITALIC")) {
468 agxbput(xb2, " ITALIC");
469 }
470 }
471 }
472 return agxbdisown(xb2);
473 }
474 }
475 return NULL;
476}
477
478static void
479printFontMap (gv_font_map*gv_fmap, int sz)
480{
481 int j;
482 char* font;
483
484 for (j = 0; j < sz; j++) {
485 font = gv_fmap[j].gv_font;
486 if (!font)
487 fprintf (stderr, " [%d] %s => <Not available>\n", j, gv_fmap[j].gv_ps_fontname);
488 else
489 fprintf (stderr, " [%d] %s => \"%s\"\n", j, gv_fmap[j].gv_ps_fontname, font);
490 }
491}
492
493/* Sets up a structure array that contains the Graphviz PS font name
494 and the corresponding installed font string.
495*/
496gv_font_map* get_font_mapping(PangoFontMap * fontmap)
497{
498 PostscriptAlias *ps_alias;
499 static const size_t ps_fontnames_sz =
500 sizeof(postscript_alias) / sizeof(PostscriptAlias);
501 gv_font_map* gv_fmap = gv_calloc(ps_fontnames_sz, sizeof(gv_font_map));
502 agxbuf xb = {0};
503 agxbuf xb2 = {0};
504 availfonts_t gv_af_p = gv_get_ps_fontlist(fontmap); // get the available installed fonts
505 /* add the Graphviz PS font name and available system font string to the array */
506 for (size_t j = 0; j < ps_fontnames_sz; j++) {
507 ps_alias = &postscript_alias[j];
508 gv_fmap[ps_alias->xfig_code].gv_ps_fontname = ps_alias->name;
509 gv_fmap[ps_alias->xfig_code].gv_font = gv_get_font(gv_af_p, ps_alias, &xb, &xb2);
510 }
511 gv_flist_free_af(gv_af_p);
512 agxbfree(&xb);
513 agxbfree(&xb2);
514 if (Verbose > 1) {
515 fprintf(stderr, "Verbose %d\n", Verbose);
516 printFontMap (gv_fmap, ps_fontnames_sz);
517 }
518 return gv_fmap;
519}
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:77
static size_t agxbput(agxbuf *xb, const char *s)
append string s into xb
Definition agxbuf.h:249
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:213
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:256
static char * agxbuse(agxbuf *xb)
Definition agxbuf.h:286
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:299
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static int Verbose
Definition gml2gv.c:22
void free(void *)
node NULL
Definition grammar.y:149
replacements for ctype.h functions
static char gv_toupper(int c)
Definition gv_ctype.h:93
#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 void printFontMap(gv_font_map *gv_fmap, int sz)
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)
#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
agxbuf * str
Definition htmlparse.c:97
$2 font
Definition htmlparse.y:498
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