Added missing newline in NEDsim error message.
[screensavers] / screenhack / xft.c
CommitLineData
3144ee8a
AT
1/* xscreensaver, Copyright (c) 2014-2018 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/* Compatibility layer using XDrawString, XDrawString16() or Xutf8DrawString().
13 This layer is used by X11 systems without Xft, and by MacOS / iOS.
14 */
15
16#ifdef HAVE_CONFIG_H
17# include "config.h"
18#endif
19
20#ifndef HAVE_XFT
21
22# include "utils.h"
23# include "resources.h"
24# include "xft.h"
25# include "utf8wc.h"
26
27extern const char *progname;
28
29struct _XftDraw {
30 Display *dpy;
31 Drawable drawable;
32 GC gc;
33 unsigned long pixel;
34 Font fid;
35 Visual *visual;
36 Colormap colormap;
37};
38
39
40XftFont *
41XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd)
42{
43 XftFont *ff = (XftFont *) calloc (1, sizeof(*ff));
44
45 if (!dpy || !xlfd) abort();
46 if (!ff) return 0;
47 ff->xfont = XLoadQueryFont (dpy, xlfd);
48 if (!ff->xfont)
49 {
50 free (ff);
51 return 0;
52 }
53
54 ff->name = strdup (xlfd);
55 ff->ascent = ff->xfont->ascent;
56 ff->descent = ff->xfont->descent;
57 ff->height = ff->ascent + ff->descent;
58
59# ifdef HAVE_XUTF8DRAWSTRING
60 {
61 unsigned i;
62
63 // In the event of -*-random-* (under JWXYZ), get the actual XLFD,
64 // otherwise we'll get another random font that doesn't match ff->xfont.
65 char *xlfd_resolved = NULL;
66
67 char **missing_charset_list_return;
68 int missing_charset_count_return;
69 char *def_string_return;
70
71 char *ss;
72
73 for (i = 0; i != ff->xfont->n_properties; ++i) {
74 if (ff->xfont->properties[i].name == XA_FONT) {
75 xlfd_resolved = XGetAtomName (dpy, ff->xfont->properties[i].card32);
76 if (xlfd_resolved)
77 xlfd = xlfd_resolved;
78 break;
79 }
80 }
81
82 ss = (char *) malloc (strlen(xlfd) + 10);
83 strcpy (ss, xlfd);
84 strcat (ss, ",*");
85 ff->fontset = XCreateFontSet (dpy, ss,
86 &missing_charset_list_return,
87 &missing_charset_count_return,
88 &def_string_return);
89
90# if 0
91 {
92 int i;
93 for (i = 0; i < missing_charset_count_return; i++)
94 fprintf (stderr, "%s: missing charset: %s\n",
95 ss, missing_charset_list_return[i]);
96 }
97# endif
98
99 /* Apparently this is not to be freed. */
100 /* if (def_string_return) XFree (def_string_return); */
101
102 if (missing_charset_list_return)
103 XFreeStringList (missing_charset_list_return);
104
105 free (ss);
106 free (xlfd_resolved);
107 }
108# endif
109
110 return ff;
111}
112
113
114void
115XftFontClose (Display *dpy, XftFont *font)
116{
117 if (!dpy || !font) abort();
118 free (font->name);
119 XFreeFont (dpy, font->xfont);
120# ifdef HAVE_XUTF8DRAWSTRING
121 XFreeFontSet (dpy, font->fontset);
122# endif
123 free (font);
124}
125
126
127Bool
128XftColorAllocName (Display *dpy,
129 _Xconst Visual *visual,
130 Colormap cmap,
131 _Xconst char *name,
132 XftColor *result)
133{
134 XColor color;
135 if (!dpy || !visual || !name || !result) abort();
136
137 if (! XParseColor (dpy, cmap, name, &color))
138 {
139 fprintf (stderr, "%s: can't parse color %s", progname, name);
140 return False;
141 }
142 else if (! XAllocColor (dpy, cmap, &color))
143 {
144 fprintf (stderr, "%s: couldn't allocate color %s", progname, name);
145 return False;
146 }
147 else
148 {
149 XRenderColor color2;
150 color2.red = color.red;
151 color2.green = color.green;
152 color2.blue = color.blue;
153 color2.alpha = 0xFFFF;
154 XftColorAllocValue (dpy, visual, cmap, &color2, result);
155 result->pixel = color.pixel;
156 return True;
157 }
158}
159
160
161static short
162maskbase (unsigned long m)
163{
164 short i;
165 if (!m)
166 return 0;
167 i = 0;
168 while (! (m&1))
169 {
170 m >>= 1;
171 i++;
172 }
173 return i;
174}
175
176
177static short
178masklen (unsigned long m)
179{
180 unsigned long y;
181 y = (m >> 1) & 033333333333;
182 y = m - y - ((y >>1) & 033333333333);
183 return (short) (((y + (y >> 3)) & 030707070707) % 077);
184}
185
186
187Bool
188XftColorAllocValue (Display *dpy,
189 _Xconst Visual *visual,
190 Colormap cmap,
191 _Xconst XRenderColor *color,
192 XftColor *result)
193{
194 if (!dpy || !visual || !color || !result) abort();
195 if (visual->class == TrueColor)
196 {
197 int red_shift = maskbase (visual->red_mask);
198 int red_len = masklen (visual->red_mask);
199 int green_shift = maskbase (visual->green_mask);
200 int green_len = masklen (visual->green_mask);
201 int blue_shift = maskbase (visual->blue_mask);
202 int blue_len = masklen (visual->blue_mask);
203 result->pixel = (((color->red >> (16 - red_len)) << red_shift) |
204 ((color->green >> (16 - green_len)) << green_shift) |
205 ((color->blue >> (16 - blue_len)) << blue_shift));
206# ifdef HAVE_JWXYZ
207 result->pixel |= BlackPixel(dpy, 0); /* alpha */
208# endif
209 }
210 else
211 {
212 XColor xcolor;
213 xcolor.red = color->red;
214 xcolor.green = color->green;
215 xcolor.blue = color->blue;
216 if (!XAllocColor (dpy, cmap, &xcolor))
217 return False;
218 result->pixel = xcolor.pixel;
219 }
220 result->color.red = color->red;
221 result->color.green = color->green;
222 result->color.blue = color->blue;
223 result->color.alpha = color->alpha;
224 return True;
225}
226
227
228void
229XftColorFree (Display *dpy,
230 Visual *visual,
231 Colormap cmap,
232 XftColor *color)
233{
234 if (!dpy || !visual || !color) abort();
235 if (visual->class != TrueColor)
236 XFreeColors (dpy, cmap, &color->pixel, 1, 0);
237}
238
239
240XftDraw *
241XftDrawCreate (Display *dpy,
242 Drawable drawable,
243 Visual *visual,
244 Colormap colormap)
245{
246 XftDraw *dd = (XftDraw *) calloc (1, sizeof(*dd));
247 if (!dpy || !drawable || !visual) abort();
248 if (!dd) return 0;
249
250 dd->dpy = dpy;
251 dd->drawable = drawable;
252 dd->visual = visual;
253 dd->colormap = colormap;
254 dd->gc = XCreateGC (dpy, drawable, 0, 0);
255 return dd;
256}
257
258
259void
260XftDrawDestroy (XftDraw *draw)
261{
262 if (!draw) abort();
263 XFreeGC (draw->dpy, draw->gc);
264 free (draw);
265}
266
267
268void
269XftTextExtentsUtf8 (Display *dpy,
270 XftFont *font,
271 _Xconst FcChar8 *string,
272 int len,
273 XGlyphInfo *extents)
274{
275 XCharStruct overall;
276
277 if (!dpy || !font || !string || !extents) abort();
278
279# ifdef HAVE_XUTF8DRAWSTRING
280 {
281 XRectangle ink;
282 int advancement =
283 Xutf8TextExtents (font->fontset, (const char *) string, len, &ink, 0);
284 XmbRectangle_to_XCharStruct (ink, overall, advancement);
285 }
286# else /* !HAVE_XUTF8DRAWSTRING */
287 {
288 char *s2 = (char *) malloc (len + 1);
289 int direction, ascent, descent;
290 XChar2b *s16;
291 int s16_len = 0;
292 strncpy (s2, (char *) string, len);
293 s2[len] = 0;
294 s16 = utf8_to_XChar2b (s2, &s16_len);
295 XTextExtents16 (font->xfont, s16, s16_len,
296 &direction, &ascent, &descent, &overall);
297 free (s2);
298 free (s16);
299 }
300# endif /* !HAVE_XUTF8DRAWSTRING */
301
302 XCharStruct_to_XGlyphInfo (overall, *extents);
303}
304
305
306void
307XftDrawStringUtf8 (XftDraw *draw,
308 _Xconst XftColor *color,
309 XftFont *font,
310 int x,
311 int y,
312 _Xconst FcChar8 *string,
313 int len)
314{
315 if (!draw || !color || !font || !string) abort();
316
317 if (color->pixel != draw->pixel)
318 {
319 XSetForeground (draw->dpy, draw->gc, color->pixel);
320 draw->pixel = color->pixel;
321 }
322 if (font->xfont->fid != draw->fid)
323 {
324 XSetFont (draw->dpy, draw->gc, font->xfont->fid);
325 draw->fid = font->xfont->fid;
326 }
327
328# ifdef HAVE_XUTF8DRAWSTRING
329 /* If we have Xutf8DrawString, use it instead of XDrawString16 because
330 there is some chance it will handle characters of more than 16 bits
331 (beyond the Basic Multilingual Plane).
332 */
333
334 /* #### I guess I don't really understand how FontSet works, because when
335 using the real X11 implementation of Xutf8DrawString, this seems
336 to just truncate the text at the first non-ASCII character.
337
338 The XDrawString16() path works, however, at the expense of losing
339 everything above Basic Multilingual. However, that path is only
340 taken on X11 systems that are old enough to not have libXft,
341 which means that the chance of Unicode working was already slim.
342 */
343 Xutf8DrawString (draw->dpy, draw->drawable, font->fontset, draw->gc, x, y,
344 (const char *) string, len);
345# else
346 {
347 int s16_len = 0;
348 char *s2 = (char *) malloc (len + 1);
349 XChar2b *s16;
350 strncpy (s2, (char *) string, len);
351 s2[len] = 0;
352 s16 = utf8_to_XChar2b (s2, &s16_len);
353 free (s2);
354 XDrawString16 (draw->dpy, draw->drawable, draw->gc, x, y, s16, s16_len);
355 free (s16);
356 }
357# endif
358}
359
360#else /* HAVE_XFT */
361
362const int Wempty_translation_unit_is_a_dumb_warning = 0;
363
364#endif /* HAVE_XFT */