source: branches/alilink/WINDOW/AW_xfont.cxx

Last change on this file was 16768, checked in by westram, 7 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.6 KB
Line 
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
34typedef XFontStruct *PIX_FONT;
35
36static bool openwinfonts;
37static 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)
52static const char *known_iso_versions[KNOWN_ISO_VERSIONS] = { "ISO10646", "ISO8859", "*" };
53#else
54static const char *known_iso_versions[KNOWN_ISO_VERSIONS] = { "ISO8859", "ISO10646", "*" };
55#endif
56
57static 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
137static 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
219STATIC_ASSERT(ARRAY_ELEMS(x_fontinfo) == AW_NUM_FONTS);
220STATIC_ASSERT(ARRAY_ELEMS(ps_fontinfo) == AW_NUM_FONTS+1);
221
222#if defined(ASSERTION_USED)
223static 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
248static 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}
261static 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
278static 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
300void 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)
307    check_ps_fontinfo_valid();
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].= 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)
452static 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
474static 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
621static 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
651static 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
668const char *AW_get_font_specification(AW_font font_nr, bool& found) {
669    //! converts fontnr to string
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
721const 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
726int AW_font_2_xfig(AW_font font_nr) {
727    //! converts fontnr to xfigid
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
735inline bool CI_NonExistChar(const XCharStruct *cs) {
736    return
737        cs->width                                          == 0 &&
738        (cs->rbearing|cs->lbearing|cs->ascent|cs->descent) == 0;
739}
740
741inline 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
755inline 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
763inline 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
781inline 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
794inline 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
808void 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
830    aw_assert(AW_FONTINFO_CHAR_ASCII_MIN < AW_FONTINFO_CHAR_ASCII_MAX);
831
832    unsigned int i;
833    for (i = AW_FONTINFO_CHAR_ASCII_MIN; i <= AW_FONTINFO_CHAR_ASCII_MAX; 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
841void 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
848int 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}
Note: See TracBrowser for help on using the repository browser.