1 | /* FIG : Facility for Interactive Generation of figures |
---|
2 | * Copyright (c) 1985 by Supoj Sutanthavibul |
---|
3 | * Copyright (c) 1992 by Brian V. Smith |
---|
4 | * |
---|
5 | * "Permission to use, copy, modify, distribute, and sell this software and its |
---|
6 | * documentation for any purpose is hereby granted without fee, provided that |
---|
7 | * the above copyright notice appear in all copies and that both the copyright |
---|
8 | * notice and this permission notice appear in supporting documentation. |
---|
9 | * No representations are made about the suitability of this software for |
---|
10 | * any purpose. It is provided "as is" without express or implied warranty." |
---|
11 | * |
---|
12 | * This software has been widely modified for usage inside ARB. |
---|
13 | */ |
---|
14 | |
---|
15 | #include "aw_xfont.hxx" |
---|
16 | #include "aw_root.hxx" |
---|
17 | |
---|
18 | #include <arbdb.h> |
---|
19 | |
---|
20 | #include <cctype> |
---|
21 | |
---|
22 | // -------------------------------------------------------------------------------- |
---|
23 | |
---|
24 | #define FONT_EXAMINE_MAX 5000 |
---|
25 | #define KNOWN_ISO_VERSIONS 3 |
---|
26 | |
---|
27 | #if !defined(DEVEL_RELEASE) |
---|
28 | // #define DUMP_FONT_LOOKUP |
---|
29 | // #define DUMP_FONT_DETAILS |
---|
30 | #endif |
---|
31 | |
---|
32 | // -------------------------------------------------------------------------------- |
---|
33 | |
---|
34 | typedef XFontStruct *PIX_FONT; |
---|
35 | |
---|
36 | static bool openwinfonts; |
---|
37 | static bool is_scalable[AW_NUM_FONTS]; // whether the font is scalable |
---|
38 | |
---|
39 | // defines the preferred xfontsel-'rgstry' values (most wanted first) |
---|
40 | |
---|
41 | #define PREFER_ISO10646 |
---|
42 | |
---|
43 | #if defined(DEVEL_RALF) |
---|
44 | #if defined(PREFER_ISO10646) |
---|
45 | // #warning current iso setting: prefer ISO10646 (this is recommended) |
---|
46 | #else |
---|
47 | #warning current iso setting: prefer ISO8859 |
---|
48 | #endif // PREFER_ISO10646 |
---|
49 | #endif // DEVEL_RALF |
---|
50 | |
---|
51 | #if defined(PREFER_ISO10646) |
---|
52 | static const char *known_iso_versions[KNOWN_ISO_VERSIONS] = { "ISO10646", "ISO8859", "*" }; |
---|
53 | #else |
---|
54 | static const char *known_iso_versions[KNOWN_ISO_VERSIONS] = { "ISO8859", "ISO10646", "*" }; |
---|
55 | #endif |
---|
56 | |
---|
57 | static struct _xfstruct x_fontinfo[] = { |
---|
58 | { "-adobe-times-medium-r-*--", "Times", NULp }, // #0 |
---|
59 | { "-adobe-times-medium-i-*--", "Times I", NULp }, // #1 |
---|
60 | { "-adobe-times-bold-r-*--", "Times B", NULp }, // #2 |
---|
61 | { "-adobe-times-bold-i-*--", "Times IB", NULp }, // #3 |
---|
62 | { "-schumacher-clean-medium-r-*--", "Schumacher", NULp }, // closest to Avant-Garde |
---|
63 | { "-schumacher-clean-medium-i-*--", "Schumacher I", NULp }, // #5 |
---|
64 | { "-schumacher-clean-bold-r-*--", "Schumacher B", NULp }, // #6 |
---|
65 | { "-schumacher-clean-bold-i-*--", "Schumacher IB", NULp }, // #7 |
---|
66 | { "-*-urw bookman l-medium-r-*--", "Bookman", NULp }, // closest to Bookman |
---|
67 | { "-*-urw bookman l-medium-i-*--", "Bookman I", NULp }, // #9 |
---|
68 | { "-*-urw bookman l-bold-r-*--", "Bookman B", NULp }, // #10 |
---|
69 | { "-*-urw bookman l-bold-i-*--", "Bookman IB", NULp }, // #11 |
---|
70 | { "-adobe-courier-medium-r-*--", "Courier", NULp }, // #12 |
---|
71 | { "-adobe-courier-medium-o-*--", "Courier I", NULp }, // #13 |
---|
72 | { "-adobe-courier-bold-r-*--", "Courier B", NULp }, // #14 |
---|
73 | { "-adobe-courier-bold-o-*--", "Courier IB", NULp }, // #15 |
---|
74 | { "-adobe-helvetica-medium-r-*--", "Helvetica", NULp }, // #16 |
---|
75 | { "-adobe-helvetica-medium-o-*--", "Helvetica I", NULp }, // #17 |
---|
76 | { "-adobe-helvetica-bold-r-*--", "Helvetica B", NULp }, // #18 |
---|
77 | { "-adobe-helvetica-bold-o-*--", "Helvetica IB", NULp }, // #19 |
---|
78 | { "-*-liberation sans narrow-medium-r-*--", "Liberation", NULp }, // closest to Helv-nar. |
---|
79 | { "-*-liberation sans narrow-medium-o-*--", "Liberation I", NULp }, // #21 |
---|
80 | { "-*-liberation sans narrow-bold-r-*--", "Liberation B", NULp }, // #22 |
---|
81 | { "-*-liberation sans narrow-bold-o-*--", "Liberation IB", NULp }, // #23 |
---|
82 | { "-adobe-new century schoolbook-medium-r-*--", "Schoolbook", NULp }, // #24 |
---|
83 | { "-adobe-new century schoolbook-medium-i-*--", "Schoolbook I", NULp }, // #25 |
---|
84 | { "-adobe-new century schoolbook-bold-r-*--", "Schoolbook B", NULp }, // #26 |
---|
85 | { "-adobe-new century schoolbook-bold-i-*--", "Schoolbook IB", NULp }, // #27 |
---|
86 | { "-*-lucidabright-medium-r-*--", "LucidaBr", NULp }, // closest to Palatino |
---|
87 | { "-*-lucidabright-medium-i-*--", "LucidaBr I", NULp }, // #29 |
---|
88 | { "-*-lucidabright-demibold-r-*--", "LucidaBr B", NULp }, // #30 |
---|
89 | { "-*-lucidabright-demibold-i-*--", "LucidaBr IB", NULp }, // #31 |
---|
90 | { "-*-symbol-medium-r-*--", "Symbol", NULp }, // #32 |
---|
91 | { "-*-zapfchancery-medium-i-*--", "zapfchancery", NULp }, // #33 |
---|
92 | { "-*-zapfdingbats-*-*-*--", "zapfdingbats", NULp }, // #34 |
---|
93 | |
---|
94 | // below here are fonts not defined in xfig! |
---|
95 | // on export, they will be mapped to xfig fonts |
---|
96 | // (according to ps_fontinfo.xfontnum, i.e. the number behind the postscript fontname below) |
---|
97 | |
---|
98 | { "-*-lucida-medium-r-*-*-", "Lucida", NULp }, // #35 |
---|
99 | { "-*-lucida-medium-i-*-*-", "Lucida I", NULp }, // #36 |
---|
100 | { "-*-lucida-bold-r-*-*-", "Lucida B", NULp }, // #37 |
---|
101 | { "-*-lucida-bold-i-*-*-", "Lucida IB", NULp }, // #38 |
---|
102 | { "-*-lucidatypewriter-medium-r-*-*-", "Lucida mono", NULp }, // #39 |
---|
103 | { "-*-lucidatypewriter-bold-r-*-*-", "Lucida mono B", NULp }, // #40 |
---|
104 | |
---|
105 | { "-*-screen-medium-r-*-*-", "Screen", NULp }, // #41 |
---|
106 | { "-*-screen-bold-r-*-*-", "Screen B", NULp }, // #42 |
---|
107 | { "-*-clean-medium-r-*-*-", "Clean", NULp }, // #43 |
---|
108 | { "-*-clean-bold-r-*-*-", "Clean B", NULp }, // #44 |
---|
109 | { "-*-terminal-medium-r-*-*-", "Terminal", NULp }, // #45 |
---|
110 | { "-*-terminal-bold-r-*-*-", "Terminal B", NULp }, // #46 |
---|
111 | |
---|
112 | { "-*-dustismo-medium-r-*-*-", "Dustismo", NULp }, // #47 |
---|
113 | { "-*-dustismo-bold-r-*-*-", "Dustismo B", NULp }, // #48 |
---|
114 | { "-*-utopia-medium-r-*-*-", "Utopia", NULp }, // #49 |
---|
115 | { "-*-utopia-bold-r-*-*-", "Utopia B", NULp }, // #50 |
---|
116 | { "-*-dejavu sans-medium-r-*-*-", "Dejavu", NULp }, // #51 |
---|
117 | { "-*-dejavu sans-bold-r-*-*-", "Dejavu B", NULp }, // #52 |
---|
118 | |
---|
119 | { "-*-fixed-medium-r-*-*-", "Fixed", NULp }, // #53 |
---|
120 | { "-*-fixed-bold-r-*-*-", "Fixed B", NULp }, // #54 |
---|
121 | { "-*-dejavu sans mono-medium-r-*-*-", "Dejavu mono", NULp }, // #55 |
---|
122 | { "-*-dejavu sans mono-bold-r-*-*-", "Dejavu mono B", NULp }, // #56 |
---|
123 | { "-*-luxi mono-medium-r-*-*-", "Luxi mono", NULp }, // #57 |
---|
124 | { "-*-luxi mono-bold-r-*-*-", "Luxi mono B", NULp }, // #58 |
---|
125 | { "-*-nimbus mono l-medium-r-*-*-", "Nimbus mono", NULp }, // #59 |
---|
126 | { "-*-nimbus mono l-bold-r-*-*-", "Nimbus mono B", NULp }, // #60 |
---|
127 | { "-*-latin modern typewriter-medium-r-*-*-", "Latin mono", NULp }, // #61 |
---|
128 | { "-*-latin modern typewriter-bold-r-*-*-", "Latin mono B", NULp }, // #62 |
---|
129 | |
---|
130 | { "-*-terminus-medium-r-*-*-", "Terminus", NULp }, // #63 |
---|
131 | { "-*-terminus-bold-r-*-*-", "Terminus B", NULp }, // #64 |
---|
132 | { "-sony-fixed-medium-r-*-*-", "SonyFixed", NULp }, // #65 |
---|
133 | { "-sony-fixed-bold-r-*-*-", "SonyFixed B", NULp }, // #66 |
---|
134 | { "-mutt-clearlyu-medium-r-*-*-", "MuttClearlyu", NULp }, // #67 |
---|
135 | }; |
---|
136 | |
---|
137 | static struct _fstruct ps_fontinfo[] = { |
---|
138 | // map window fonts to postscript fonts |
---|
139 | // negative values indicate monospaced fonts |
---|
140 | { "Default", -1 }, |
---|
141 | { "Times-Roman", 0 }, |
---|
142 | { "Times-Italic", 1 }, |
---|
143 | { "Times-Bold", 2 }, |
---|
144 | { "Times-BoldItalic", 3 }, |
---|
145 | { "AvantGarde-Book", 4 }, |
---|
146 | { "AvantGarde-BookOblique", 5 }, |
---|
147 | { "AvantGarde-Demi", 6 }, |
---|
148 | { "AvantGarde-DemiOblique", 7 }, |
---|
149 | { "Bookman-Light", 8 }, |
---|
150 | { "Bookman-LightItalic", 9 }, |
---|
151 | { "Bookman-Demi", 10 }, |
---|
152 | { "Bookman-DemiItalic", 11 }, |
---|
153 | { "Courier", -12 }, |
---|
154 | { "Courier-Oblique", -13 }, |
---|
155 | { "Courier-Bold", -14 }, |
---|
156 | { "Courier-BoldOblique", -15 }, |
---|
157 | { "Helvetica", 16 }, |
---|
158 | { "Helvetica-Oblique", 17 }, |
---|
159 | { "Helvetica-Bold", 18 }, |
---|
160 | { "Helvetica-BoldOblique", 19 }, |
---|
161 | { "Helvetica-Narrow", 20 }, |
---|
162 | { "Helvetica-Narrow-Oblique", 21 }, |
---|
163 | { "Helvetica-Narrow-Bold", 22 }, |
---|
164 | { "Helvetica-Narrow-BoldOblique", 23 }, |
---|
165 | { "NewCenturySchlbk-Roman", 24 }, |
---|
166 | { "NewCenturySchlbk-Italic", 25 }, |
---|
167 | { "NewCenturySchlbk-Bold", 26 }, |
---|
168 | { "NewCenturySchlbk-BoldItalic", 27 }, |
---|
169 | { "Palatino-Roman", 28 }, |
---|
170 | { "Palatino-Italic", 29 }, |
---|
171 | { "Palatino-Bold", 30 }, |
---|
172 | { "Palatino-BoldItalic", 31 }, |
---|
173 | { "Symbol", 32 }, |
---|
174 | { "ZapfChancery-MediumItalic", 33 }, |
---|
175 | { "ZapfDingbats", 34 }, |
---|
176 | |
---|
177 | // non xfig-fonts below. |
---|
178 | // Need to be mapped to best matching xfig font using a font number between 0 and AW_NUM_FONTS_XFIG-1 |
---|
179 | |
---|
180 | { "LucidaSans", 16 }, |
---|
181 | { "LucidaSans-Italic", 17 }, |
---|
182 | { "LucidaSans-Bold", 18 }, |
---|
183 | { "LucidaSans-BoldItalic", 19 }, |
---|
184 | { "LucidaSansTypewriter", -12 }, |
---|
185 | { "LucidaSansTypewriter-Bold", -14 }, |
---|
186 | |
---|
187 | { "Screen", -16 }, |
---|
188 | { "Screen-Bold", -18 }, |
---|
189 | { "Clean", -12 }, |
---|
190 | { "Clean-Bold", -14 }, |
---|
191 | { "Terminal", -12 }, |
---|
192 | { "Terminal-Bold", -14 }, |
---|
193 | |
---|
194 | { "AvantGarde-Book", 4 }, |
---|
195 | { "AvantGarde-Demi", 6 }, |
---|
196 | { "Palatino-Roman", 28 }, |
---|
197 | { "Palatino-Bold", 30 }, |
---|
198 | { "AvantGarde-Book", 4 }, |
---|
199 | { "AvantGarde-Demi", 6 }, |
---|
200 | |
---|
201 | { "Courier", -12 }, |
---|
202 | { "Courier-Bold", -14 }, |
---|
203 | { "Courier", -12 }, |
---|
204 | { "Courier-Bold", -14 }, |
---|
205 | { "Courier", -12 }, |
---|
206 | { "Courier-Bold", -14 }, |
---|
207 | { "Courier", -12 }, |
---|
208 | { "Courier-Bold", -14 }, |
---|
209 | { "Courier", -12 }, |
---|
210 | { "Courier-Bold", -14 }, |
---|
211 | |
---|
212 | { "Courier", -12 }, |
---|
213 | { "Courier-Bold", -14 }, |
---|
214 | { "Courier", -12 }, |
---|
215 | { "Courier-Bold", -14 }, |
---|
216 | { "Times-Roman", 0 }, |
---|
217 | }; |
---|
218 | |
---|
219 | STATIC_ASSERT(ARRAY_ELEMS(x_fontinfo) == AW_NUM_FONTS); |
---|
220 | STATIC_ASSERT(ARRAY_ELEMS(ps_fontinfo) == AW_NUM_FONTS+1); |
---|
221 | |
---|
222 | #if defined(ASSERTION_USED) |
---|
223 | static void check_ps_fontinfo_valid() { |
---|
224 | // check all fonts do translate into valid xfig fonts: |
---|
225 | for (int f = 0; f<AW_NUM_FONTS; ++f) { |
---|
226 | int xfig_fontnr = AW_font_2_xfig(f); |
---|
227 | if (xfig_fontnr<0) xfig_fontnr = -xfig_fontnr; |
---|
228 | aw_assert(xfig_fontnr >= 0); |
---|
229 | aw_assert(xfig_fontnr < AW_NUM_FONTS_XFIG); |
---|
230 | } |
---|
231 | |
---|
232 | // check for unique font-specs and unique font-shortnames: |
---|
233 | for (int f1 = 0; f1<AW_NUM_FONTS; ++f1) { |
---|
234 | const _xfstruct& x1 = x_fontinfo[f1]; |
---|
235 | for (int f2 = f1+1; f2<AW_NUM_FONTS; ++f2) { |
---|
236 | const _xfstruct& x2 = x_fontinfo[f2]; |
---|
237 | |
---|
238 | aw_assert(strcmp(x1.templat, x2.templat) != 0); |
---|
239 | aw_assert(strcmp(x1.description, x2.description) != 0); |
---|
240 | } |
---|
241 | } |
---|
242 | } |
---|
243 | #endif |
---|
244 | |
---|
245 | |
---|
246 | #define FONT_STRING_PARTS 14 |
---|
247 | |
---|
248 | static const char *parseFontString(const char *fontname, int *minus_position) { |
---|
249 | const char *error = NULp; |
---|
250 | const char *minus = strchr(fontname, '-'); |
---|
251 | int count = 0; |
---|
252 | |
---|
253 | for (; minus; minus = strchr(minus+1, '-'), ++count) { |
---|
254 | if (count >= FONT_STRING_PARTS) { error = "too many '-'"; break; } |
---|
255 | minus_position[count] = minus-fontname; |
---|
256 | } |
---|
257 | if (count != FONT_STRING_PARTS) error = "expected 14 '-'"; |
---|
258 | |
---|
259 | return error; |
---|
260 | } |
---|
261 | static char *getParsedFontPart(const char *fontname, int *minus_position, int idx) { |
---|
262 | aw_assert(idx >= 0 && idx<FONT_STRING_PARTS); |
---|
263 | |
---|
264 | int startpos = minus_position[idx]+1; // behind minus |
---|
265 | int endpos = (idx == (FONT_STRING_PARTS-1) ? strlen(fontname) : minus_position[idx+1])-1; // in front of minus/string-end |
---|
266 | int length = endpos-startpos+1; // excluding minus |
---|
267 | char *result = new char[length+1]; |
---|
268 | |
---|
269 | memcpy(result, fontname+startpos, length); |
---|
270 | result[length] = 0; |
---|
271 | |
---|
272 | return result; |
---|
273 | } |
---|
274 | |
---|
275 | // parse the point size of font 'name' |
---|
276 | // e.g. -adobe-courier-bold-o-normal--10-100-75-75-m-60-ISO8859-1 |
---|
277 | |
---|
278 | static int parsesize(const char *fontname) { |
---|
279 | int pos[14]; |
---|
280 | int size; |
---|
281 | const char *error = parseFontString(fontname, pos); |
---|
282 | |
---|
283 | if (!error) { |
---|
284 | char *sizeString = getParsedFontPart(fontname, pos, 6); |
---|
285 | size = atoi(sizeString); |
---|
286 | if (size == 0 && strcmp(sizeString, "0") != 0) { |
---|
287 | error = GBS_global_string("Can't parse size (from '%s')", sizeString); |
---|
288 | } |
---|
289 | delete [] sizeString; |
---|
290 | } |
---|
291 | |
---|
292 | if (error) { |
---|
293 | fprintf(stderr, "Error parsing size info from '%s' (%s)\n", fontname, error); |
---|
294 | return 0; |
---|
295 | } |
---|
296 | |
---|
297 | return size; |
---|
298 | } |
---|
299 | |
---|
300 | void aw_root_init_font(Display *display) { |
---|
301 | static bool initialized = false; |
---|
302 | if (initialized) return; |
---|
303 | |
---|
304 | initialized = true; |
---|
305 | |
---|
306 | #if defined(ASSERTION_USED) |
---|
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].s = size; |
---|
390 | found_fonts++; |
---|
391 | } |
---|
392 | } |
---|
393 | |
---|
394 | free(font_template); |
---|
395 | } |
---|
396 | |
---|
397 | #if defined(DUMP_FONT_LOOKUP) |
---|
398 | printf("Considering %i fonts for '%s'\n", found_fonts, x_fontinfo[f].templat); |
---|
399 | #endif // DUMP_FONT_LOOKUP |
---|
400 | |
---|
401 | aw_assert(found_fonts <= FONT_EXAMINE_MAX); |
---|
402 | xfont *nf = NULp; |
---|
403 | |
---|
404 | for (int size = MIN_FONTSIZE; size <= MAX_FONTSIZE; size++) { // scan all useful sizes |
---|
405 | int i; |
---|
406 | for (i = 0; i < found_fonts; i++) { |
---|
407 | if (flist[i].s == size) break; // search first font matching current size |
---|
408 | } |
---|
409 | |
---|
410 | if (i < found_fonts && flist[i].s == size) { |
---|
411 | xfont *newfont = ARB_alloc<xfont>(1); |
---|
412 | |
---|
413 | (nf ? nf->next : x_fontinfo[f].xfontlist) = newfont; |
---|
414 | nf = newfont; |
---|
415 | |
---|
416 | // store size and actual fontname : |
---|
417 | nf->size = size; |
---|
418 | nf->fname = strdup(flist[i].fn); |
---|
419 | nf->fstruct = NULp; |
---|
420 | nf->next = NULp; |
---|
421 | } |
---|
422 | } |
---|
423 | |
---|
424 | if (!nf) { // no font has been found -> fallback to "fixed 12pt" |
---|
425 | aw_assert(!x_fontinfo[f].xfontlist); |
---|
426 | xfont *newfont = ARB_alloc<xfont>(1); |
---|
427 | x_fontinfo[f].xfontlist = newfont; |
---|
428 | |
---|
429 | newfont->size = DEF_FONTSIZE; |
---|
430 | newfont->fname = strdup(NORMAL_FONT); |
---|
431 | newfont->fstruct = NULp; |
---|
432 | newfont->next = NULp; |
---|
433 | } |
---|
434 | |
---|
435 | #if defined(DUMP_FONT_LOOKUP) |
---|
436 | nf = x_fontinfo[f].xfontlist; |
---|
437 | printf("Fonts used for '%s':\n", x_fontinfo[f].templat); |
---|
438 | while (nf) { |
---|
439 | printf("- %2i pt: '%s'\n", nf->size, nf->fname); |
---|
440 | nf = nf->next; |
---|
441 | } |
---|
442 | #endif // DUMP_FONT_LOOKUP |
---|
443 | |
---|
444 | for (iso = 0; iso<KNOWN_ISO_VERSIONS; ++iso) XFreeFontNames(fontlist[iso]); |
---|
445 | } |
---|
446 | |
---|
447 | delete [] flist; |
---|
448 | } |
---|
449 | } |
---|
450 | |
---|
451 | #if defined(DUMP_FONT_DETAILS) |
---|
452 | static void dumpFontInformation(xfont *xf) { |
---|
453 | printf("Font information for '%s'", xf->fname); |
---|
454 | XFontStruct *xfs = xf->fstruct; |
---|
455 | if (xfs) { |
---|
456 | printf(":\n"); |
---|
457 | printf("- max letter ascent = %2i\n", xfs->max_bounds.ascent); |
---|
458 | printf("- max letter descent = %2i\n", xfs->max_bounds.descent); |
---|
459 | printf("- max letter height = %2i\n", xfs->max_bounds.ascent + xfs->max_bounds.descent); |
---|
460 | printf("- max letter width = %2i\n", xfs->max_bounds.width); |
---|
461 | } |
---|
462 | else { |
---|
463 | printf(" (not available, font is not loaded)\n"); |
---|
464 | } |
---|
465 | } |
---|
466 | #endif // DEBUG |
---|
467 | |
---|
468 | /* Lookup an X font, "f" corresponding to a Postscript font style that is |
---|
469 | * close in size to "s" |
---|
470 | */ |
---|
471 | |
---|
472 | #define DEFAULT (-1) |
---|
473 | |
---|
474 | static bool lookfont(Display *tool_d, int f, int s, int& found_size, bool verboose, bool only_query, PIX_FONT *fontstPtr) { |
---|
475 | // returns true if appropriate font is available. |
---|
476 | // |
---|
477 | // 'found_size' is set to the actually found size, which may be bigger or smaller than 's', if the requested size is not available |
---|
478 | // |
---|
479 | // if 'only_query' is true, then only report availability |
---|
480 | // if 'only_query' is false, then actually load the font and store the loaded fontstruct in 'fontstPtr' |
---|
481 | bool found; |
---|
482 | xfont *newfont, *nf, *oldnf; |
---|
483 | |
---|
484 | // @@@ 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 | |
---|
619 | static 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 | |
---|
649 | static 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 | |
---|
666 | const 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 | |
---|
719 | const 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 | |
---|
724 | int 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 | |
---|
733 | inline bool CI_NonExistChar(const XCharStruct *cs) { |
---|
734 | return |
---|
735 | cs->width == 0 && |
---|
736 | (cs->rbearing|cs->lbearing|cs->ascent|cs->descent) == 0; |
---|
737 | } |
---|
738 | |
---|
739 | inline 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 | |
---|
753 | inline 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 | |
---|
761 | inline 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 | |
---|
779 | inline 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 | |
---|
792 | inline 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 | |
---|
806 | void 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 | |
---|
839 | void 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 | |
---|
846 | int 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 | } |
---|