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 #if defined(WARN_TODO)
485 #warning scalability shall be checked for each font -- not only for first
486 #warning fontdetection is called for each GC -- do some caching ?
487 #endif
488 
489  found_size = -1;
490 
491  if (f == DEFAULT)
492  f = 0; // pass back the -normal font font
493  if (s < 0)
494  s = DEF_FONTSIZE; // default font size
495 
496  /* see if we've already loaded that font size 's'
497  from the font family 'f' */
498 
499  found = false;
500 
501  /* start with the basic font name (e.g. adobe-times-medium-r-normal-...
502  OR times-roman for OpenWindows fonts) */
503 
504  nf = x_fontinfo[f].xfontlist;
505  if (!nf) nf = x_fontinfo[0].xfontlist;
506  oldnf = nf;
507  if (nf) {
508  if (nf->size > s && !is_scalable[f]) {
509  found = true;
510  }
511  else {
512  while (nf) {
513  if (nf->size == s ||
514  (!is_scalable[f] && (nf->size >= s && oldnf->size <= s)))
515  {
516  found = true;
517  break;
518  }
519  oldnf = nf;
520  nf = nf->next;
521  }
522  }
523  }
524  if (found) { // found exact size (or only larger available)
525  if (verboose) {
526  if (s < nf->size) fprintf(stderr, "Font size %d not found, using larger %d point\n", s, nf->size);
527 #if defined(DUMP_FONT_LOOKUP)
528  fprintf(stderr, "Detected font %s\n", nf->fname);
529 #endif
530  }
531  }
532  else if (!is_scalable[f]) { // not found, use largest available
533  nf = oldnf;
534  if (verboose) {
535  if (s > nf->size) fprintf(stderr, "Font size %d not found, using smaller %d point\n", s, nf->size);
536 #if defined(DUMP_FONT_LOOKUP)
537  fprintf(stderr, "Using font %s for size %d\n", nf->fname, s);
538 #endif
539  }
540  }
541  else { // SCALABLE; none yet of that size, alloc one and put it in the list
542  ARB_alloc(newfont, 1);
543 
544  // add it on to the end of the list
545  nf = oldnf ? oldnf->next : NULp; // store successor
546 
547  if (!x_fontinfo[f].xfontlist) x_fontinfo[f].xfontlist = newfont;
548  else oldnf->next = newfont;
549 
550  newfont->next = nf; // old successor in fontlist
551  newfont->size = s;
552  newfont->fstruct = NULp;
553  newfont->fname = NULp;
554 
555  nf = newfont;
556 
557  if (openwinfonts) {
558  // OpenWindows fonts, create font name like times-roman-13
559 
560  nf->fname = GBS_global_string_copy("%s-%d", x_fontinfo[f].templat, s);
561  }
562  else {
563  // X11 fonts, create a full XLFD font name
564  // attach pointsize to font name, use the pixel field instead of points in the fontname so that the
565  // font scales with screen size
566 
567  for (int iso = 0; iso<KNOWN_ISO_VERSIONS; ++iso) {
568  char *fontname = GBS_global_string_copy("%s%d-*-*-*-*-*-%s-*", x_fontinfo[f].templat, s, known_iso_versions[iso]);
569 #if defined(DUMP_FONT_LOOKUP)
570  fprintf(stderr, "Checking for '%s' (x_fontinfo[%i].templat='%s')\n", fontname, f, x_fontinfo[f].templat);
571 #endif
572 
573  int matching_fonts_found;
574  char **matching_fonts = XListFonts(tool_d, fontname, 1, &matching_fonts_found);
575 
576  if (matching_fonts) {
577  XFreeFontNames(matching_fonts);
578  aw_assert(matching_fonts_found >= 1);
579  nf->fname = fontname;
580  break;
581  }
582 
583  free(fontname);
584  }
585  // @@@ what if nf->fstruct is 0 now ?
586  }
587  // aw_assert(nf->fname); // fails e.g. for screen-medium-r, but font nevertheless seems to be usable
588  } // scalable
589 
590  bool font_found = true;
591 
592  if (!nf->fstruct) {
593  if (only_query) {
594  ; // assume its available (or use XQueryFont to reduce server-client bandwidth)
595  }
596  else {
597 #if defined(DUMP_FONT_LOOKUP)
598  if (verboose) fprintf(stderr, "Loading font '%s'\n", nf->fname);
599 #endif
600  PIX_FONT fontst = XLoadQueryFont(tool_d, nf->fname);
601  if (!fontst) {
602  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);
603  fontst = XLoadQueryFont(tool_d, NORMAL_FONT); // @@@ may return 0!
604  freedup(nf->fname, NORMAL_FONT); // store actual name
605  }
606  // put the structure in the list
607  nf->fstruct = fontst;
608  }
609  }
610 
611 #if defined(DUMP_FONT_DETAILS)
612  dumpFontInformation(nf);
613 #endif // DEBUG
614 
615  found_size = nf->size; // report used size
616  *fontstPtr = nf->fstruct;
617 
618  return font_found;
619 }
620 
621 static int get_available_fontsizes(Display *tool_d, int f, int *available_sizes) {
622  // returns number of available sizes
623  // specific sizes are stored in available_sizes[]
624 
625  int size_count = 0;
626  for (int size = MAX_FONTSIZE; size >= MIN_FONTSIZE; --size) {
627  int found_size;
628  PIX_FONT fontst;
629 
630  ASSERT_TRUE(lookfont(tool_d, f, size, found_size, false, true, &fontst)); // lookfont should do fallback
631 
632  if (found_size<size) size = found_size;
633  if (found_size == size) available_sizes[size_count++] = size;
634  }
635 
636  // reverse order of found fontsizes
637  if (size_count>1) {
638  for (int reverse = size_count/2-1; reverse >= 0; --reverse) {
639  int o = size_count-1-reverse;
640  aw_assert(o >= 0 && o<size_count);
641 
642  int s = available_sizes[reverse];
643  available_sizes[reverse] = available_sizes[o];
644  available_sizes[o] = s;
645  }
646  }
647 
648  return size_count;
649 }
650 
651 static char *caps(char *sentence) {
652  bool doCaps = true;
653  for (int i = 0; sentence[i]; ++i) {
654  if (isalpha(sentence[i])) {
655  if (doCaps) {
656  sentence[i] = toupper(sentence[i]);
657  doCaps = false;
658  }
659  }
660  else {
661  doCaps = true;
662  }
663  }
664  return sentence;
665 }
666 
667 
668 const char *AW_get_font_specification(AW_font font_nr, bool& found) {
670  //
671  // @return 0 if font is not available
672 
673  found = false;
674  aw_assert(font_nr >= 0);
675  if (font_nr<0 || font_nr>=AW_NUM_FONTS) return NULp;
676 
677  const char *readable_fontname = NULp;
678  struct _xfstruct& xf = x_fontinfo[font_nr];
679 
680  if (xf.xfontlist) {
681  const char *fontname = xf.xfontlist->fname;
682 
683  if (strcmp(fontname, "fixed") == 0) {
684  readable_fontname = GBS_global_string("[not found: %s]", xf.templat);
685  }
686  else {
687  int pos[14];
688  const char *error = parseFontString(fontname, pos);
689  if (error) {
690  readable_fontname = GBS_global_string("[%s - parse-error (%s)]", fontname, error);
691  }
692  else {
693  char *fndry = caps(getParsedFontPart(fontname, pos, 0));
694  char *fmly = caps(getParsedFontPart(fontname, pos, 1));
695  char *wght = getParsedFontPart(fontname, pos, 2); wght[3] = 0;
696  char *slant = getParsedFontPart(fontname, pos, 3);
697  char *rgstry = getParsedFontPart(fontname, pos, 12);
698 
699  readable_fontname = GBS_global_string("%s %s %s,%s,%s",
700  fndry, fmly,
701  wght, slant,
702  rgstry);
703 
704  found = true;
705 
706  delete [] rgstry;
707  delete [] slant;
708  delete [] wght;
709  delete [] fmly;
710  delete [] fndry;
711  }
712  }
713  }
714  else {
715  readable_fontname = xf.templat;
716  found = true;
717  }
718  return readable_fontname;
719 }
720 
721 const char *AW_get_font_shortname(AW_font font_nr) {
722  aw_assert(font_nr>=0 && font_nr<AW_NUM_FONTS);
723  return x_fontinfo[font_nr].description;
724 }
725 
726 int AW_font_2_xfig(AW_font font_nr) {
728  //
729  // negative values indicate monospaced f.
730 
731  if (font_nr<0 || font_nr>=AW_NUM_FONTS) return 0;
732  return ps_fontinfo[font_nr+1].xfontnum;
733 }
734 
735 inline bool CI_NonExistChar(const XCharStruct *cs) {
736  return
737  cs->width == 0 &&
738  (cs->rbearing|cs->lbearing|cs->ascent|cs->descent) == 0;
739 }
740 
741 inline void CI_GetCharInfo_1D(const XFontStruct *fs, unsigned col, const XCharStruct *def, const XCharStruct*& cs) {
742  cs = def;
743  aw_assert(fs->min_byte1 == 0 && fs->max_byte1 == 0); // otherwise CI_GetCharInfo_1D is not the appropriate function
744  if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) {
745  if (!fs->per_char) {
746  cs = &fs->min_bounds;
747  }
748  else {
749  cs = &fs->per_char[col - fs->min_char_or_byte2];
750  if (CI_NonExistChar(cs)) cs = def;
751  }
752  }
753 }
754 
755 inline void CI_GetDefaultInfo_1D(const XFontStruct *fs, const XCharStruct*& cs) {
756  CI_GetCharInfo_1D(fs, fs->default_char, NULp, cs);
757 }
758 
759 /* CI_GET_CHAR_INFO_2D - return the charinfo struct for the indicated row and
760  * column. This is used for fonts that have more than row zero.
761  */
762 
763 inline void CI_GetCharInfo_2D(const XFontStruct *fs, unsigned row, unsigned col, const XCharStruct *def, const XCharStruct*& cs) {
764  cs = def;
765  if (row >= fs->min_byte1 && row <= fs->max_byte1 &&
766  col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2)
767  {
768  if (!fs->per_char) {
769  cs = &fs->min_bounds;
770  }
771  else {
772  cs = &fs->per_char[((row - fs->min_byte1) *
773  (fs->max_char_or_byte2 -
774  fs->min_char_or_byte2 + 1)) +
775  (col - fs->min_char_or_byte2)];
776  if (CI_NonExistChar(cs)) cs = def;
777  }
778  }
779 }
780 
781 inline void CI_GetDefaultInfo_2D(const XFontStruct *fs, const XCharStruct*& cs) {
782  unsigned int r = (fs->default_char >> 8);
783  unsigned int c = (fs->default_char & 0xff);
784  CI_GetCharInfo_2D (fs, r, c, NULp, cs);
785 }
786 
787 /* CI_GetRowzeroCharInfo_2D - do the same thing as CI_GetCharInfo_1D,
788  * except that the font has more than one row. This is special case of more
789  * general version used in XTextExt16.c since row == 0. This is used when
790  * max_byte2 is not zero. A further optimization would do the check for
791  * min_byte1 being zero ahead of time.
792  */
793 
794 inline void CI_GetRowzeroCharInfo_2D(const XFontStruct *fs, unsigned col, const XCharStruct *def, const XCharStruct*& cs) {
795  cs = def;
796  if (fs->min_byte1 == 0 &&
797  col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) {
798  if (!fs->per_char) {
799  cs = &fs->min_bounds;
800  }
801  else {
802  cs = &fs->per_char[(col - fs->min_char_or_byte2)];
803  if (CI_NonExistChar(cs)) cs = def;
804  }
805  }
806 }
807 
808 void AW_GC_Xm::wm_set_font(const AW_font font_nr, const int size, int *found_size) {
809  // if found_size != 0 -> return value for used font size
810  XFontStruct *xfs;
811  {
812  int found_font_size;
813  ASSERT_TRUE(lookfont(get_common()->get_display(), font_nr, size, found_font_size, true, false, &xfs)); // lookfont should do fallback
814  if (found_size) *found_size = found_font_size;
815  }
816  XSetFont(get_common()->get_display(), gc, xfs->fid);
817  curfont = *xfs;
818 
819  const XCharStruct *cs;
820  const XCharStruct *def; // info about default char
821  bool singlerow = (xfs->max_byte1 == 0); // optimization
822 
823  if (singlerow) { // optimization
824  CI_GetDefaultInfo_1D(xfs, def);
825  }
826  else {
827  CI_GetDefaultInfo_2D(xfs, def);
828  }
829 
831 
832  unsigned int i;
834  if (singlerow) CI_GetCharInfo_1D(xfs, i, def, cs); // optimization
835  else CI_GetRowzeroCharInfo_2D(xfs, i, def, cs);
836  if (cs) set_char_size(i, cs->ascent, cs->descent, cs->width);
837  else set_no_char_size(i);
838  }
839 }
840 
841 void AW_GC::set_font(const AW_font font_nr, const int size, int *found_size) {
842  font_limits.reset();
843  wm_set_font(font_nr, size, found_size);
844  fontnr = font_nr;
845  fontsize = size;
846 }
847 
848 int AW_GC_Xm::get_available_fontsizes(AW_font font_nr, int *available_sizes) const {
849  return ::get_available_fontsizes(get_common()->get_display(), font_nr, available_sizes);
850 }
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:841
const char * AW_get_font_specification(AW_font font_nr, bool &found)
Definition: AW_xfont.cxx:668
#define AW_FONTINFO_CHAR_ASCII_MAX
Definition: aw_common.hxx:27
static char * caps(char *sentence)
Definition: AW_xfont.cxx:651
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
int AW_font_2_xfig(AW_font font_nr)
Definition: AW_xfont.cxx:726
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:763
void CI_GetDefaultInfo_2D(const XFontStruct *fs, const XCharStruct *&cs)
Definition: AW_xfont.cxx:781
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:735
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:848
xfont * next
Definition: aw_xfont.hxx:17
void CI_GetDefaultInfo_1D(const XFontStruct *fs, const XCharStruct *&cs)
Definition: AW_xfont.cxx:755
static int get_available_fontsizes(Display *tool_d, int f, int *available_sizes)
Definition: AW_xfont.cxx:621
#define KNOWN_ISO_VERSIONS
Definition: AW_xfont.cxx:25
#define NULp
Definition: cxxforward.h:97
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:794
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:741
const char * AW_get_font_shortname(AW_font font_nr)
Definition: AW_xfont.cxx:721
void set_no_char_size(int i)
Definition: aw_common.hxx:110
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
GB_write_int const char s
Definition: AW_awar.cxx:156