gvgetfontlist_pango.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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. #include "config.h"
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <cgraph/gv_ctype.h>
  16. #include <cgraph/strview.h>
  17. #include <util/agxbuf.h>
  18. #include <util/alloc.h>
  19. #include <util/prisize_t.h>
  20. #include <util/strcasecmp.h>
  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. #endif
  51. #include <gvc/gvplugin_textlayout.h>
  52. #include <pango/pangocairo.h>
  53. #include "gvgetfontlist.h"
  54. #include <common/globals.h>
  55. #define FNT_BOLD 1<<0
  56. #define FNT_BOOK 1<<1
  57. #define FNT_CONDENSED 1<<2
  58. #define FNT_DEMI 1<<3
  59. #define FNT_EXTRALIGHT 1<<4
  60. #define FNT_ITALIC 1<<5
  61. #define FNT_LIGHT 1<<6
  62. #define FNT_MEDIUM 1<<7
  63. #define FNT_OBLIQUE 1<<8
  64. #define FNT_REGULAR 1<<9
  65. #define FNT_ROMAN 1<<9
  66. #define PS_AVANTGARDE "AvantGarde"
  67. #define PS_BOOKMAN "Bookman"
  68. #define PS_COURIER "Courier"
  69. #define PS_HELVETICA SAN_5
  70. #define PS_NEWCENTURYSCHLBK "NewCenturySchlbk"
  71. #define PS_PALATINO "Palatino"
  72. #define PS_SYMBOL "Symbol"
  73. #define PS_TIMES SER_3
  74. #define PS_CHANCERY "ZapfChancery"
  75. #define PS_DINGBATS "ZapfDingbats"
  76. #define FNT_BOLD_ST "BOLD"
  77. #define FNT_BOOK_ST "BOOK"
  78. #define FNT_CONDENSED_ST "CONDENSED"
  79. #define FNT_DEMI_ST "DEMI"
  80. #define FNT_EXTRALIGHT_ST "EXTRALIGHT"
  81. #define FNT_ITALIC_ST "ITALIC"
  82. #define FNT_LIGHT_ST "LIGHT"
  83. #define FNT_MEDIUM_ST "MEDIUM"
  84. #define FNT_OBLIQUE_ST "OBLIQUE"
  85. #define FNT_REGULAR_ST "REGULAR"
  86. #define FNT_ROMAN_ST "ROMAN"
  87. #define SAN_0 "sans"
  88. #define SAN_1 "URW Gothic L"
  89. #define SAN_2 "Charcoal"
  90. #define SAN_3 "Nimbus Sans L"
  91. #define SAN_4 "Verdana"
  92. #define SAN_5 "Helvetica"
  93. #define SAN_6 "Bitstream Vera Sans"
  94. #define SAN_7 "DejaVu Sans"
  95. #define SAN_8 "Liberation Sans"
  96. #define SAN_9 "Luxi Sans"
  97. #define SAN_10 "FreeSans"
  98. #define SAN_11 "Arial"
  99. #define SER_0 "serif"
  100. #define SER_1 "URW Bookman L"
  101. #define SER_2 "Times New Roman"
  102. #define SER_3 "Times"
  103. #define SER_4 "Nimbus Roman No9 L"
  104. #define SER_5 "Bitstream Vera Serif"
  105. #define SER_6 "DejaVu Serif"
  106. #define SER_7 "Liberation Serif"
  107. #define SER_8 "Luxi Serif"
  108. #define SER_9 "FreeSerif"
  109. #define SER_10 "Century Schoolbook L"
  110. #define SER_11 "Charcoal"
  111. #define SER_12 "Georgia"
  112. #define SER_13 "URW Palladio L"
  113. #define SER_14 "Norasi"
  114. #define SER_15 "Rekha"
  115. #define SER_16 "URW Chancery L"
  116. #define MON_0 "monospace"
  117. #define MON_1 "Nimbus Mono L"
  118. #define MON_2 "Inconsolata"
  119. #define MON_3 "Courier New"
  120. #define MON_4 "Bitstream Vera Sans Mono"
  121. #define MON_5 "DejaVu Sans Mono"
  122. #define MON_6 "Liberation Mono"
  123. #define MON_7 "Luxi Mono"
  124. #define MON_8 "FreeMono"
  125. #define SYM_0 "fantasy"
  126. #define SYM_1 "Impact"
  127. #define SYM_2 "Copperplate Gothic Std"
  128. #define SYM_3 "Cooper Std"
  129. #define SYM_4 "Bauhaus Std"
  130. #define DING_0 "fantasy"
  131. #define DING_1 "Dingbats"
  132. #define DING_2 "Impact"
  133. #define DING_3 "Copperplate Gothic Std"
  134. #define DING_4 "Cooper Std"
  135. #define DING_5 "Bauhaus Std"
  136. typedef struct {
  137. int flag;
  138. char* name;
  139. } face_t;
  140. static face_t facelist[] = {
  141. { FNT_BOLD, FNT_BOLD_ST},
  142. { FNT_BOOK, FNT_BOOK_ST},
  143. { FNT_CONDENSED, FNT_CONDENSED_ST},
  144. { FNT_DEMI, FNT_DEMI_ST},
  145. { FNT_EXTRALIGHT, FNT_EXTRALIGHT_ST},
  146. { FNT_ITALIC, FNT_ITALIC_ST},
  147. { FNT_LIGHT, FNT_LIGHT_ST},
  148. { FNT_MEDIUM, FNT_MEDIUM_ST},
  149. { FNT_OBLIQUE, FNT_OBLIQUE_ST},
  150. { FNT_REGULAR, FNT_REGULAR_ST},
  151. { FNT_ROMAN, FNT_ROMAN_ST},
  152. };
  153. #define FACELIST_SZ (sizeof(facelist)/sizeof(face_t))
  154. /* This is where the hierarchy of equivalent fonts is established. The order can be changed
  155. here or new equivalent fonts can be added here. Each font family used by the Graphviz
  156. PS fonts is set up.
  157. */
  158. static const char *PS_AVANT_E[] = {
  159. SAN_1, SAN_2, SAN_3, SAN_4, SAN_5, SAN_6, SAN_7, SAN_8, SAN_9, SAN_10
  160. };
  161. #define PS_AVANT_E_SZ (sizeof(PS_AVANT_E) / sizeof(char *))
  162. static const char *PS_BOOKMAN_E[] = {
  163. SER_1, SER_2, SER_3, SER_4, SER_5, SER_6, SER_7, SER_8, SER_9
  164. };
  165. #define PS_BOOKMAN_E_SZ (sizeof(PS_BOOKMAN_E) / sizeof(char *))
  166. static const char *PS_COURIER_E[] = {
  167. MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8
  168. };
  169. #define PS_COURIER_E_SZ (sizeof(PS_COURIER_E) / sizeof(char *))
  170. static const char *PS_HELVETICA_E[] = {
  171. SAN_3, SAN_11, SAN_4, SAN_6, SAN_7, SAN_8, SAN_9, SAN_10
  172. };
  173. #define PS_HELVETICA_E_SZ (sizeof(PS_HELVETICA_E) / sizeof(char *))
  174. static const char *PS_NEWCENT_E[] = {
  175. SER_10, SER_2, SER_3, SER_4, SER_12, SER_5, SER_6, SER_7, SER_8, SER_9
  176. };
  177. #define PS_NEWCENT_E_SZ (sizeof(PS_NEWCENT_E) / sizeof(char *))
  178. static const char *PS_PALATINO_E[] = {
  179. SER_13, SER_2, SER_3, SER_4, SER_14, SER_15, SER_5, SER_6, SER_7, SER_8, SER_9
  180. };
  181. #define PS_PALATINO_E_SZ (sizeof(PS_PALATINO_E) / sizeof(char *))
  182. static const char *PS_TIMES_E[] = {
  183. SER_4, SER_2, SER_11, SER_5, SER_6, SER_7, SER_8, SER_9
  184. };
  185. #define PS_TIMES_E_SZ (sizeof(PS_TIMES_E) / sizeof(char *))
  186. static const char *PS_SYMBOL_E[] = { SYM_1, SYM_2, SYM_3, SYM_4 };
  187. #define PS_SYMBOL_E_SZ (sizeof(PS_SYMBOL_E) / sizeof(char *))
  188. static const char *PS_CHANCERY_E[] = {
  189. SER_16, SER_11, SER_2, SER_3, SER_4, SER_5, SER_6, SER_7, SER_8, SER_9
  190. };
  191. #define PS_CHANCERY_E_SZ (sizeof(PS_CHANCERY_E) / sizeof(char *))
  192. static const char *PS_DINGBATS_E[] = { DING_1, SYM_1, SYM_2, SYM_3, SYM_4 };
  193. #define PS_DINGBATS_E_SZ (sizeof(PS_DINGBATS_E) / sizeof(char *))
  194. typedef struct {
  195. char *generic_name;
  196. char *fontname;
  197. int eq_sz;
  198. const char **equiv;
  199. } fontdef_t;
  200. /* array of recognized Graphviz PS font names */
  201. static fontdef_t gv_ps_fontdefs[] = {
  202. { SAN_0, PS_AVANTGARDE, PS_AVANT_E_SZ, PS_AVANT_E},
  203. { SER_0, PS_BOOKMAN, PS_BOOKMAN_E_SZ, PS_BOOKMAN_E},
  204. { MON_0, PS_COURIER, PS_COURIER_E_SZ, PS_COURIER_E},
  205. { SAN_0, PS_HELVETICA, PS_HELVETICA_E_SZ, PS_HELVETICA_E},
  206. { SER_0, PS_NEWCENTURYSCHLBK, PS_NEWCENT_E_SZ, PS_NEWCENT_E},
  207. { SER_0, PS_PALATINO, PS_PALATINO_E_SZ, PS_PALATINO_E},
  208. { SYM_0, PS_SYMBOL, PS_SYMBOL_E_SZ, PS_SYMBOL_E},
  209. { SER_0, PS_TIMES, PS_TIMES_E_SZ, PS_TIMES_E},
  210. { SER_0, PS_CHANCERY, PS_CHANCERY_E_SZ, PS_CHANCERY_E},
  211. { DING_0, PS_DINGBATS, PS_DINGBATS_E_SZ, PS_DINGBATS_E},
  212. };
  213. #define GV_FONT_LIST_SIZE (sizeof(gv_ps_fontdefs)/sizeof(fontdef_t))
  214. typedef struct {
  215. char *gv_ps_fontname;
  216. char *fontname;
  217. int faces;
  218. } availfont_t;
  219. /// list of available fonts
  220. ///
  221. /// The i-th entry corresponds to the i-th entry from \p gv_ps_fontdefs. An
  222. /// entry will have zeroed fields if the corresponding font is unavailable at
  223. /// runtime.
  224. typedef struct {
  225. availfont_t fonts[GV_FONT_LIST_SIZE];
  226. } availfonts_t;
  227. static PostscriptAlias postscript_alias[] = {
  228. #include "ps_font_equiv.h"
  229. };
  230. /* Frees memory used by the available system font definitions */
  231. static void gv_flist_free_af(availfonts_t gv_af_p) {
  232. for (size_t i = 0; i < GV_FONT_LIST_SIZE; i++) {
  233. free(gv_af_p.fonts[i].fontname);
  234. }
  235. }
  236. static int get_faces(PangoFontFamily * family)
  237. {
  238. PangoFontFace **faces;
  239. PangoFontFace *face;
  240. int i, n_faces;
  241. const char *name;
  242. int availfaces = 0;
  243. /* Get the faces (Bold, Italic, etc.) for the current font family */
  244. pango_font_family_list_faces(family, &faces, &n_faces);
  245. for (i = 0; i < n_faces; i++) {
  246. face = faces[i];
  247. name = pango_font_face_get_face_name(face);
  248. /* if the family face type is one of the known types, logically OR the known type value
  249. to the available faces integer */
  250. for (size_t j = 0; j < FACELIST_SZ; j++) {
  251. if (strcasestr(name, facelist[j].name)) {
  252. availfaces |= facelist[j].flag;
  253. break;
  254. }
  255. }
  256. }
  257. g_free(faces);
  258. return availfaces;
  259. }
  260. #ifdef DEBUG
  261. static void
  262. display_available_fonts(availfonts_t gv_af_p) {
  263. int faces;
  264. /* Displays the Graphviz PS font name, system available font name and associated faces */
  265. for (size_t j = 0; j < GV_FONT_LIST_SIZE; j++) {
  266. if (gv_af_p.fonts[j].faces == 0 || gv_af_p.fonts[j].fontname == NULL) {
  267. fprintf (stderr, "ps font = %s not available\n", gv_ps_fontdefs[j].fontname);
  268. continue;
  269. }
  270. fprintf (stderr, "ps font = %s available %d font = %s\n",
  271. gv_ps_fontdefs[j].fontname, gv_af_p.fonts[j].faces,
  272. gv_af_p.fonts[j].fontname);
  273. faces = gv_af_p.fonts[j].faces;
  274. for (size_t i = 0; i < FACELIST_SZ; i++) {
  275. if (faces & facelist[i].flag)
  276. fprintf (stderr, "\t%s\n", facelist[i].name);
  277. }
  278. }
  279. }
  280. #endif
  281. /* Construct the list of font faces */
  282. static char *get_avail_faces(int faces, agxbuf* xb)
  283. {
  284. for (size_t i = 0; i < FACELIST_SZ; i++) {
  285. if (faces & facelist[i].flag) {
  286. agxbprint (xb, "%s ", facelist[i].name);
  287. }
  288. }
  289. return agxbuse (xb);
  290. }
  291. /* This function creates an array of font definitions. Each entry corresponds to one of
  292. the Graphviz PS fonts. The font definitions contain the generic font name and a list
  293. of equivalent fonts that can be used in place of the PS font if the PS font is not
  294. available on the system
  295. */
  296. static availfonts_t gv_get_ps_fontlist(PangoFontMap *fontmap) {
  297. PangoFontFamily **families;
  298. PangoFontFamily *family;
  299. fontdef_t* gv_ps_fontdef;
  300. int n_families;
  301. int i, k, array_sz, availfaces = 0;
  302. const char *name;
  303. /* Get a list of font families installed on the system */
  304. pango_font_map_list_families(fontmap, &families, &n_families);
  305. availfonts_t gv_af_p = {0};
  306. for (size_t j = 0; j < GV_FONT_LIST_SIZE; j++) {
  307. /* get the Graphviz PS font information and create the
  308. available font definition structs */
  309. availfont_t *gv_afs = &gv_af_p.fonts[j];
  310. gv_ps_fontdef = gv_ps_fontdefs+j;
  311. gv_afs->gv_ps_fontname = gv_ps_fontdef->fontname;
  312. strview_t family_name = {0};
  313. /* Search the installed system font families for the current
  314. Graphvis PS font family name, i.e. AvantGarde */
  315. for (i = 0; i < n_families; i++) {
  316. family = families[i];
  317. name = pango_font_family_get_name(family);
  318. /* if a match is found get the installed font faces */
  319. if (strcasecmp(gv_ps_fontdef->fontname, name) == 0) {
  320. family_name = strview(name, '\0');
  321. availfaces = get_faces(family);
  322. }
  323. if (family_name.data != NULL)
  324. break;
  325. }
  326. /* if a match is not found on the primary Graphviz font family,
  327. search for a match on the equivalent font family names */
  328. if (family_name.data == NULL) {
  329. array_sz = gv_ps_fontdef->eq_sz;
  330. for (k = 0; k < array_sz; k++) {
  331. for (i = 0; i < n_families; i++) {
  332. family = families[i];
  333. name = pango_font_family_get_name(family);
  334. if (strcasecmp(gv_ps_fontdef->equiv[k], name) == 0) {
  335. family_name = strview(name, '\0');
  336. availfaces = get_faces(family);
  337. break;
  338. }
  339. }
  340. if (family_name.data != NULL)
  341. break;
  342. }
  343. }
  344. /* if a match is not found on the equivalent font family names, search
  345. for a match on the generic family name assigned to the Graphviz PS font */
  346. if (family_name.data == NULL) {
  347. for (i = 0; i < n_families; i++) {
  348. family = families[i];
  349. name = pango_font_family_get_name(family);
  350. if (strcasecmp(gv_ps_fontdef->generic_name, name) == 0) {
  351. family_name = strview(name, '\0');
  352. availfaces = get_faces(family);
  353. break;
  354. }
  355. }
  356. }
  357. /* if not match is found on the generic name, set the available font
  358. name to NULL */
  359. if (family_name.data != NULL && availfaces) {
  360. gv_afs->fontname = strview_str(family_name);
  361. gv_afs->faces = availfaces;
  362. } else {
  363. gv_afs->fontname = NULL;
  364. gv_afs->faces = 0;
  365. }
  366. }
  367. g_free(families);
  368. #ifdef DEBUG
  369. display_available_fonts(gv_af_p);
  370. #endif
  371. /* Free the Graphviz PS font definitions */
  372. return gv_af_p;
  373. }
  374. static void copyUpper (agxbuf* xb, char* s)
  375. {
  376. int c;
  377. while ((c = *s++))
  378. (void)agxbputc(xb, gv_toupper(c));
  379. }
  380. /* Returns the font corresponding to a Graphviz PS font.
  381. AvantGarde-Book may return URW Gothic L, book
  382. Returns NULL if no appropriate font found.
  383. */
  384. static char *gv_get_font(availfonts_t gv_af_p,
  385. PostscriptAlias * ps_alias, agxbuf* xb, agxbuf *xb2)
  386. {
  387. char *avail_faces;
  388. for (size_t i = 0; i < GV_FONT_LIST_SIZE; i++) {
  389. /* Searches the array of available system fonts for the one that
  390. corresponds to the current Graphviz PS font name. Sets up the
  391. font string with the available font name and the installed font
  392. faces that match what are required by the Graphviz PS font.
  393. */
  394. if (gv_af_p.fonts[i].faces &&
  395. strstr(ps_alias->name, gv_af_p.fonts[i].gv_ps_fontname)) {
  396. agxbprint(xb2, "%s, ", gv_af_p.fonts[i].fontname);
  397. avail_faces = get_avail_faces(gv_af_p.fonts[i].faces, xb);
  398. if (ps_alias->weight) {
  399. if (strcasestr(avail_faces, ps_alias->weight)) {
  400. agxbputc(xb2, ' ');
  401. copyUpper(xb2, ps_alias->weight);
  402. }
  403. } else if (strcasestr(avail_faces, "REGULAR")) {
  404. agxbput(xb2, " REGULAR");
  405. } else if (strstr(avail_faces, "ROMAN")) {
  406. agxbput(xb2, " ROMAN");
  407. }
  408. if (ps_alias->stretch) {
  409. if (strcasestr(avail_faces, ps_alias->stretch)) {
  410. agxbputc(xb2, ' ');
  411. copyUpper(xb2, ps_alias->stretch);
  412. }
  413. }
  414. if (ps_alias->style) {
  415. if (strcasestr(avail_faces, ps_alias->style)) {
  416. agxbputc(xb2, ' ');
  417. copyUpper(xb2, ps_alias->style);
  418. } else if (!strcasecmp(ps_alias->style, "ITALIC")) {
  419. /* try to use ITALIC in place of OBLIQUE & visa versa */
  420. if (strcasestr(avail_faces, "OBLIQUE")) {
  421. agxbput(xb2, " OBLIQUE");
  422. }
  423. } else if (!strcasecmp(ps_alias->style, "OBLIQUE")) {
  424. if (strcasestr(avail_faces, "ITALIC")) {
  425. agxbput(xb2, " ITALIC");
  426. }
  427. }
  428. }
  429. return agxbdisown(xb2);
  430. }
  431. }
  432. return NULL;
  433. }
  434. static void printFontMap(gv_font_map *gv_fmap, size_t sz) {
  435. char* font;
  436. for (size_t j = 0; j < sz; j++) {
  437. font = gv_fmap[j].gv_font;
  438. if (!font)
  439. fprintf(stderr, " [%" PRISIZE_T "] %s => <Not available>\n", j,
  440. gv_fmap[j].gv_ps_fontname);
  441. else
  442. fprintf(stderr, " [%" PRISIZE_T "] %s => \"%s\"\n", j,
  443. gv_fmap[j].gv_ps_fontname, font);
  444. }
  445. }
  446. /* Sets up a structure array that contains the Graphviz PS font name
  447. and the corresponding installed font string.
  448. */
  449. gv_font_map* get_font_mapping(PangoFontMap * fontmap)
  450. {
  451. PostscriptAlias *ps_alias;
  452. static const size_t ps_fontnames_sz =
  453. sizeof(postscript_alias) / sizeof(PostscriptAlias);
  454. gv_font_map* gv_fmap = gv_calloc(ps_fontnames_sz, sizeof(gv_font_map));
  455. agxbuf xb = {0};
  456. agxbuf xb2 = {0};
  457. availfonts_t gv_af_p = gv_get_ps_fontlist(fontmap); // get the available installed fonts
  458. /* add the Graphviz PS font name and available system font string to the array */
  459. for (size_t j = 0; j < ps_fontnames_sz; j++) {
  460. ps_alias = &postscript_alias[j];
  461. gv_fmap[ps_alias->xfig_code].gv_ps_fontname = ps_alias->name;
  462. gv_fmap[ps_alias->xfig_code].gv_font = gv_get_font(gv_af_p, ps_alias, &xb, &xb2);
  463. }
  464. gv_flist_free_af(gv_af_p);
  465. agxbfree(&xb);
  466. agxbfree(&xb2);
  467. if (Verbose > 1) {
  468. fprintf(stderr, "Verbose %d\n", Verbose);
  469. printFontMap (gv_fmap, ps_fontnames_sz);
  470. }
  471. return gv_fmap;
  472. }