source: tags/arb-6.0/WINDOW/AW_xfont.cxx

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