Commit | Line | Data |
---|---|---|
3144ee8a AT |
1 | /* xscreensaver, Copyright (c) 2018-2020 by Jamie Zawinski <jwz@jwz.org> |
2 | * | |
3 | * Permission to use, copy, modify, distribute, and sell this software and its | |
4 | * documentation for any purpose is hereby granted without fee, provided that | |
5 | * the above copyright notice appear in all copies and that both that | |
6 | * copyright notice and this permission notice appear in supporting | |
7 | * documentation. No representations are made about the suitability of this | |
8 | * software for any purpose. It is provided "as is" without express or | |
9 | * implied warranty. | |
10 | */ | |
11 | ||
12 | /* Like XLoadQueryFont, but if it fails, it tries some heuristics to | |
13 | load something close. | |
14 | */ | |
15 | ||
16 | #define _GNU_SOURCE | |
17 | ||
18 | #include "utils.h" | |
19 | #include "visual.h" | |
20 | #include "xft.h" | |
21 | #include "font-retry.h" | |
22 | ||
23 | extern const char *progname; | |
24 | ||
25 | #undef countof | |
26 | #define countof(x) (sizeof((x))/sizeof((*x))) | |
27 | ||
28 | #undef DEBUG | |
29 | ||
30 | static void * | |
31 | load_font_retry_1 (Display *dpy, int screen, const char *xlfd, Bool xft_p) | |
32 | { | |
33 | ||
34 | # ifdef USE_XFT | |
35 | # define LOADFONT(F) (xft_p \ | |
36 | ? (void *) XftFontOpenXlfd (dpy, screen, (F)) \ | |
37 | : (void *) XLoadQueryFont (dpy, (F))) | |
38 | # else | |
39 | # define LOADFONT(F) ((void *) XLoadQueryFont (dpy, (F))) | |
40 | # endif | |
41 | ||
42 | void *f = xlfd ? LOADFONT(xlfd) : 0; | |
43 | ||
44 | # ifndef USE_XFT | |
45 | if (xft_p) abort(); | |
46 | # endif | |
47 | ||
48 | # ifdef HAVE_JWXYZ | |
49 | return f; | |
50 | # else /* !HAVE_JWXYZ */ | |
51 | if (! xlfd) xlfd = "<null>"; | |
52 | if (f) | |
53 | { | |
54 | # ifdef DEBUG | |
55 | fprintf (stderr, "%s: loaded %s\n", progname, xlfd); | |
56 | # endif | |
57 | return f; | |
58 | } | |
59 | else | |
60 | { | |
61 | Bool bold_p = (!!strcasestr (xlfd, "-bold-") || | |
62 | !!strcasestr (xlfd, "-ocr")); | |
63 | Bool italic_p = (!!strcasestr (xlfd, "-i-") || | |
64 | !!strcasestr (xlfd, "-o-")); | |
65 | Bool fixed_p = (!!strcasestr (xlfd, "courier") || | |
66 | !!strcasestr (xlfd, "-ocr") || | |
67 | !!strcasestr (xlfd, "-m-") || | |
68 | !!strcasestr (xlfd, "-c-")); | |
69 | int size = 0; | |
70 | ||
71 | # ifdef DEBUG | |
72 | fprintf (stderr, "%s: failed %s\n", progname, xlfd); | |
73 | # endif | |
74 | ||
75 | if (!strcmp (xlfd, "vga")) /* BSOD uses this: it has no XLFD name. */ | |
76 | fixed_p = True, size = 120; | |
77 | ||
78 | /* Look for the first number in the string like "-180-" */ | |
79 | if (! size) | |
80 | { | |
81 | const char *s; | |
82 | for (s = xlfd; *s; s++) | |
83 | if (s[0] == '-' && s[1] >= '0' && s[1] <= '9') | |
84 | { | |
85 | int i = s[1] - '0'; | |
86 | const char *s2 = s+2; | |
87 | while (*s2 >= '0' && *s2 <= '9') | |
88 | { | |
89 | i = i * 10 + *s2 - '0'; | |
90 | s2++; | |
91 | } | |
92 | if (*s2 != '-') continue; /* Number ends with dash */ | |
93 | if (i < 60 || i >= 2000) continue; /* In range 6pt - 200pt */ | |
94 | if (i % 10) continue; /* Multiple of 10 */ | |
95 | ||
96 | size = i; | |
97 | break; | |
98 | } | |
99 | } | |
100 | ||
101 | if (! size) | |
102 | { | |
103 | fprintf (stderr, "%s: unloadable, unparsable font: \"%s\"\n", | |
104 | progname, xlfd); | |
105 | xlfd = "fixed"; | |
106 | return LOADFONT(xlfd); | |
107 | } | |
108 | else | |
109 | { | |
110 | const char *variable[] = { | |
111 | "helvetica", | |
112 | "arial", | |
113 | "bitstream vera sans", /* sometimes foundry is in family */ | |
114 | "vera sans", /* sometimes not? */ | |
115 | "gill sans", | |
116 | "times", | |
117 | "times new roman", | |
118 | "new century schoolbook", | |
119 | "utopia", | |
120 | "palatino", | |
121 | "lucida", | |
122 | "clearlyu", | |
123 | "bitstream charter", /* sometimes foundry is in family */ | |
124 | "charter", /* sometimes not? */ | |
125 | "utopia", | |
126 | "luxi sans", | |
127 | "latin modern roman", | |
128 | ||
129 | /* Don't use a wildcard family. If none of the above worked, then | |
130 | then almost none of the X11 fonts are installed, and it's not | |
131 | unlikely that "-*-*-medium-r-*-*-*-140-*-*-*-10646-1" will | |
132 | match an Arabic or or Japanese font that contains no Latin | |
133 | glyphs at all, even in a Latin locale. So in that case, just | |
134 | let "helvetica" fall back to "fixed". | |
135 | */ | |
136 | /* "*" */ | |
137 | }; | |
138 | const char *fixed[] = { | |
139 | "courier", | |
140 | "courier new", | |
141 | "courier 10 pitch", | |
142 | "lucidatypewriter", | |
143 | "american typewriter", | |
144 | "luxi mono", | |
145 | "fixed", | |
146 | "ocr a std", | |
147 | /* As above, but "can't happen" because we already tried fixed? */ | |
148 | /* "*" */ | |
149 | }; | |
150 | const char *charsets[] = { "iso10646-1", "iso8859-1", "*-*" }; | |
151 | const char *weights[] = { "bold", "medium" }; | |
152 | const char *slants[] = { "o", "i", "r" }; | |
153 | const char *spacings[] = { "m", "c", "p" }; | |
154 | int a, b, c, d, e, g; | |
155 | char buf[1024]; | |
156 | ||
157 | for (a = 0; a < countof(charsets); a++) | |
158 | for (b = (bold_p ? 0 : 1); b < countof(weights); b++) | |
159 | for (c = (italic_p ? 0 : 2); c < countof(slants); c++) | |
160 | for (d = 0; | |
161 | d < (fixed_p ? countof(fixed) : countof(variable)); | |
162 | d++) | |
163 | for (g = size; g >= 60; g -= 10) | |
164 | for (e = (fixed_p ? 0 : 2); e < countof(spacings); e++) | |
165 | { | |
166 | sprintf (buf, | |
167 | "-%s-%s-%s-%s-%s-%s-%s-%d-%s-%s-%s-%s-%s", | |
168 | "*", /* foundry */ | |
169 | (fixed_p ? fixed[d] : variable[d]), | |
170 | weights[b], | |
171 | slants[c], | |
172 | "*", /* set width */ | |
173 | "*", /* add style */ | |
174 | "*", /* pixel size */ | |
175 | g, /* point size */ | |
176 | "*", /* x resolution */ | |
177 | "*", /* y resolution */ | |
178 | spacings[e], | |
179 | "*", /* average width */ | |
180 | charsets[a]); | |
181 | # ifdef DEBUG | |
182 | fprintf(stderr, "%s: trying %s\n", progname, buf); | |
183 | # endif | |
184 | f = LOADFONT(buf); | |
185 | if (f) | |
186 | { | |
187 | # ifdef DEBUG | |
188 | fprintf (stderr, | |
189 | "%s: substituted \"%s\" for \"%s\"\n", | |
190 | progname, buf, xlfd); | |
191 | # endif | |
192 | return f; | |
193 | } | |
194 | } | |
195 | ||
196 | fprintf (stderr, "%s: unable to find any alternatives to \"%s\"\n", | |
197 | progname, xlfd); | |
198 | xlfd = "fixed"; | |
199 | return LOADFONT(xlfd); | |
200 | } | |
201 | } | |
202 | # endif /* !HAVE_JWXYZ */ | |
203 | } | |
204 | ||
205 | XFontStruct * | |
206 | load_font_retry (Display *dpy, const char *xlfd) | |
207 | { | |
208 | return (XFontStruct *) load_font_retry_1 (dpy, 0, xlfd, 0); | |
209 | } | |
210 | ||
211 | #ifdef USE_XFT | |
212 | XftFont * | |
213 | load_xft_font_retry (Display *dpy, int screen, const char *xlfd) | |
214 | { | |
215 | return (XftFont *) load_font_retry_1 (dpy, screen, xlfd, 1); | |
216 | } | |
217 | ||
218 | #elif defined(HAVE_JWXYZ) | |
219 | ||
220 | XftFont * | |
221 | load_xft_font_retry (Display *dpy, int screen, const char *xlfd) | |
222 | { | |
223 | return XftFontOpenXlfd (dpy, screen, xlfd); | |
224 | } | |
225 | ||
226 | #endif /* !HAVE_JWXYZ */ |