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