Graphviz  2.35.20130930.0449
gvgetfontlist_pango.c
Go to the documentation of this file.
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 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
22 
23 /* FIXME - the following declaration should be removed
24  * when configure is coordinated with flags passed to the
25  * compiler. On Linux, strcasestr is defined but needs a special
26  * preprocessor constant to be defined. Configure sets the
27  * HAVE_STRCASESTR, but the flag is not used during compilation,
28  * so strcasestr is undeclared.
29  */
30 char* strcasestr (const char *str, const char *pat);
31 #ifndef HAVE_STRCASESTR
32 char* strcasestr (const char *str, const char *pat)
33 {
34  int slen, plen;
35  char p0, pc;
36  const char *endp, *sp, *pp;
37  if (!(p0 = *pat)) return (char*)str;
38  plen = strlen (pat++);
39  slen = strlen (str);
40  if (slen < plen) return NULL;
41  endp = str + slen - plen;
42  p0 = toupper (p0);
43  do {
44  while ((str <= endp) && (p0 != toupper(*str))) str++;
45  if (str > endp) return NULL;
46  pp = pat;
47  sp = ++str;
48  while ((pc = *pp++) && (toupper(pc) == toupper(*sp))) sp++;
49  } while (pc);
50  return (char*)(str-1);
51 }
52 
53 #endif
54 
55 #include "agxbuf.h"
56 #include "gvplugin_textlayout.h"
57 #ifdef HAVE_PANGOCAIRO
58 #include <pango/pangocairo.h>
59 #include "gvgetfontlist.h"
60 #endif
61 
62 extern int Verbose;
63 
64 #define FNT_BOLD 1<<0
65 #define FNT_BOOK 1<<1
66 #define FNT_CONDENSED 1<<2
67 #define FNT_DEMI 1<<3
68 #define FNT_EXTRALIGHT 1<<4
69 #define FNT_ITALIC 1<<5
70 #define FNT_LIGHT 1<<6
71 #define FNT_MEDIUM 1<<7
72 #define FNT_OBLIQUE 1<<8
73 #define FNT_REGULAR 1<<9
74 #define FNT_ROMAN 1<<9
75 
76 #define PS_AVANTGARDE "AvantGarde"
77 #define PS_BOOKMAN "Bookman"
78 #define PS_COURIER "Courier"
79 #define PS_HELVETICA SAN_5
80 #define PS_NEWCENTURYSCHLBK "NewCenturySchlbk"
81 #define PS_PALATINO "Palatino"
82 #define PS_SYMBOL "Symbol"
83 #define PS_TIMES SER_3
84 #define PS_CHANCERY "ZapfChancery"
85 #define PS_DINGBATS "ZapfDingbats"
86 
87 #define FNT_BOLD_ST "BOLD"
88 #define FNT_BOOK_ST "BOOK"
89 #define FNT_CONDENSED_ST "CONDENSED"
90 #define FNT_DEMI_ST "DEMI"
91 #define FNT_EXTRALIGHT_ST "EXTRALIGHT"
92 #define FNT_ITALIC_ST "ITALIC"
93 #define FNT_LIGHT_ST "LIGHT"
94 #define FNT_MEDIUM_ST "MEDIUM"
95 #define FNT_OBLIQUE_ST "OBLIQUE"
96 #define FNT_REGULAR_ST "REGULAR"
97 #define FNT_ROMAN_ST "ROMAN"
98 
99 #define SAN_0 "sans"
100 #define SAN_1 "URW Gothic L"
101 #define SAN_2 "Charcoal"
102 #define SAN_3 "Nimbus Sans L"
103 #define SAN_4 "Verdana"
104 #define SAN_5 "Helvetica"
105 #define SAN_6 "Bitstream Vera Sans"
106 #define SAN_7 "DejaVu Sans"
107 #define SAN_8 "Liberation Sans"
108 #define SAN_9 "Luxi Sans"
109 #define SAN_10 "FreeSans"
110 #define SAN_11 "Arial"
111 
112 #define SER_0 "serif"
113 #define SER_1 "URW Bookman L"
114 #define SER_2 "Times New Roman"
115 #define SER_3 "Times"
116 #define SER_4 "Nimbus Roman No9 L"
117 #define SER_5 "Bitstream Vera Serif"
118 #define SER_6 "DejaVu Serif"
119 #define SER_7 "Liberation Serif"
120 #define SER_8 "Luxi Serif"
121 #define SER_9 "FreeSerif"
122 #define SER_10 "Century Schoolbook L"
123 #define SER_11 "Charcoal"
124 #define SER_12 "Georgia"
125 #define SER_13 "URW Palladio L"
126 #define SER_14 "Norasi"
127 #define SER_15 "Rekha"
128 #define SER_16 "URW Chancery L"
129 
130 #define MON_0 "monospace"
131 #define MON_1 "Nimbus Mono L"
132 #define MON_2 "Inconsolata"
133 #define MON_3 "Courier New"
134 #define MON_4 "Bitstream Vera Sans Mono"
135 #define MON_5 "DejaVu Sans Mono"
136 #define MON_6 "Liberation Mono"
137 #define MON_7 "Luxi Mono"
138 #define MON_8 "FreeMono"
139 
140 #define SYM_0 "fantasy"
141 #define SYM_1 "Impact"
142 #define SYM_2 "Copperplate Gothic Std"
143 #define SYM_3 "Cooper Std"
144 #define SYM_4 "Bauhaus Std"
145 
146 #define DING_0 "fantasy"
147 #define DING_1 "Dingbats"
148 #define DING_2 "Impact"
149 #define DING_3 "Copperplate Gothic Std"
150 #define DING_4 "Cooper Std"
151 #define DING_5 "Bauhaus Std"
152 
153 
154 typedef struct {
155  int flag;
156  char* name;
157 } face_t;
158 static face_t facelist[] = {
159  { FNT_BOLD, FNT_BOLD_ST},
160  { FNT_BOOK, FNT_BOOK_ST},
162  { FNT_DEMI, FNT_DEMI_ST},
165  { FNT_LIGHT, FNT_LIGHT_ST},
170 };
171 #define FACELIST_SZ (sizeof(facelist)/sizeof(face_t))
172 
173 /* This is where the hierarchy of equivalent fonts is established. The order can be changed
174  here or new equivalent fonts can be added here. Each font family used by the Graphviz
175  PS fonts is set up.
176 */
177 static const char *PS_AVANT_E[] = {
179 };
180 #define PS_AVANT_E_SZ (sizeof(PS_AVANT_E) / sizeof(char *))
181 
182 static const char *PS_BOOKMAN_E[] = {
184 };
185 #define PS_BOOKMAN_E_SZ (sizeof(PS_BOOKMAN_E) / sizeof(char *))
186 
187 static const char *PS_COURIER_E[] = {
189 };
190 #define PS_COURIER_E_SZ (sizeof(PS_COURIER_E) / sizeof(char *))
191 
192 static const char *PS_HELVETICA_E[] = {
194 };
195 #define PS_HELVETICA_E_SZ (sizeof(PS_HELVETICA_E) / sizeof(char *))
196 
197 static const char *PS_NEWCENT_E[] = {
199 };
200 #define PS_NEWCENT_E_SZ (sizeof(PS_NEWCENT_E) / sizeof(char *))
201 
202 static const char *PS_PALATINO_E[] = {
204 };
205 #define PS_PALATINO_E_SZ (sizeof(PS_PALATINO_E) / sizeof(char *))
206 
207 static const char *PS_TIMES_E[] = {
209 };
210 #define PS_TIMES_E_SZ (sizeof(PS_TIMES_E) / sizeof(char *))
211 
212 static const char *PS_SYMBOL_E[] = { SYM_1, SYM_2, SYM_3, SYM_4 };
213 #define PS_SYMBOL_E_SZ (sizeof(PS_SYMBOL_E) / sizeof(char *))
214 
215 static const char *PS_CHANCERY_E[] = {
217 };
218 #define PS_CHANCERY_E_SZ (sizeof(PS_CHANCERY_E) / sizeof(char *))
219 
220 static const char *PS_DINGBATS_E[] = { DING_1, SYM_1, SYM_2, SYM_3, SYM_4 };
221 #define PS_DINGBATS_E_SZ (sizeof(PS_DINGBATS_E) / sizeof(char *))
222 
223 typedef struct {
225  char *fontname;
226  int eq_sz;
227  const char **equiv;
228 } fontdef_t;
229 
230 /* array of recognized Graphviz PS font names */
231 static fontdef_t gv_ps_fontdefs[] = {
232  { SAN_0, PS_AVANTGARDE, PS_AVANT_E_SZ, PS_AVANT_E},
233  { SER_0, PS_BOOKMAN, PS_BOOKMAN_E_SZ, PS_BOOKMAN_E},
234  { MON_0, PS_COURIER, PS_COURIER_E_SZ, PS_COURIER_E},
235  { SAN_0, PS_HELVETICA, PS_HELVETICA_E_SZ, PS_HELVETICA_E},
236  { SER_0, PS_NEWCENTURYSCHLBK, PS_NEWCENT_E_SZ, PS_NEWCENT_E},
237  { SER_0, PS_PALATINO, PS_PALATINO_E_SZ, PS_PALATINO_E},
238  { SYM_0, PS_SYMBOL, PS_SYMBOL_E_SZ, PS_SYMBOL_E},
239  { SER_0, PS_TIMES, PS_TIMES_E_SZ, PS_TIMES_E},
240  { SER_0, PS_CHANCERY, PS_CHANCERY_E_SZ, PS_CHANCERY_E},
241  { DING_0, PS_DINGBATS, PS_DINGBATS_E_SZ, PS_DINGBATS_E},
242 };
243 #define GV_FONT_LIST_SIZE (sizeof(gv_ps_fontdefs)/sizeof(fontdef_t))
244 
245 typedef struct {
247  char *fontname;
248  int faces;
249 } availfont_t;
250 
251 #define NEW(t) (t*)malloc(sizeof(t))
252 #define N_NEW(n,t) (t*)malloc((n)*sizeof(t))
253 
254 static PostscriptAlias postscript_alias[] = {
255 #include "ps_font_equiv.h"
256 };
257 
258 /* Frees memory used by the available system font definitions */
259 static void gv_flist_free_af(availfont_t* gv_af_p)
260 {
261  int i;
262 
263  for (i = 0; i < GV_FONT_LIST_SIZE; i++) {
264  if (gv_af_p[i].fontname)
265  free(gv_af_p[i].fontname);
266  }
267  free(gv_af_p);
268 }
269 
270 static int get_faces(PangoFontFamily * family)
271 {
272  PangoFontFace **faces;
273  PangoFontFace *face;
274  int i, j, n_faces;
275  const char *name;
276  int availfaces = 0;
277  /* Get the faces (Bold, Italic, etc.) for the current font family */
278  pango_font_family_list_faces(family, &faces, &n_faces);
279  for (i = 0; i < n_faces; i++) {
280  face = faces[i];
281  name = pango_font_face_get_face_name(face);
282 
283  /* if the family face type is one of the known types, logically OR the known type value
284  to the available faces integer */
285  for (j = 0; j < FACELIST_SZ; j++) {
286  if (strcasestr(name, facelist[j].name)) {
287  availfaces |= facelist[j].flag;
288  break;
289  }
290  }
291  }
292  g_free(faces);
293  return availfaces;
294 }
295 
296 #ifdef DEBUG
297 static void
298 display_available_fonts(availfont_t* gv_af_p)
299 {
300  int i, j, faces;
301 
302 /* Displays the Graphviz PS font name, system available font name and associated faces */
303  for (j = 0; j < GV_FONT_LIST_SIZE; j++) {
304  if ((gv_af_p[j].faces == 0) || (gv_af_p[j].fontname == NULL)) {
305  fprintf (stderr, "ps font = %s not available\n", gv_ps_fontdefs[j].fontname);
306  continue;
307  }
308  fprintf (stderr, "ps font = %s available %d font = %s\n",
309  gv_ps_fontdefs[j].fontname, gv_af_p[j].faces, gv_af_p[j].fontname);
310  faces = gv_af_p[j].faces;
311  for (i = 0; i < FACELIST_SZ; i++) {
312  if (faces & facelist[i].flag)
313  fprintf (stderr, "\t%s\n", facelist[i].name);
314  }
315  }
316 }
317 #endif
318 
319 /* Construct the list of font faces */
320 static char *get_avail_faces(int faces, agxbuf* xb)
321 {
322  int i;
323  for (i = 0; i < FACELIST_SZ; i++) {
324  if (faces & facelist[i].flag) {
325  agxbput (xb, facelist[i].name);
326  agxbputc(xb, ' ');
327  }
328  }
329  return agxbuse (xb);
330 }
331 
332 
333 /* This function creates an array of font definitions. Each entry corresponds to one of
334  the Graphviz PS fonts. The font definitions contain the generic font name and a list
335  of equivalent fonts that can be used in place of the PS font if the PS font is not
336  available on the system
337 */
338 static availfont_t *gv_get_ps_fontlist(PangoFontMap * fontmap)
339 {
340  PangoFontFamily **families;
341  PangoFontFamily *family;
342  fontdef_t* gv_ps_fontdef;
343  int n_families;
344  int i, j, k, array_sz, availfaces;
345  availfont_t *gv_af_p, *gv_afs;
346  const char *name;
347  char *family_name;
348 
349  /* Get a list of font families installed on the system */
350  pango_font_map_list_families(fontmap, &families, &n_families);
351 
352  /* Setup a pointer to available font structs */
353  gv_af_p = N_NEW(GV_FONT_LIST_SIZE, availfont_t);
354 
355  for (j = 0; j < GV_FONT_LIST_SIZE; j++) {
356  /* get the Graphviz PS font information and create the
357  available font definition structs */
358  gv_afs = gv_af_p+j;
359  gv_ps_fontdef = gv_ps_fontdefs+j;
360  gv_afs->gv_ps_fontname = gv_ps_fontdef->fontname;
361  family_name = NULL;
362  /* Search the installed system font families for the current
363  Graphvis PS font family name, i.e. AvantGarde */
364  for (i = 0; i < n_families; i++) {
365  family = families[i];
366  name = pango_font_family_get_name(family);
367  /* if a match is found get the installed font faces */
368  if (strcasecmp(gv_ps_fontdef->fontname, name) == 0) {
369  family_name = strdup(name);
370  availfaces = get_faces(family);
371  }
372  if (family_name)
373  break;
374  }
375  /* if a match is not found on the primary Graphviz font family,
376  search for a match on the equivalent font family names */
377  if (!family_name) {
378  array_sz = gv_ps_fontdef->eq_sz;
379  for (k = 0; k < array_sz; k++) {
380  for (i = 0; i < n_families; i++) {
381  family = families[i];
382  name = pango_font_family_get_name(family);
383  if (strcasecmp(gv_ps_fontdef->equiv[k], name) == 0) {
384  family_name = strdup(name);
385  availfaces = get_faces(family);
386  break;
387  }
388  }
389  if (family_name)
390  break;
391  }
392  }
393  /* if a match is not found on the equivalent font family names, search
394  for a match on the generic family name assigned to the Graphviz PS font */
395  if (!family_name) {
396  for (i = 0; i < n_families; i++) {
397  family = families[i];
398  name = pango_font_family_get_name(family);
399  if (strcasecmp(gv_ps_fontdef->generic_name, name) == 0) {
400  family_name = strdup(name);
401  availfaces = get_faces(family);
402  break;
403  }
404  }
405  }
406  /* if not match is found on the generic name, set the available font
407  name to NULL */
408  if (family_name && availfaces) {
409  gv_afs->fontname = family_name;
410  gv_afs->faces = availfaces;
411  } else {
412  gv_afs->fontname = NULL;
413  gv_afs->faces = 0;
414  }
415  }
416  g_free(families);
417 #ifdef DEBUG
418  display_available_fonts(gv_af_p);
419 #endif
420 /* Free the Graphviz PS font definitions */
421  return (gv_af_p);
422 }
423 
424 static void copyUpper (agxbuf* xb, char* s)
425 {
426  int c;
427 
428  while ((c = *s++))
429  (void)agxbputc (xb, toupper(c));
430 }
431 
432 /* Returns the font corresponding to a Graphviz PS font.
433  AvantGarde-Book may return URW Gothic L, book
434  Returns NULL if no appropriate font found.
435 */
436 static char *gv_get_font(availfont_t* gv_af_p,
437  PostscriptAlias * ps_alias, agxbuf* xb, agxbuf *xb2)
438 {
439  char *avail_faces;
440  int i;
441 
442  for (i = 0; i < GV_FONT_LIST_SIZE; i++) {
443  /* Searches the array of available system fonts for the one that
444  corresponds to the current Graphviz PS font name. Sets up the
445  font string with the available font name and the installed font
446  faces that match what are required by the Graphviz PS font.
447  */
448  if (gv_af_p[i].faces && strstr(ps_alias->name, gv_af_p[i].gv_ps_fontname)) {
449  agxbput(xb2, gv_af_p[i].fontname);
450  agxbput(xb2, ", ");
451  avail_faces = get_avail_faces(gv_af_p[i].faces, xb);
452  if (ps_alias->weight) {
453  if (strcasestr(avail_faces, ps_alias->weight)) {
454  agxbputc(xb2, ' ');
455  copyUpper(xb2, ps_alias->weight);
456  }
457  } else if (strcasestr(avail_faces, "REGULAR")) {
458  agxbputc(xb2, ' ');
459  agxbput(xb2, "REGULAR");
460  } else if (strstr(avail_faces, "ROMAN")) {
461  agxbputc(xb2, ' ');
462  agxbput(xb2, "ROMAN");
463  }
464  if (ps_alias->stretch) {
465  if (strcasestr(avail_faces, ps_alias->stretch)) {
466  agxbputc(xb2, ' ');
467  copyUpper(xb2, ps_alias->stretch);
468  }
469  }
470  if (ps_alias->style) {
471  if (strcasestr(avail_faces, ps_alias->style)) {
472  agxbputc(xb2, ' ');
473  copyUpper(xb2, ps_alias->style);
474  } else if (!strcasecmp(ps_alias->style, "ITALIC")) {
475  /* try to use ITALIC in place of OBLIQUE & visa versa */
476  if (strcasestr(avail_faces, "OBLIQUE")) {
477  agxbputc(xb2, ' ');
478  agxbput(xb2, "OBLIQUE");
479  }
480  } else if (!strcasecmp(ps_alias->style, "OBLIQUE")) {
481  if (strcasestr(avail_faces, "ITALIC")) {
482  agxbputc(xb2, ' ');
483  agxbput(xb2, "ITALIC");
484  }
485  }
486  }
487  return strdup(agxbuse(xb2));
488  }
489  }
490  return NULL;
491 }
492 
493 static void
494 printFontMap (gv_font_map*gv_fmap, int sz)
495 {
496  int j;
497  char* font;
498 
499  for (j = 0; j < sz; j++) {
500  font = gv_fmap[j].gv_font;
501  if (!font)
502  fprintf (stderr, " [%d] %s => <Not available>\n", j, gv_fmap[j].gv_ps_fontname);
503  else
504  fprintf (stderr, " [%d] %s => \"%s\"\n", j, gv_fmap[j].gv_ps_fontname, font);
505  }
506 }
507 
508 /* Sets up a structure array that contains the Graphviz PS font name
509  and the corresponding installed font string.
510 */
511 gv_font_map* get_font_mapping(PangoFontMap * fontmap)
512 {
513  PostscriptAlias *ps_alias;
514  availfont_t *gv_af_p;
515  int j, ps_fontnames_sz = sizeof(postscript_alias) / sizeof(PostscriptAlias);
516  gv_font_map* gv_fmap = N_NEW(ps_fontnames_sz, gv_font_map);
517  agxbuf xb;
518  agxbuf xb2;
519  unsigned char buf[BUFSIZ];
520  unsigned char buf2[BUFSIZ];
521 
522  agxbinit(&xb, BUFSIZ, buf);
523  agxbinit(&xb2, BUFSIZ, buf2);
524  gv_af_p = gv_get_ps_fontlist(fontmap); // get the available installed fonts
525  /* add the Graphviz PS font name and available system font string to the array */
526  for (j = 0; j < ps_fontnames_sz; j++) {
527  ps_alias = &postscript_alias[j];
528  gv_fmap[ps_alias->xfig_code].gv_ps_fontname = ps_alias->name;
529  gv_fmap[ps_alias->xfig_code].gv_font = gv_get_font(gv_af_p, ps_alias, &xb, &xb2);
530  }
531  gv_flist_free_af(gv_af_p);
532  agxbfree(&xb);
533  agxbfree(&xb2);
534 #ifndef WIN32
535  if (Verbose > 1)
536  printFontMap (gv_fmap, ps_fontnames_sz);
537 #endif
538  return gv_fmap;
539 }
540 
541 /* Returns a list of the fonts that are available for use
542 
543 */
544 
545 void get_font_list(char **fonts[], int *cnt){
546 
547 PangoFontMap *fontmap;
548 availfont_t *gv_af_p;
549 int j, i;
550 char **fontlist;
551 fontlist = N_NEW(GV_FONT_LIST_SIZE,char *);
552 fontmap = pango_cairo_font_map_new();
553 gv_af_p = gv_get_ps_fontlist(fontmap); // get the available installed fonts
554 g_object_unref(fontmap);
555 /* load array with available font names */
556 i=0;
557 for (j = 0; j < GV_FONT_LIST_SIZE; j++) {
558  *(fontlist + j) = 0;
559  if ((gv_af_p[j].faces == 0) || (gv_af_p[j].fontname == NULL)) {
560  continue;
561  }
562  *(fontlist + i++) = strdup(gv_af_p[j].fontname);
563 }
564 /* Free unused array elements */
565 for(j=i;j<GV_FONT_LIST_SIZE;j++){
566  free(*(fontlist + j));
567 }
568 /* Free available fonts structure */
569 gv_flist_free_af(gv_af_p);
570 
571 *cnt = i;
572 *fonts = fontlist;
573 return;
574 }