From http://www.jwz.org/xscreensaver/xscreensaver-5.40.tar.gz
[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 "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 static void *
29 load_font_retry_1 (Display *dpy, int screen, const char *xlfd, Bool xft_p)
30 {
31
32 # ifdef USE_XFT
33 #  define LOADFONT() (xft_p \
34                       ? (void *) XftFontOpenXlfd (dpy, screen, xlfd) \
35                       : (void *) XLoadQueryFont (dpy, xlfd))
36 # else
37 #  define LOADFONT() ((void *) XLoadQueryFont (dpy, xlfd))
38 # endif
39
40   void *f = LOADFONT();
41
42 # ifndef USE_XFT
43   if (xft_p) abort();
44 # endif
45
46 # ifdef HAVE_JWXYZ
47   return f;
48 # else /* !HAVE_JWXYZ */
49   if (f)
50     return f;
51   else
52     {
53       Bool bold_p   = (!!strcasestr (xlfd, "-bold-"));
54       Bool italic_p = (!!strcasestr (xlfd, "-i-") ||
55                        !!strcasestr (xlfd, "-o-"));
56       Bool fixed_p  = (!!strcasestr (xlfd, "courier") ||
57                        !!strcasestr (xlfd, "-ocr") ||
58                        !!strcasestr (xlfd, "-m-") ||
59                        !!strcasestr (xlfd, "-c-"));
60       int size = 0;
61
62       if (!strcmp (xlfd, "vga"))  /* BSOD uses this: it has no XLFD name. */
63         fixed_p = True, size = 120;
64
65       /* Look for the first number in the string like "-180-" */
66       if (! size)
67         {
68           const char *s;
69           for (s = xlfd; *s; s++)
70             if (s[0] == '-' && s[1] >= '0' && s[1] <= '9')
71               {
72                 int i = s[1] - '0';
73                 const char *s2 = s+2;
74                 while (*s2 >= '0' && *s2 <= '9')
75                   {
76                     i = i * 10 + *s2 - '0';
77                     s2++;
78                   }
79                 if (*s2 != '-') continue;          /* Number ends with dash */
80                 if (i < 60 || i >= 2000) continue; /* In range 6pt - 200pt */
81                 if (i % 10) continue;              /* Multiple of 10 */
82
83                 size = i;
84                 break;
85               }
86         }
87
88       if (! size)
89         {
90           fprintf (stderr, "%s: unloadable, unparsable font: \"%s\"\n",
91                    progname, xlfd);
92           xlfd = "fixed";
93           return LOADFONT();
94         }
95       else
96         {
97           const char *fixed[] = { "courier",
98                                   "courier new",
99                                   "courier 10 pitch",
100                                   "lucidatypewriter",
101                                   "american typewriter",
102                                   "fixed",
103                                   "ocr a std",
104                                   "*" };
105           const char *variable[] = { "helvetica",
106                                      "arial",
107                                      "bitstream vera sans",
108                                      "gill sans",
109                                      "times",
110                                      "times new roman",
111                                      "new century schoolbook",
112                                      "utopia",
113                                      "palatino",
114                                      "lucida",
115                                      "bitstream charter",
116                                      "*" };
117           const char *charsets[] = { "iso10646-1", "iso8859-1", "*-*" };
118           const char *weights[]  = { "bold", "medium" };
119           const char *slants[]   = { "o", "i", "r" };
120           const char *spacings[] = { "m", "c", "p" };
121           int a, b, c, d, e, g;
122           char buf[1024];
123
124           for (a = 0; a < countof(charsets); a++)
125             for (b = (bold_p ? 0 : 1); b < countof(weights); b++)
126               for (c = (italic_p ? 0 : 2); c < countof(slants); c++)
127                 for (d = 0;
128                      d < (fixed_p ? countof(fixed) : countof(variable));
129                      d++)
130                   for (g = size; g >= 60; g -= 10)
131                     for (e = (fixed_p ? 0 : 2); e < countof(spacings); e++)
132                       {
133                         sprintf (buf,
134                                  "-%s-%s-%s-%s-%s-%s-%s-%d-%s-%s-%s-%s-%s",
135                                  "*",                   /* foundry */
136                                  (fixed_p ? fixed[d] : variable[d]),
137                                  weights[b],
138                                  slants[c],
139                                  "*",                   /* set width */
140                                  "*",                   /* add style */
141                                  "*",                   /* pixel size */
142                                  g,                     /* point size */
143                                  "*",                   /* x resolution */
144                                  "*",                   /* y resolution */
145                                  spacings[e],
146                                  "*",                   /* average width */
147                                  charsets[a]);
148                         /* fprintf(stderr, "%s: trying %s\n", progname, buf);*/
149                         f = LOADFONT();
150                         if (f)
151                           {
152                             /* fprintf (stderr,
153                                      "%s: substituted \"%s\" for \"%s\"\n",
154                                      progname, buf, xlfd); */
155                             return f;
156                           }
157                       }
158
159           fprintf (stderr, "%s: unable to find any alternatives to \"%s\"\n",
160                    progname, xlfd);
161           xlfd = "fixed";
162           return LOADFONT();
163         }
164     }
165 # endif /* !HAVE_JWXYZ */
166 }
167
168 XFontStruct *
169 load_font_retry (Display *dpy, const char *xlfd)
170 {
171   return (XFontStruct *) load_font_retry_1 (dpy, 0, xlfd, 0);
172 }
173
174 #ifdef USE_XFT
175 XftFont *
176 load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
177 {
178   return (XftFont *) load_font_retry_1 (dpy, screen, xlfd, 1);
179 }
180
181 #elif defined(HAVE_JWXYZ)
182
183 XftFont *
184 load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
185 {
186   return XftFontOpenXlfd (dpy, screen, xlfd);
187 }
188
189 #endif /* !HAVE_JWXYZ */