From http://www.jwz.org/xscreensaver/xscreensaver-5.31.tar.gz
[xscreensaver] / utils / xft.c
1 /* xscreensaver, Copyright (c) 2014 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
27 extern const char *progname;
28
29 struct _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
40 XftFont *
41 XftFontOpenXlfd (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     char **missing_charset_list_return;
62     int missing_charset_count_return;
63     char *def_string_return;
64
65     char *ss = (char *) malloc (strlen(xlfd) + 10);
66     strcpy (ss, xlfd);
67     strcat (ss, ",*");
68     ff->fontset = XCreateFontSet (dpy, ss,
69                                   &missing_charset_list_return,
70                                   &missing_charset_count_return,
71                                   &def_string_return);
72
73 # if 0
74     {
75       int i;
76       for (i = 0; i < missing_charset_count_return; i++)
77         fprintf (stderr, "%s: missing charset: %s\n",
78                  ss, missing_charset_list_return[i]);
79     }
80 # endif
81
82     /* Apparently this is not to be freed. */
83     /* if (def_string_return) XFree (def_string_return); */
84
85     if (missing_charset_list_return)
86       XFreeStringList (missing_charset_list_return);
87
88     free (ss);
89   }
90 # endif
91
92   return ff;
93 }
94
95
96 void
97 XftFontClose (Display *dpy, XftFont *font)
98 {
99   if (!dpy || !font) abort();
100   free (font->name);
101   XFreeFont (dpy, font->xfont);
102 # ifdef HAVE_XUTF8DRAWSTRING
103   XFreeFontSet (dpy, font->fontset);
104 # endif
105   free (font);
106 }
107
108
109 Bool
110 XftColorAllocName (Display  *dpy,
111                    _Xconst Visual *visual,
112                    Colormap cmap,
113                    _Xconst char *name,
114                    XftColor *result)
115 {
116   XColor color;
117   if (!dpy || !visual || !name || !result) abort();
118
119   if (! XParseColor (dpy, cmap, name, &color))
120     {
121       fprintf (stderr, "%s: can't parse color %s", progname, name);
122       return False;
123     }
124   else if (! XAllocColor (dpy, cmap, &color))
125     {
126       fprintf (stderr, "%s: couldn't allocate color %s", progname, name);
127       return False;
128     }
129   else
130     {
131       XRenderColor color2;
132       color2.red    = color.red;
133       color2.green  = color.green;
134       color2.blue   = color.blue;
135       color2.alpha  = 0xFFFF;
136       XftColorAllocValue (dpy, visual, cmap, &color2, result);
137       result->pixel = color.pixel;
138       return True;
139     }
140 }
141
142
143 static short
144 maskbase (unsigned long m)
145 {
146   short i;
147   if (!m)
148     return 0;
149   i = 0;
150   while (! (m&1))
151     {
152       m >>= 1;
153       i++;
154     }
155   return i;
156 }
157
158
159 static short
160 masklen (unsigned long m)
161 {
162   unsigned long y;
163   y = (m >> 1) & 033333333333;
164   y = m - y - ((y >>1) & 033333333333);
165   return (short) (((y + (y >> 3)) & 030707070707) % 077);
166 }
167
168
169 Bool
170 XftColorAllocValue (Display *dpy,
171                     _Xconst Visual *visual,
172                     Colormap cmap,
173                     _Xconst XRenderColor *color,
174                     XftColor *result)
175 {
176   if (!dpy || !visual || !color || !result) abort();
177   if (visual->class == TrueColor)
178     {
179       int red_shift, red_len;
180       int green_shift, green_len;
181       int blue_shift, blue_len;
182
183       red_shift   = maskbase (visual->red_mask);
184       red_len     = masklen  (visual->red_mask);
185       green_shift = maskbase (visual->green_mask);
186       green_len   = masklen (visual->green_mask);
187       blue_shift  = maskbase (visual->blue_mask);
188       blue_len    = masklen (visual->blue_mask);
189       result->pixel = (((color->red   >> (16 - red_len))   << red_shift)   |
190                        ((color->green >> (16 - green_len)) << green_shift) |
191                        ((color->blue  >> (16 - blue_len))  << blue_shift));
192 # ifdef HAVE_COCOA
193       result->pixel |= BlackPixel(dpy, 0);  /* alpha */
194 # endif
195     }
196   else
197     {
198       XColor xcolor;
199       xcolor.red   = color->red;
200       xcolor.green = color->green;
201       xcolor.blue  = color->blue;
202       if (!XAllocColor (dpy, cmap, &xcolor))
203         return False;
204       result->pixel = xcolor.pixel;
205     }
206   result->color.red   = color->red;
207   result->color.green = color->green;
208   result->color.blue  = color->blue;
209   result->color.alpha = color->alpha;
210   return True;
211 }
212
213
214 void
215 XftColorFree (Display *dpy,
216               Visual *visual,
217               Colormap cmap,
218               XftColor *color)
219 {
220   if (!dpy || !visual || !color) abort();
221   if (visual->class != TrueColor)
222     XFreeColors (dpy, cmap, &color->pixel, 1, 0);
223 }
224
225
226 XftDraw *
227 XftDrawCreate (Display   *dpy,
228                Drawable  drawable,
229                Visual    *visual,
230                Colormap  colormap)
231 {
232   XftDraw *dd = (XftDraw *) calloc (1, sizeof(*dd));
233   if (!dpy || !drawable || !visual) abort();
234   if (!dd) return 0;
235
236   dd->dpy = dpy;
237   dd->drawable = drawable;
238   dd->visual = visual;
239   dd->colormap = colormap;
240   dd->gc = XCreateGC (dpy, drawable, 0, 0);
241   return dd;
242 }
243
244
245 void
246 XftDrawDestroy (XftDraw *draw)
247 {
248   if (!draw) abort();
249   XFreeGC (draw->dpy, draw->gc);
250   free (draw);
251 }
252
253
254 void
255 XftTextExtentsUtf8 (Display         *dpy,
256                     XftFont         *font,
257                     _Xconst FcChar8 *string,
258                     int             len,
259                     XGlyphInfo      *extents)
260 {
261   int direction, ascent, descent;
262   XCharStruct overall;
263   XChar2b *s16;
264   int s16_len = 0;
265   char *s2 = (char *) malloc (len + 1);
266
267   if (!dpy || !font || !string || !extents || !s2) abort();
268
269   strncpy (s2, (char *) string, len);
270   s2[len] = 0;
271   s16 = utf8_to_XChar2b (s2, &s16_len);
272   free (s2);
273   XTextExtents16 (font->xfont, s16, s16_len,
274                   &direction, &ascent, &descent, &overall);
275   free (s16);
276
277   extents->x      = -overall.lbearing;
278   extents->y      =  overall.ascent;
279   extents->xOff   =  overall.width;
280   extents->yOff   =  0;
281   extents->width  =  overall.rbearing - overall.lbearing;
282   extents->height =  overall.ascent + overall.descent;
283 }
284
285
286 void
287 XftDrawStringUtf8 (XftDraw          *draw,
288                    _Xconst XftColor *color,
289                    XftFont          *font,
290                    int              x,
291                    int              y,
292                    _Xconst FcChar8  *string,
293                    int              len)
294 {
295   if (!draw || !color || !font || !string) abort();
296
297   if (color->pixel != draw->pixel)
298     {
299       XSetForeground (draw->dpy, draw->gc, color->pixel);
300       draw->pixel = color->pixel;
301     }
302   if (font->xfont->fid != draw->fid)
303     {
304       XSetFont (draw->dpy, draw->gc, font->xfont->fid);
305       draw->fid = font->xfont->fid;
306     }
307
308 # ifdef HAVE_XUTF8DRAWSTRING
309   /* If we have Xutf8DrawString, use it instead of XDrawString16 because
310      there is some chance it will handle characters of more than 16 bits
311      (beyond the Basic Multilingual Plane).
312    */
313
314   /* #### I guess I don't really understand how FontSet works, because this
315           seems to just truncate the text at the first non-ASCII character.
316           The XDrawString16() path works, however.
317    */
318   Xutf8DrawString (draw->dpy, draw->drawable, font->fontset, draw->gc, x, y, 
319                    (const char *) string, len);
320 # else
321   {
322     int s16_len = 0;
323     char *s2 = (char *) malloc (len + 1);
324     XChar2b *s16;
325     strncpy (s2, (char *) string, len);
326     s2[len] = 0;
327     s16 = utf8_to_XChar2b (s2, &s16_len);
328     free (s2);
329     XDrawString16 (draw->dpy, draw->drawable, draw->gc, x, y, s16, s16_len);
330     free (s16);
331   }
332 # endif
333 }
334
335 #else  /* HAVE_XFT */
336
337 const int Wempty_translation_unit_is_a_dumb_warning = 0;
338
339 #endif /* HAVE_XFT */