395ffbe58f66dd31090aaacacf2b16dc29876e20
[xscreensaver] / utils / font-retry.c
1 /* xscreensaver, Copyright (c) 2018 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 "font-retry.h"
20
21 extern const char *progname;
22
23 #undef countof
24 #define countof(x) (sizeof((x))/sizeof((*x)))
25
26 XFontStruct *
27 load_font_retry (Display *dpy, const char *xlfd)
28 {
29   XFontStruct *f = XLoadQueryFont (dpy, xlfd);
30 # ifdef HAVE_JWXYZ
31   return f;
32 # else
33   if (f)
34     return f;
35   else
36     {
37       Bool bold_p   = (!!strcasestr (xlfd, "-bold-"));
38       Bool italic_p = (!!strcasestr (xlfd, "-i-") ||
39                        !!strcasestr (xlfd, "-o-"));
40       Bool fixed_p  = (!!strcasestr (xlfd, "courier") ||
41                        !!strcasestr (xlfd, "-ocr") ||
42                        !!strcasestr (xlfd, "-m-") ||
43                        !!strcasestr (xlfd, "-c-"));
44       int size = 0;
45
46       if (!strcmp (xlfd, "vga"))  /* BSOD uses this: it has no XLFD name. */
47         fixed_p = True, size = 120;
48
49       /* Look for the first number in the string like "-180-" */
50       if (! size)
51         {
52           const char *s;
53           for (s = xlfd; *s; s++)
54             if (s[0] == '-' && s[1] >= '0' && s[1] <= '9')
55               {
56                 int i = s[1] - '0';
57                 const char *s2 = s+2;
58                 while (*s2 >= '0' && *s2 <= '9')
59                   {
60                     i = i * 10 + *s2 - '0';
61                     s2++;
62                   }
63                 if (*s2 != '-') continue;          /* Number ends with dash */
64                 if (i < 60 || i >= 2000) continue; /* In range 6pt - 200pt */
65                 if (i % 10) continue;              /* Multiple of 10 */
66
67                 size = i;
68                 break;
69               }
70         }
71
72       if (! size)
73         {
74           fprintf (stderr, "%s: unloadable, unparsable font: \"%s\"\n",
75                    progname, xlfd);
76           return XLoadQueryFont (dpy, "fixed");
77         }
78       else
79         {
80           const char *fixed[] = { "courier",
81                                   "courier new",
82                                   "courier 10 pitch",
83                                   "lucidatypewriter",
84                                   "american typewriter",
85                                   "fixed",
86                                   "ocr a std",
87                                   "*" };
88           const char *variable[] = { "helvetica",
89                                      "arial",
90                                      "bitstream vera sans",
91                                      "gill sans",
92                                      "times",
93                                      "times new roman",
94                                      "new century schoolbook",
95                                      "utopia",
96                                      "palatino",
97                                      "lucida",
98                                      "bitstream charter",
99                                      "*" };
100           const char *charsets[] = { "iso10646-1", "iso8859-1", "*-*" };
101           const char *weights[]  = { "bold", "medium" };
102           const char *slants[]   = { "o", "i", "r" };
103           const char *spacings[] = { "m", "c", "p" };
104           int a, b, c, d, e, g;
105           char buf[1024];
106
107           for (a = 0; a < countof(charsets); a++)
108             for (b = (bold_p ? 0 : 1); b < countof(weights); b++)
109               for (c = (italic_p ? 0 : 2); c < countof(slants); c++)
110                 for (d = 0;
111                      d < (fixed_p ? countof(fixed) : countof(variable));
112                      d++)
113                   for (g = size; g >= 60; g -= 10)
114                     for (e = (fixed_p ? 0 : 2); e < countof(spacings); e++)
115                       {
116                         sprintf (buf,
117                                  "-%s-%s-%s-%s-%s-%s-%s-%d-%s-%s-%s-%s-%s",
118                                  "*",                   /* foundry */
119                                  (fixed_p ? fixed[d] : variable[d]),
120                                  weights[b],
121                                  slants[c],
122                                  "*",                   /* set width */
123                                  "*",                   /* add style */
124                                  "*",                   /* pixel size */
125                                  g,                     /* point size */
126                                  "*",                   /* x resolution */
127                                  "*",                   /* y resolution */
128                                  spacings[e],
129                                  "*",                   /* average width */
130                                  charsets[a]);
131                         /* fprintf(stderr, "%s: trying %s\n", progname, buf);*/
132                         f = XLoadQueryFont (dpy, buf);
133                         if (f)
134                           {
135                             /* fprintf (stderr,
136                                      "%s: substituted \"%s\" for \"%s\"\n",
137                                      progname, buf, xlfd); */
138                             return f;
139                           }
140                       }
141
142           fprintf (stderr, "%s: unable to find any alternatives to \"%s\"\n",
143                    progname, xlfd);
144           return XLoadQueryFont (dpy, "fixed");
145         }
146     }
147 # endif
148 }