ARB
AW_xfont.cxx
Go to the documentation of this file.
1 /* FIG : Facility for Interactive Generation of figures
2  * Copyright (c) 1985 by Supoj Sutanthavibul
3  * Copyright (c) 1992 by Brian V. Smith
4  *
5  * "Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both the copyright
8  * notice and this permission notice appear in supporting documentation.
9  * No representations are made about the suitability of this software for
10  * any purpose. It is provided "as is" without express or implied warranty."
11  *
12  * This software has been widely modified for usage inside ARB.
13  */
14 
15 #include "aw_xfont.hxx"
16 #include "aw_root.hxx"
17 
18 #include <arbdb.h>
19 
20 #include <cctype>
21 
22 // --------------------------------------------------------------------------------
23 
24 #define FONT_EXAMINE_MAX 5000
25 #define KNOWN_ISO_VERSIONS 3
26 
27 #if !defined(DEVEL_RELEASE)
28 // #define DUMP_FONT_LOOKUP
29 // #define DUMP_FONT_DETAILS
30 #endif
31 
32 // --------------------------------------------------------------------------------
33 
34 typedef XFontStruct *PIX_FONT;
35 
36 static bool openwinfonts;
37 static bool is_scalable[AW_NUM_FONTS]; // whether the font is scalable
38 
39 // defines the preferred xfontsel-'rgstry' values (most wanted first)
40 
41 #define PREFER_ISO10646
42 
43 #if defined(DEVEL_RALF)
44 #if defined(PREFER_ISO10646)
45 // #warning current iso setting: prefer ISO10646 (this is recommended)
46 #else
47 #warning current iso setting: prefer ISO8859
48 #endif // PREFER_ISO10646
49 #endif // DEVEL_RALF
50 
51 #if defined(PREFER_ISO10646)
52 static const char *known_iso_versions[KNOWN_ISO_VERSIONS] = { "ISO10646", "ISO8859", "*" };
53 #else
54 static const char *known_iso_versions[KNOWN_ISO_VERSIONS] = { "ISO8859", "ISO10646", "*" };
55 #endif
56 
57 static struct _xfstruct x_fontinfo[] = {
58  { "-adobe-times-medium-r-*--", "Times", NULp }, // #0
59  { "-adobe-times-medium-i-*--", "Times I", NULp }, // #1
60  { "-adobe-times-bold-r-*--", "Times B", NULp }, // #2
61  { "-adobe-times-bold-i-*--", "Times IB", NULp }, // #3
62  { "-schumacher-clean-medium-r-*--", "Schumacher", NULp }, // closest to Avant-Garde
63  { "-schumacher-clean-medium-i-*--", "Schumacher I", NULp }, // #5
64  { "-schumacher-clean-bold-r-*--", "Schumacher B", NULp }, // #6
65  { "-schumacher-clean-bold-i-*--", "Schumacher IB", NULp }, // #7
66  { "-*-urw bookman l-medium-r-*--", "Bookman", NULp }, // closest to Bookman
67  { "-*-urw bookman l-medium-i-*--", "Bookman I", NULp }, // #9
68  { "-*-urw bookman l-bold-r-*--", "Bookman B", NULp }, // #10
69  { "-*-urw bookman l-bold-i-*--", "Bookman IB", NULp }, // #11
70  { "-adobe-courier-medium-r-*--", "Courier", NULp }, // #12
71  { "-adobe-courier-medium-o-*--", "Courier I", NULp }, // #13
72  { "-adobe-courier-bold-r-*--", "Courier B", NULp }, // #14
73  { "-adobe-courier-bold-o-*--", "Courier IB", NULp }, // #15
74  { "-adobe-helvetica-medium-r-*--", "Helvetica", NULp }, // #16
75  { "-adobe-helvetica-medium-o-*--", "Helvetica I", NULp }, // #17
76  { "-adobe-helvetica-bold-r-*--", "Helvetica B", NULp }, // #18
77  { "-adobe-helvetica-bold-o-*--", "Helvetica IB", NULp }, // #19
78  { "-*-liberation sans narrow-medium-r-*--", "Liberation", NULp }, // closest to Helv-nar.
79  { "-*-liberation sans narrow-medium-o-*--", "Liberation I", NULp }, // #21
80  { "-*-liberation sans narrow-bold-r-*--", "Liberation B", NULp }, // #22
81  { "-*-liberation sans narrow-bold-o-*--", "Liberation IB", NULp }, // #23
82  { "-adobe-new century schoolbook-medium-r-*--", "Schoolbook", NULp }, // #24
83  { "-adobe-new century schoolbook-medium-i-*--", "Schoolbook I", NULp }, // #25
84  { "-adobe-new century schoolbook-bold-r-*--", "Schoolbook B", NULp }, // #26
85  { "-adobe-new century schoolbook-bold-i-*--", "Schoolbook IB", NULp }, // #27
86  { "-*-lucidabright-medium-r-*--", "LucidaBr", NULp }, // closest to Palatino
87  { "-*-lucidabright-medium-i-*--", "LucidaBr I", NULp }, // #29
88  { "-*-lucidabright-demibold-r-*--", "LucidaBr B", NULp }, // #30
89  { "-*-lucidabright-demibold-i-*--", "LucidaBr IB", NULp }, // #31
90  { "-*-symbol-medium-r-*--", "Symbol", NULp }, // #32
91  { "-*-zapfchancery-medium-i-*--", "zapfchancery", NULp }, // #33
92  { "-*-zapfdingbats-*-*-*--", "zapfdingbats", NULp }, // #34
93 
94  // below here are fonts not defined in xfig!
95  // on export, they will be mapped to xfig fonts
96  // (according to ps_fontinfo.xfontnum, i.e. the number behind the postscript fontname below)
97 
98  { "-*-lucida-medium-r-*-*-", "Lucida", NULp }, // #35
99  { "-*-lucida-medium-i-*-*-", "Lucida I", NULp }, // #36
100  { "-*-lucida-bold-r-*-*-", "Lucida B", NULp }, // #37
101  { "-*-lucida-bold-i-*-*-", "Lucida IB", NULp }, // #38
102  { "-*-lucidatypewriter-medium-r-*-*-", "Lucida mono", NULp }, // #39
103  { "-*-lucidatypewriter-bold-r-*-*-", "Lucida mono B", NULp }, // #40
104 
105  { "-*-screen-medium-r-*-*-", "Screen", NULp }, // #41
106  { "-*-screen-bold-r-*-*-", "Screen B", NULp }, // #42
107  { "-*-clean-medium-r-*-*-", "Clean", NULp }, // #43
108  { "-*-clean-bold-r-*-*-", "Clean B", NULp }, // #44
109  { "-*-terminal-medium-r-*-*-", "Terminal", NULp }, // #45
110  { "-*-terminal-bold-r-*-*-", "Terminal B", NULp }, // #46
111 
112  { "-*-dustismo-medium-r-*-*-", "Dustismo", NULp }, // #47
113  { "-*-dustismo-bold-r-*-*-", "Dustismo B", NULp }, // #48
114  { "-*-utopia-medium-r-*-*-", "Utopia", NULp }, // #49
115  { "-*-utopia-bold-r-*-*-", "Utopia B", NULp }, // #50
116  { "-*-dejavu sans-medium-r-*-*-", "Dejavu", NULp }, // #51
117  { "-*-dejavu sans-bold-r-*-*-", "Dejavu B", NULp }, // #52
118 
119  { "-*-fixed-medium-r-*-*-", "Fixed", NULp }, // #53
120  { "-*-fixed-bold-r-*-*-", "Fixed B", NULp }, // #54
121  { "-*-dejavu sans mono-medium-r-*-*-", "Dejavu mono", NULp }, // #55
122  { "-*-dejavu sans mono-bold-r-*-*-", "Dejavu mono B", NULp }, // #56
123  { "-*-luxi mono-medium-r-*-*-", "Luxi mono", NULp }, // #57
124  { "-*-luxi mono-bold-r-*-*-", "Luxi mono B", NULp }, // #58
125  { "-*-nimbus mono l-medium-r-*-*-", "Nimbus mono", NULp }, // #59
126  { "-*-nimbus mono l-bold-r-*-*-", "Nimbus mono B", NULp }, // #60
127  { "-*-latin modern typewriter-medium-r-*-*-", "Latin mono", NULp }, // #61
128  { "-*-latin modern typewriter-bold-r-*-*-", "Latin mono B", NULp }, // #62
129 
130  { "-*-terminus-medium-r-*-*-", "Terminus", NULp }, // #63
131  { "-*-terminus-bold-r-*-*-", "Terminus B", NULp }, // #64
132  { "-sony-fixed-medium-r-*-*-", "SonyFixed", NULp }, // #65
133  { "-sony-fixed-bold-r-*-*-", "SonyFixed B", NULp }, // #66
134  { "-mutt-clearlyu-medium-r-*-*-", "MuttClearlyu", NULp }, // #67
135 };
136 
137 static struct _fstruct ps_fontinfo[] = {
138  // map window fonts to postscript fonts
139  // negative values indicate monospaced fonts
140  { "Default", -1 },
141  { "Times-Roman", 0 },
142  { "Times-Italic", 1 },
143  { "Times-Bold", 2 },
144  { "Times-BoldItalic", 3 },
145  { "AvantGarde-Book", 4 },
146  { "AvantGarde-BookOblique", 5 },
147  { "AvantGarde-Demi", 6 },
148  { "AvantGarde-DemiOblique", 7 },
149  { "Bookman-Light", 8 },
150  { "Bookman-LightItalic", 9 },
151  { "Bookman-Demi", 10 },
152  { "Bookman-DemiItalic", 11 },
153  { "Courier", -12 },
154  { "Courier-Oblique", -13 },
155  { "Courier-Bold", -14 },
156  { "Courier-BoldOblique", -15 },
157  { "Helvetica", 16 },
158  { "Helvetica-Oblique", 17 },
159  { "Helvetica-Bold", 18 },
160  { "Helvetica-BoldOblique", 19 },
161  { "Helvetica-Narrow", 20 },
162  { "Helvetica-Narrow-Oblique", 21 },
163  { "Helvetica-Narrow-Bold", 22 },
164  { "Helvetica-Narrow-BoldOblique", 23 },
165  { "NewCenturySchlbk-Roman", 24 },
166  { "NewCenturySchlbk-Italic", 25 },
167  { "NewCenturySchlbk-Bold", 26 },
168  { "NewCenturySchlbk-BoldItalic", 27 },
169  { "Palatino-Roman", 28 },
170  { "Palatino-Italic", 29 },
171  { "Palatino-Bold", 30 },
172  { "Palatino-BoldItalic", 31 },
173  { "Symbol", 32 },
174  { "ZapfChancery-MediumItalic", 33 },
175  { "ZapfDingbats", 34 },
176 
177  // non xfig-fonts below.
178  // Need to be mapped to best matching xfig font using a font number between 0 and AW_NUM_FONTS_XFIG-1
179 
180  { "LucidaSans", 16 },
181  { "LucidaSans-Italic", 17 },
182  { "LucidaSans-Bold", 18 },
183  { "LucidaSans-BoldItalic", 19 },
184  { "LucidaSansTypewriter", -12 },
185  { "LucidaSansTypewriter-Bold", -14 },
186 
187  { "Screen", -16 },
188  { "Screen-Bold", -18 },
189  { "Clean", -12 },
190  { "Clean-Bold", -14 },
191  { "Terminal", -12 },
192  { "Terminal-Bold", -14 },
193 
194  { "AvantGarde-Book", 4 },
195  { "AvantGarde-Demi", 6 },
196  { "Palatino-Roman", 28 },
197  { "Palatino-Bold", 30 },
198  { "AvantGarde-Book", 4 },
199  { "AvantGarde-Demi", 6 },
200 
201  { "Courier", -12 },
202  { "Courier-Bold", -14 },
203  { "Courier", -12 },
204  { "Courier-Bold", -14 },
205  { "Courier", -12 },
206  { "Courier-Bold", -14 },
207  { "Courier", -12 },
208  { "Courier-Bold", -14 },
209  { "Courier", -12 },
210  { "Courier-Bold", -14 },
211 
212  { "Courier", -12 },
213  { "Courier-Bold", -14 },
214  { "Courier", -12 },
215  { "Courier-Bold", -14 },
216  { "Times-Roman", 0 },
217 };
218 
219 STATIC_ASSERT(ARRAY_ELEMS(x_fontinfo) == AW_NUM_FONTS);
220 STATIC_ASSERT(ARRAY_ELEMS(ps_fontinfo) == AW_NUM_FONTS+1);
221 
222 #if defined(ASSERTION_USED)
223 static void check_ps_fontinfo_valid() {
224  // check all fonts do translate into valid xfig fonts:
225  for (int f = 0; f<AW_NUM_FONTS; ++f) {
226  int xfig_fontnr = AW_font_2_xfig(f);
227  if (xfig_fontnr<0) xfig_fontnr = -xfig_fontnr;
228  aw_assert(xfig_fontnr >= 0);
229  aw_assert(xfig_fontnr < AW_NUM_FONTS_XFIG);
230  }
231 
232  // check for unique font-specs and unique font-shortnames:
233  for (int f1 = 0; f1<AW_NUM_FONTS; ++f1) {
234  const _xfstruct& x1 = x_fontinfo[f1];
235  for (int f2 = f1+1; f2<AW_NUM_FONTS; ++f2) {
236  const _xfstruct& x2 = x_fontinfo[f2];
237 
238  aw_assert(strcmp(x1.templat, x2.templat) != 0);
239  aw_assert(strcmp(x1.description, x2.description) != 0);
240  }
241  }
242 }
243 #endif
244 
245 
246 #define FONT_STRING_PARTS 14
247 
248 static const char *parseFontString(const char *fontname, int *minus_position) {
249  const char *error = NULp;
250  const char *minus = strchr(fontname, '-');
251  int count = 0;
252 
253  for (; minus; minus = strchr(minus+1, '-'), ++count) {
254  if (count >= FONT_STRING_PARTS) { error = "too many '-'"; break; }
255  minus_position[count] = minus-fontname;
256  }
257  if (count != FONT_STRING_PARTS) error = "expected 14 '-'";
258 
259  return error;
260 }
261 static char *getParsedFontPart(const char *fontname, int *minus_position, int idx) {
262  aw_assert(idx >= 0 && idx<FONT_STRING_PARTS);
263 
264  int startpos = minus_position[idx]+1; // behind minus
265  int endpos = (idx == (FONT_STRING_PARTS-1) ? strlen(fontname) : minus_position[idx+1])-1; // in front of minus/string-end
266  int length = endpos-startpos+1; // excluding minus
267  char *result = new char[length+1];
268 
269  memcpy(result, fontname+startpos, length);
270  result[length] = 0;
271 
272  return result;
273 }
274 
275 // parse the point size of font 'name'
276 // e.g. -adobe-courier-bold-o-normal--10-100-75-75-m-60-ISO8859-1
277 
278 static int parsesize(const char *fontname) {
279  int pos[14];
280  int size;
281  const char *error = parseFontString(fontname, pos);
282 
283  if (!error) {
284  char *sizeString = getParsedFontPart(fontname, pos, 6);
285  size = atoi(sizeString);
286  if (size == 0 && strcmp(sizeString, "0") != 0) {
287  error = GBS_global_string("Can't parse size (from '%s')", sizeString);
288  }
289  delete [] sizeString;
290  }
291 
292  if (error) {
293  fprintf(stderr, "Error parsing size info from '%s' (%s)\n", fontname, error);
294  return 0;
295  }
296 
297  return size;
298 }
299 
300 void aw_root_init_font(Display *display) {
301  static bool initialized = false;
302  if (initialized) return;
303 
304  initialized = true;
305 
306 #if defined(ASSERTION_USED)
308 #endif
309 
310  /* Now initialize the font structure for the X fonts corresponding to the
311  * Postscript fonts for the canvas. OpenWindows can use any LaserWriter
312  * fonts at any size, so we don't need to load anything if we are using
313  * it.
314  */
315 
316  // check for OpenWindow-style fonts, otherwise check for scalable font
317  openwinfonts = false;
318  {
319  char **fontlist;
320  int count;
321 
322  // first look for OpenWindow style font names (e.g. times-roman)
323  if ((fontlist = XListFonts(display, ps_fontinfo[1].name, 1, &count))) {
324  openwinfonts = true;
325  for (int f = 0; f<AW_NUM_FONTS; f++) { // copy the OpenWindow font names ( = postscript fontnames?)
326  x_fontinfo[f].templat = ps_fontinfo[f+1].name;
327  is_scalable[f] = true;
328 #if defined(DUMP_FONT_LOOKUP)
329  printf("ps_fontinfo[f+1].name='%s'\n", ps_fontinfo[f+1].name);
330 #endif // DUMP_FONT_LOOKUP
331  }
332  XFreeFontNames(fontlist);
333 #if defined(DUMP_FONT_LOOKUP)
334  printf("Using OpenWindow fonts\n");
335 #endif
336  }
337  else {
338  for (int f = 0; f<AW_NUM_FONTS; f++) {
339  char templat[200];
340  strcpy(templat, x_fontinfo[f].templat);
341  strcat(templat, "0-0-*-*-*-*-*-*");
342 
343  if ((fontlist = XListFonts(display, templat, 1, &count))) {
344  // font with size zero exists -> this font is scalable
345  is_scalable[f] = true;
346  XFreeFontNames(fontlist);
347  }
348  else {
349  is_scalable[f] = false;
350  }
351 #if defined(DUMP_FONT_LOOKUP)
352  printf("Using %s font for '%s' (templat='%s')\n", is_scalable[f] ? "scalable" : "fixed", x_fontinfo[f].templat, templat);
353 #endif // DUMP_FONT_LOOKUP
354  }
355  }
356  }
357 
358  struct found_font { const char *fn; int s; };
359 
360  if (!openwinfonts) {
361  found_font *flist = new found_font[FONT_EXAMINE_MAX];
362 
363  for (int f = 0; f<AW_NUM_FONTS; f++) {
364  if (is_scalable[f]) continue;
365 
366  // for all non-scalable fonts:
367  // query the server for all the font names and sizes and build a list of them
368 
369  char **fontlist[KNOWN_ISO_VERSIONS];
370  int iso;
371  int found_fonts = 0;
372 
373  for (iso = 0; iso<KNOWN_ISO_VERSIONS; ++iso) fontlist[iso] = NULp;
374 
375  for (iso = 0; iso<KNOWN_ISO_VERSIONS; ++iso) {
376  char *font_template = GBS_global_string_copy("%s*-*-*-*-*-*-%s-*", x_fontinfo[f].templat, known_iso_versions[iso]);
377  int count;
378 
379  fontlist[iso] = XListFonts(display, font_template, FONT_EXAMINE_MAX, &count);
380  if (fontlist[iso]) {
381  if ((found_fonts+count) >= FONT_EXAMINE_MAX) {
382  printf("Warning: Too many fonts found for '%s..%s' - ARB can't examine all fonts\n", x_fontinfo[f].templat, known_iso_versions[iso]);
383  count = FONT_EXAMINE_MAX-found_fonts;
384  }
385  for (int c = 0; c<count; ++c) {
386  const char *fontname = fontlist[iso][c];
387  int size = parsesize(fontname);
388  flist[found_fonts].fn = fontname; // valid as long fontlist[iso] is not freed!
389  flist[found_fonts].s = size;
390  found_fonts++;
391  }
392  }
393 
394  free(font_template);
395  }
396 
397 #if defined(DUMP_FONT_LOOKUP)
398  printf("Considering %i fonts for '%s'\n", found_fonts, x_fontinfo[f].templat);
399 #endif // DUMP_FONT_LOOKUP
400 
401  aw_assert(found_fonts <= FONT_EXAMINE_MAX);
402  xfont *nf = NULp;
403 
404  for (int size = MIN_FONTSIZE; size <= MAX_FONTSIZE; size++) { // scan all useful sizes
405  int i;
406  for (i = 0; i < found_fonts; i++) {
407  if (flist[i].s == size) break; // search first font matching current size
408  }
409 
410  if (i < found_fonts && flist[i].s == size) {
411  xfont *newfont = ARB_alloc<xfont>(1);
412 
413  (nf ? nf->next : x_fontinfo[f].xfontlist) = newfont;
414  nf = newfont;
415 
416  // store size and actual fontname :
417  nf->size = size;
418  nf->fname = strdup(flist[i].fn);
419  nf->fstruct = NULp;
420  nf->next = NULp;
421  }
422  }
423 
424  if (!nf) { // no font has been found -> fallback to "fixed 12pt"
425  aw_assert(!x_fontinfo[f].xfontlist);
426  xfont *newfont = ARB_alloc<xfont>(1);
427  x_fontinfo[f].xfontlist = newfont;
428 
429  newfont->size = DEF_FONTSIZE;
430  newfont->fname = strdup(NORMAL_FONT);
431  newfont->fstruct = NULp;
432  newfont->next = NULp;
433  }
434 
435 #if defined(DUMP_FONT_LOOKUP)
436  nf = x_fontinfo[f].xfontlist;
437  printf("Fonts used for '%s':\n", x_fontinfo[f].templat);
438  while (nf) {
439  printf("- %2i pt: '%s'\n", nf->size, nf->fname);
440  nf = nf->next;
441  }
442 #endif // DUMP_FONT_LOOKUP
443 
444  for (iso = 0; iso<KNOWN_ISO_VERSIONS; ++iso) XFreeFontNames(fontlist[iso]);
445  }
446 
447  delete [] flist;
448  }
449 }
450 
451 #if defined(DUMP_FONT_DETAILS)
452 static void dumpFontInformation(xfont *xf) {
453  printf("Font information for '%s'", xf->fname);
454  XFontStruct *xfs = xf->fstruct;
455  if (xfs) {
456  printf(":\n");
457  printf("- max letter ascent = %2i\n", xfs->max_bounds.ascent);
458  printf("- max letter descent = %2i\n", xfs->max_bounds.descent);
459  printf("- max letter height = %2i\n", xfs->max_bounds.ascent + xfs->max_bounds.descent);
460  printf("- max letter width = %2i\n", xfs->max_bounds.width);
461  }
462  else {
463  printf(" (not available, font is not loaded)\n");
464  }
465 }
466 #endif // DEBUG
467 
468 /* Lookup an X font, "f" corresponding to a Postscript font style that is
469  * close in size to "s"
470  */
471 
472 #define DEFAULT (-1)
473 
474 static bool lookfont(Display *tool_d, int f, int s, int& found_size, bool verboose, bool only_query, PIX_FONT *fontstPtr) {
475  // returns true if appropriate font is available.
476  //
477  // 'found_size' is set to the actually found size, which may be bigger or smaller than 's', if the requested size is not available
478  //
479  // if 'only_query' is true, then only report availability
480  // if 'only_query' is false, then actually load the font and store the loaded fontstruct in 'fontstPtr'
481  bool found;
482  xfont *newfont, *nf, *oldnf;
483 
484  // @@@ scalability shall be checked for each font -- not only for first
485  // @@@ fontdetection is called for each GC -- do some caching ?
486 
487  found_size = -1;
488 
489  if (f == DEFAULT)
490  f = 0; // pass back the -normal font font
491  if (s < 0)
492  s = DEF_FONTSIZE; // default font size
493 
494  /* see if we've already loaded that font size 's'
495  from the font family 'f' */
496 
497  found = false;
498 
499  /* start with the basic font name (e.g. adobe-times-medium-r-normal-...
500  OR times-roman for OpenWindows fonts) */
501 
502  nf = x_fontinfo[f].xfontlist;
503  if (!nf) nf = x_fontinfo[0].xfontlist;
504  oldnf = nf;
505  if (nf) {
506  if (nf->size > s && !is_scalable[f]) {
507  found = true;
508  }
509  else {
510  while (nf) {
511  if (nf->size == s ||
512  (!is_scalable[f] && (nf->size >= s && oldnf->size <= s)))
513  {
514  found = true;
515  break;
516  }
517  oldnf = nf;
518  nf = nf->next;
519  }
520  }
521  }
522  if (found) { // found exact size (or only larger available)
523  if (verboose) {
524  if (s < nf->size) fprintf(stderr, "Font size %d not found, using larger %d point\n", s, nf->size);
525 #if defined(DUMP_FONT_LOOKUP)
526  fprintf(stderr, "Detected font %s\n", nf->fname);
527 #endif
528  }
529  }
530  else if (!is_scalable[f]) { // not found, use largest available
531  nf = oldnf;
532  if (verboose) {
533  if (s > nf->size) fprintf(stderr, "Font size %d not found, using smaller %d point\n", s, nf->size);
534 #if defined(DUMP_FONT_LOOKUP)
535  fprintf(stderr, "Using font %s for size %d\n", nf->fname, s);
536 #endif
537  }
538  }
539  else { // SCALABLE; none yet of that size, alloc one and put it in the list
540  ARB_alloc(newfont, 1);
541 
542  // add it on to the end of the list
543  nf = oldnf ? oldnf->next : NULp; // store successor
544 
545  if (!x_fontinfo[f].xfontlist) x_fontinfo[f].xfontlist = newfont;
546  else oldnf->next = newfont;
547 
548  newfont->next = nf; // old successor in fontlist
549  newfont->size = s;
550  newfont->fstruct = NULp;
551  newfont->fname = NULp;
552 
553  nf = newfont;
554 
555  if (openwinfonts) {
556  // OpenWindows fonts, create font name like times-roman-13
557 
558  nf->fname = GBS_global_string_copy("%s-%d", x_fontinfo[f].templat, s);
559  }
560  else {
561  // X11 fonts, create a full XLFD font name
562  // attach pointsize to font name, use the pixel field instead of points in the fontname so that the
563  // font scales with screen size
564 
565  for (int iso = 0; iso<KNOWN_ISO_VERSIONS; ++iso) {
566  char *fontname = GBS_global_string_copy("%s%d-*-*-*-*-*-%s-*", x_fontinfo[f].templat, s, known_iso_versions[iso]);
567 #if defined(DUMP_FONT_LOOKUP)
568  fprintf(stderr, "Checking for '%s' (x_fontinfo[%i].templat='%s')\n", fontname, f, x_fontinfo[f].templat);
569 #endif
570 
571  int matching_fonts_found;
572  char **matching_fonts = XListFonts(tool_d, fontname, 1, &matching_fonts_found);
573 
574  if (matching_fonts) {
575  XFreeFontNames(matching_fonts);
576  aw_assert(matching_fonts_found >= 1);
577  nf->fname = fontname;
578  break;
579  }
580 
581  free(fontname);
582  }
583  // @@@ what if nf->fstruct is 0 now ?
584  }
585  // aw_assert(nf->fname); // fails e.g. for screen-medium-r, but font nevertheless seems to be usable
586  } // scalable
587 
588  bool font_found = true;
589 
590  if (!nf->fstruct) {
591  if (only_query) {
592  ; // assume its available (or use XQueryFont to reduce server-client bandwidth)
593  }
594  else {
595 #if defined(DUMP_FONT_LOOKUP)
596  if (verboose) fprintf(stderr, "Loading font '%s'\n", nf->fname);
597 #endif
598  PIX_FONT fontst = XLoadQueryFont(tool_d, nf->fname);
599  if (!fontst) {
600  fprintf(stderr, "ARB fontpackage: Unexpectedly couldn't load font '%s', falling back to '%s' (f=%i, s=%i)\n", nf->fname, NORMAL_FONT, f, s);
601  fontst = XLoadQueryFont(tool_d, NORMAL_FONT); // @@@ may return 0!
602  freedup(nf->fname, NORMAL_FONT); // store actual name
603  }
604  // put the structure in the list
605  nf->fstruct = fontst;
606  }
607  }
608 
609 #if defined(DUMP_FONT_DETAILS)
610  dumpFontInformation(nf);
611 #endif // DEBUG
612 
613  found_size = nf->size; // report used size
614  *fontstPtr = nf->fstruct;
615 
616  return font_found;
617 }
618 
619 static int get_available_fontsizes(Display *tool_d, int f, int *available_sizes) {
620  // returns number of available sizes
621  // specific sizes are stored in available_sizes[]
622 
623  int size_count = 0;
624  for (int size = MAX_FONTSIZE; size >= MIN_FONTSIZE; --size) {
625  int found_size;
626  PIX_FONT fontst;
627 
628  ASSERT_TRUE(lookfont(tool_d, f, size, found_size, false, true, &fontst)); // lookfont should do fallback
629 
630  if (found_size<size) size = found_size;
631  if (found_size == size) available_sizes[size_count++] = size;
632  }
633 
634  // reverse order of found fontsizes
635  if (size_count>1) {
636  for (int reverse = size_count/2-1; reverse >= 0; --reverse) {
637  int o = size_count-1-reverse;
638  aw_assert(o >= 0 && o<size_count);
639 
640  int s = available_sizes[reverse];
641  available_sizes[reverse] = available_sizes[o];
642  available_sizes[o] = s;
643  }
644  }
645 
646  return size_count;
647 }
648 
649 static char *caps(char *sentence) {
650  bool doCaps = true;
651  for (int i = 0; sentence[i]; ++i) {
652  if (isalpha(sentence[i])) {
653  if (doCaps) {
654  sentence[i] = toupper(sentence[i]);
655  doCaps = false;
656  }
657  }
658  else {
659  doCaps = true;
660  }
661  }
662  return sentence;
663 }
664 
665 
666 const char *AW_get_font_specification(AW_font font_nr, bool& found) {
668  //
669  // @return 0 if font is not available
670 
671  found = false;
672  aw_assert(font_nr >= 0);
673  if (font_nr<0 || font_nr>=AW_NUM_FONTS) return NULp;
674 
675  const char *readable_fontname = NULp;
676  struct _xfstruct& xf = x_fontinfo[font_nr];
677 
678  if (xf.xfontlist) {
679  const char *fontname = xf.xfontlist->fname;
680 
681  if (strcmp(fontname, "fixed") == 0) {
682  readable_fontname = GBS_global_string("[not found: %s]", xf.templat);
683  }
684  else {
685  int pos[14];
686  const char *error = parseFontString(fontname, pos);
687  if (error) {
688  readable_fontname = GBS_global_string("[%s - parse-error (%s)]", fontname, error);
689  }
690  else {
691  char *fndry = caps(getParsedFontPart(fontname, pos, 0));
692  char *fmly = caps(getParsedFontPart(fontname, pos, 1));
693  char *wght = getParsedFontPart(fontname, pos, 2); wght[3] = 0;
694  char *slant = getParsedFontPart(fontname, pos, 3);
695  char *rgstry = getParsedFontPart(fontname, pos, 12);
696 
697  readable_fontname = GBS_global_string("%s %s %s,%s,%s",
698  fndry, fmly,
699  wght, slant,
700  rgstry);
701 
702  found = true;
703 
704  delete [] rgstry;
705  delete [] slant;
706  delete [] wght;
707  delete [] fmly;
708  delete [] fndry;
709  }
710  }
711  }
712  else {
713  readable_fontname = xf.templat;
714  found = true;
715  }
716  return readable_fontname;
717 }
718 
719 const char *AW_get_font_shortname(AW_font font_nr) {
720  aw_assert(font_nr>=0 && font_nr<AW_NUM_FONTS);
721  return x_fontinfo[font_nr].description;
722 }
723 
724 int AW_font_2_xfig(AW_font font_nr) {
726  //
727  // negative values indicate monospaced f.
728 
729  if (font_nr<0 || font_nr>=AW_NUM_FONTS) return 0;
730  return ps_fontinfo[font_nr+1].xfontnum;
731 }
732 
733 inline bool CI_NonExistChar(const XCharStruct *cs) {
734  return
735  cs->width == 0 &&
736  (cs->rbearing|cs->lbearing|cs->ascent|cs->descent) == 0;
737 }
738 
739 inline void CI_GetCharInfo_1D(const XFontStruct *fs, unsigned col, const XCharStruct *def, const XCharStruct*& cs) {
740  cs = def;
741  aw_assert(fs->min_byte1 == 0 && fs->max_byte1 == 0); // otherwise CI_GetCharInfo_1D is not the appropriate function
742  if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) {
743  if (!fs->per_char) {
744  cs = &fs->min_bounds;
745  }
746  else {
747  cs = &fs->per_char[col - fs->min_char_or_byte2];
748  if (CI_NonExistChar(cs)) cs = def;
749  }
750  }
751 }
752 
753 inline void CI_GetDefaultInfo_1D(const XFontStruct *fs, const XCharStruct*& cs) {
754  CI_GetCharInfo_1D(fs, fs->default_char, NULp, cs);
755 }
756 
757 /* CI_GET_CHAR_INFO_2D - return the charinfo struct for the indicated row and
758  * column. This is used for fonts that have more than row zero.
759  */
760 
761 inline void CI_GetCharInfo_2D(const XFontStruct *fs, unsigned row, unsigned col, const XCharStruct *def, const XCharStruct*& cs) {
762  cs = def;
763  if (row >= fs->min_byte1 && row <= fs->max_byte1 &&
764  col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2)
765  {
766  if (!fs->per_char) {
767  cs = &fs->min_bounds;
768  }
769  else {
770  cs = &fs->per_char[((row - fs->min_byte1) *
771  (fs->max_char_or_byte2 -
772  fs->min_char_or_byte2 + 1)) +
773  (col - fs->min_char_or_byte2)];
774  if (CI_NonExistChar(cs)) cs = def;
775  }
776  }
777 }
778 
779 inline void CI_GetDefaultInfo_2D(const XFontStruct *fs, const XCharStruct*& cs) {
780  unsigned int r = (fs->default_char >> 8);
781  unsigned int c = (fs->default_char & 0xff);
782  CI_GetCharInfo_2D (fs, r, c, NULp, cs);
783 }
784 
785 /* CI_GetRowzeroCharInfo_2D - do the same thing as CI_GetCharInfo_1D,
786  * except that the font has more than one row. This is special case of more
787  * general version used in XTextExt16.c since row == 0. This is used when
788  * max_byte2 is not zero. A further optimization would do the check for
789  * min_byte1 being zero ahead of time.
790  */
791 
792 inline void CI_GetRowzeroCharInfo_2D(const XFontStruct *fs, unsigned col, const XCharStruct *def, const XCharStruct*& cs) {
793  cs = def;
794  if (fs->min_byte1 == 0 &&
795  col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) {
796  if (!fs->per_char) {
797  cs = &fs->min_bounds;
798  }
799  else {
800  cs = &fs->per_char[(col - fs->min_char_or_byte2)];
801  if (CI_NonExistChar(cs)) cs = def;
802  }
803  }
804 }
805 
806 void AW_GC_Xm::wm_set_font(const AW_font font_nr, const int size, int *found_size) {
807  // if found_size != 0 -> return value for used font size
808  XFontStruct *xfs;
809  {
810  int found_font_size;
811  ASSERT_TRUE(lookfont(get_common()->get_display(), font_nr, size, found_font_size, true, false, &xfs)); // lookfont should do fallback
812  if (found_size) *found_size = found_font_size;
813  }
814  XSetFont(get_common()->get_display(), gc, xfs->fid);
815  curfont = *xfs;
816 
817  const XCharStruct *cs;
818  const XCharStruct *def; // info about default char
819  bool singlerow = (xfs->max_byte1 == 0); // optimization
820 
821  if (singlerow) { // optimization
822  CI_GetDefaultInfo_1D(xfs, def);
823  }
824  else {
825  CI_GetDefaultInfo_2D(xfs, def);
826  }
827 
829 
830  unsigned int i;
832  if (singlerow) CI_GetCharInfo_1D(xfs, i, def, cs); // optimization
833  else CI_GetRowzeroCharInfo_2D(xfs, i, def, cs);
834  if (cs) set_char_size(i, cs->ascent, cs->descent, cs->width);
835  else set_no_char_size(i);
836  }
837 }
838 
839 void AW_GC::set_font(const AW_font font_nr, const int size, int *found_size) {
840  font_limits.reset();
841  wm_set_font(font_nr, size, found_size);
842  fontnr = font_nr;
843  fontsize = size;
844 }
845 
846 int AW_GC_Xm::get_available_fontsizes(AW_font font_nr, int *available_sizes) const {
847  return ::get_available_fontsizes(get_common()->get_display(), font_nr, available_sizes);
848 }
static const char * parseFontString(const char *fontname, int *minus_position)
Definition: AW_xfont.cxx:248
string result
void set_font(AW_font font_nr, int size, int *found_size)
Definition: AW_xfont.cxx:839
const char * AW_get_font_specification(AW_font font_nr, bool &found)
Definition: AW_xfont.cxx:666
#define AW_FONTINFO_CHAR_ASCII_MAX
Definition: aw_common.hxx:27
static char * caps(char *sentence)
Definition: AW_xfont.cxx:649
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
int AW_font_2_xfig(AW_font font_nr)
Definition: AW_xfont.cxx:724
static float fontsize
Definition: arb_a2ps.c:317
#define NORMAL_FONT
Definition: aw_def.hxx:22
static bool is_scalable[AW_NUM_FONTS]
Definition: AW_xfont.cxx:37
const char * name
Definition: aw_xfont.hxx:21
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
#define AW_FONTINFO_CHAR_ASCII_MIN
Definition: aw_common.hxx:26
static const char * known_iso_versions[KNOWN_ISO_VERSIONS]
Definition: AW_xfont.cxx:52
#define FONT_STRING_PARTS
Definition: AW_xfont.cxx:246
static bool initialized
Definition: AW_advice.cxx:36
#define DEF_FONTSIZE
Definition: aw_def.hxx:27
static struct _fstruct ps_fontinfo[]
Definition: AW_xfont.cxx:137
#define DEFAULT
Definition: AW_xfont.cxx:472
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
void CI_GetCharInfo_2D(const XFontStruct *fs, unsigned row, unsigned col, const XCharStruct *def, const XCharStruct *&cs)
Definition: AW_xfont.cxx:761
void CI_GetDefaultInfo_2D(const XFontStruct *fs, const XCharStruct *&cs)
Definition: AW_xfont.cxx:779
static bool lookfont(Display *tool_d, int f, int s, int &found_size, bool verboose, bool only_query, PIX_FONT *fontstPtr)
Definition: AW_xfont.cxx:474
#define aw_assert(bed)
Definition: aw_position.hxx:29
static struct _xfstruct x_fontinfo[]
Definition: AW_xfont.cxx:57
void set_char_size(int i, int ascent, int descent, int width)
Definition: aw_common.hxx:104
XFontStruct * PIX_FONT
Definition: AW_xfont.cxx:34
bool CI_NonExistChar(const XCharStruct *cs)
Definition: AW_xfont.cxx:733
static void error(const char *msg)
Definition: mkptypes.cxx:96
int xfontnum
Definition: aw_xfont.hxx:22
static int parsesize(const char *fontname)
Definition: AW_xfont.cxx:278
STATIC_ASSERT(ARRAY_ELEMS(x_fontinfo)==AW_NUM_FONTS)
const char * templat
Definition: aw_xfont.hxx:26
#define FONT_EXAMINE_MAX
Definition: AW_xfont.cxx:24
int size
Definition: aw_xfont.hxx:13
static bool openwinfonts
Definition: AW_xfont.cxx:36
#define ASSERT_TRUE(boolExpr)
Definition: arb_assert.h:362
void aw_root_init_font(Display *display)
Definition: AW_xfont.cxx:300
const char * description
Definition: aw_xfont.hxx:27
char * fname
Definition: aw_xfont.hxx:15
#define MAX_FONTSIZE
Definition: aw_def.hxx:28
static void check_ps_fontinfo_valid()
Definition: AW_xfont.cxx:223
virtual int get_available_fontsizes(AW_font font_nr, int *available_sizes) const
Definition: AW_xfont.cxx:846
xfont * next
Definition: aw_xfont.hxx:17
void CI_GetDefaultInfo_1D(const XFontStruct *fs, const XCharStruct *&cs)
Definition: AW_xfont.cxx:753
static int get_available_fontsizes(Display *tool_d, int f, int *available_sizes)
Definition: AW_xfont.cxx:619
#define KNOWN_ISO_VERSIONS
Definition: AW_xfont.cxx:25
#define NULp
Definition: cxxforward.h:116
XFontStruct * fstruct
Definition: aw_xfont.hxx:16
#define MIN_FONTSIZE
Definition: aw_def.hxx:26
static char * getParsedFontPart(const char *fontname, int *minus_position, int idx)
Definition: AW_xfont.cxx:261
void CI_GetRowzeroCharInfo_2D(const XFontStruct *fs, unsigned col, const XCharStruct *def, const XCharStruct *&cs)
Definition: AW_xfont.cxx:792
size_t length
AW_common_Xm * get_common() const
xfont * xfontlist
Definition: aw_xfont.hxx:28
void CI_GetCharInfo_1D(const XFontStruct *fs, unsigned col, const XCharStruct *def, const XCharStruct *&cs)
Definition: AW_xfont.cxx:739
const char * AW_get_font_shortname(AW_font font_nr)
Definition: AW_xfont.cxx:719
void set_no_char_size(int i)
Definition: aw_common.hxx:110
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
GB_write_int const char s
Definition: AW_awar.cxx:154