source: branches/stable/WINDOW/AW_xfont.cxx

Last change on this file was 18665, checked in by westram, 3 years ago
  • change many WARN_TODO triggered warnings into todo markers.
  • 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    // @@@ 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
619static 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
649static 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
666const char *AW_get_font_specification(AW_font font_nr, bool& found) {
667    //! converts fontnr to string
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
719const 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
724int AW_font_2_xfig(AW_font font_nr) {
725    //! converts fontnr to xfigid
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
733inline bool CI_NonExistChar(const XCharStruct *cs) {
734    return
735        cs->width                                          == 0 &&
736        (cs->rbearing|cs->lbearing|cs->ascent|cs->descent) == 0;
737}
738
739inline 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
753inline 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
761inline 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
779inline 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
792inline 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
806void 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
828    aw_assert(AW_FONTINFO_CHAR_ASCII_MIN < AW_FONTINFO_CHAR_ASCII_MAX);
829
830    unsigned int i;
831    for (i = AW_FONTINFO_CHAR_ASCII_MIN; i <= AW_FONTINFO_CHAR_ASCII_MAX; 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
839void 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
846int 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}
Note: See TracBrowser for help on using the repository browser.