From http://www.jwz.org/xscreensaver/xscreensaver-5.31.tar.gz
[xscreensaver] / utils / xft.c
diff --git a/utils/xft.c b/utils/xft.c
new file mode 100644 (file)
index 0000000..690586d
--- /dev/null
@@ -0,0 +1,339 @@
+/* xscreensaver, Copyright (c) 2014 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+/* Compatibility layer using XDrawString, XDrawString16() or Xutf8DrawString().
+   This layer is used by X11 systems without Xft, and by MacOS / iOS.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef HAVE_XFT
+
+# include "utils.h"
+# include "resources.h"
+# include "xft.h"
+# include "utf8wc.h"
+
+extern const char *progname;
+
+struct _XftDraw {
+  Display   *dpy;
+  Drawable  drawable;
+  GC gc;
+  unsigned long pixel;
+  Font fid;
+  Visual *visual;
+  Colormap  colormap;
+};
+
+
+XftFont *
+XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd)
+{
+  XftFont *ff = (XftFont *) calloc (1, sizeof(*ff));
+
+  if (!dpy || !xlfd) abort();
+  if (!ff) return 0;
+  ff->xfont = XLoadQueryFont (dpy, xlfd);
+  if (!ff->xfont)
+    {
+      free (ff);
+      return 0;
+    }
+
+  ff->name = strdup (xlfd);
+  ff->ascent  = ff->xfont->ascent;
+  ff->descent = ff->xfont->descent;
+  ff->height = ff->ascent + ff->descent;
+
+# ifdef HAVE_XUTF8DRAWSTRING
+  {
+    char **missing_charset_list_return;
+    int missing_charset_count_return;
+    char *def_string_return;
+
+    char *ss = (char *) malloc (strlen(xlfd) + 10);
+    strcpy (ss, xlfd);
+    strcat (ss, ",*");
+    ff->fontset = XCreateFontSet (dpy, ss,
+                                  &missing_charset_list_return,
+                                  &missing_charset_count_return,
+                                  &def_string_return);
+
+# if 0
+    {
+      int i;
+      for (i = 0; i < missing_charset_count_return; i++)
+        fprintf (stderr, "%s: missing charset: %s\n",
+                 ss, missing_charset_list_return[i]);
+    }
+# endif
+
+    /* Apparently this is not to be freed. */
+    /* if (def_string_return) XFree (def_string_return); */
+
+    if (missing_charset_list_return)
+      XFreeStringList (missing_charset_list_return);
+
+    free (ss);
+  }
+# endif
+
+  return ff;
+}
+
+
+void
+XftFontClose (Display *dpy, XftFont *font)
+{
+  if (!dpy || !font) abort();
+  free (font->name);
+  XFreeFont (dpy, font->xfont);
+# ifdef HAVE_XUTF8DRAWSTRING
+  XFreeFontSet (dpy, font->fontset);
+# endif
+  free (font);
+}
+
+
+Bool
+XftColorAllocName (Display  *dpy,
+                  _Xconst Visual *visual,
+                  Colormap cmap,
+                  _Xconst char *name,
+                  XftColor *result)
+{
+  XColor color;
+  if (!dpy || !visual || !name || !result) abort();
+
+  if (! XParseColor (dpy, cmap, name, &color))
+    {
+      fprintf (stderr, "%s: can't parse color %s", progname, name);
+      return False;
+    }
+  else if (! XAllocColor (dpy, cmap, &color))
+    {
+      fprintf (stderr, "%s: couldn't allocate color %s", progname, name);
+      return False;
+    }
+  else
+    {
+      XRenderColor color2;
+      color2.red    = color.red;
+      color2.green  = color.green;
+      color2.blue   = color.blue;
+      color2.alpha  = 0xFFFF;
+      XftColorAllocValue (dpy, visual, cmap, &color2, result);
+      result->pixel = color.pixel;
+      return True;
+    }
+}
+
+
+static short
+maskbase (unsigned long m)
+{
+  short i;
+  if (!m)
+    return 0;
+  i = 0;
+  while (! (m&1))
+    {
+      m >>= 1;
+      i++;
+    }
+  return i;
+}
+
+
+static short
+masklen (unsigned long m)
+{
+  unsigned long y;
+  y = (m >> 1) & 033333333333;
+  y = m - y - ((y >>1) & 033333333333);
+  return (short) (((y + (y >> 3)) & 030707070707) % 077);
+}
+
+
+Bool
+XftColorAllocValue (Display *dpy,
+                   _Xconst Visual *visual,
+                   Colormap cmap,
+                   _Xconst XRenderColor *color,
+                   XftColor *result)
+{
+  if (!dpy || !visual || !color || !result) abort();
+  if (visual->class == TrueColor)
+    {
+      int red_shift, red_len;
+      int green_shift, green_len;
+      int blue_shift, blue_len;
+
+      red_shift   = maskbase (visual->red_mask);
+      red_len     = masklen  (visual->red_mask);
+      green_shift = maskbase (visual->green_mask);
+      green_len   = masklen (visual->green_mask);
+      blue_shift  = maskbase (visual->blue_mask);
+      blue_len    = masklen (visual->blue_mask);
+      result->pixel = (((color->red   >> (16 - red_len))   << red_shift)   |
+                       ((color->green >> (16 - green_len)) << green_shift) |
+                       ((color->blue  >> (16 - blue_len))  << blue_shift));
+# ifdef HAVE_COCOA
+      result->pixel |= BlackPixel(dpy, 0);  /* alpha */
+# endif
+    }
+  else
+    {
+      XColor xcolor;
+      xcolor.red   = color->red;
+      xcolor.green = color->green;
+      xcolor.blue  = color->blue;
+      if (!XAllocColor (dpy, cmap, &xcolor))
+        return False;
+      result->pixel = xcolor.pixel;
+    }
+  result->color.red   = color->red;
+  result->color.green = color->green;
+  result->color.blue  = color->blue;
+  result->color.alpha = color->alpha;
+  return True;
+}
+
+
+void
+XftColorFree (Display *dpy,
+              Visual *visual,
+              Colormap cmap,
+              XftColor *color)
+{
+  if (!dpy || !visual || !color) abort();
+  if (visual->class != TrueColor)
+    XFreeColors (dpy, cmap, &color->pixel, 1, 0);
+}
+
+
+XftDraw *
+XftDrawCreate (Display   *dpy,
+              Drawable  drawable,
+              Visual    *visual,
+              Colormap  colormap)
+{
+  XftDraw *dd = (XftDraw *) calloc (1, sizeof(*dd));
+  if (!dpy || !drawable || !visual) abort();
+  if (!dd) return 0;
+
+  dd->dpy = dpy;
+  dd->drawable = drawable;
+  dd->visual = visual;
+  dd->colormap = colormap;
+  dd->gc = XCreateGC (dpy, drawable, 0, 0);
+  return dd;
+}
+
+
+void
+XftDrawDestroy (XftDraw        *draw)
+{
+  if (!draw) abort();
+  XFreeGC (draw->dpy, draw->gc);
+  free (draw);
+}
+
+
+void
+XftTextExtentsUtf8 (Display        *dpy,
+                   XftFont         *font,
+                   _Xconst FcChar8 *string,
+                   int             len,
+                   XGlyphInfo      *extents)
+{
+  int direction, ascent, descent;
+  XCharStruct overall;
+  XChar2b *s16;
+  int s16_len = 0;
+  char *s2 = (char *) malloc (len + 1);
+
+  if (!dpy || !font || !string || !extents || !s2) abort();
+
+  strncpy (s2, (char *) string, len);
+  s2[len] = 0;
+  s16 = utf8_to_XChar2b (s2, &s16_len);
+  free (s2);
+  XTextExtents16 (font->xfont, s16, s16_len,
+                  &direction, &ascent, &descent, &overall);
+  free (s16);
+
+  extents->x      = -overall.lbearing;
+  extents->y      =  overall.ascent;
+  extents->xOff   =  overall.width;
+  extents->yOff   =  0;
+  extents->width  =  overall.rbearing - overall.lbearing;
+  extents->height =  overall.ascent + overall.descent;
+}
+
+
+void
+XftDrawStringUtf8 (XftDraw         *draw,
+                  _Xconst XftColor *color,
+                  XftFont          *font,
+                  int              x,
+                  int              y,
+                  _Xconst FcChar8  *string,
+                  int              len)
+{
+  if (!draw || !color || !font || !string) abort();
+
+  if (color->pixel != draw->pixel)
+    {
+      XSetForeground (draw->dpy, draw->gc, color->pixel);
+      draw->pixel = color->pixel;
+    }
+  if (font->xfont->fid != draw->fid)
+    {
+      XSetFont (draw->dpy, draw->gc, font->xfont->fid);
+      draw->fid = font->xfont->fid;
+    }
+
+# ifdef HAVE_XUTF8DRAWSTRING
+  /* If we have Xutf8DrawString, use it instead of XDrawString16 because
+     there is some chance it will handle characters of more than 16 bits
+     (beyond the Basic Multilingual Plane).
+   */
+
+  /* #### I guess I don't really understand how FontSet works, because this
+          seems to just truncate the text at the first non-ASCII character.
+          The XDrawString16() path works, however.
+   */
+  Xutf8DrawString (draw->dpy, draw->drawable, font->fontset, draw->gc, x, y, 
+                   (const char *) string, len);
+# else
+  {
+    int s16_len = 0;
+    char *s2 = (char *) malloc (len + 1);
+    XChar2b *s16;
+    strncpy (s2, (char *) string, len);
+    s2[len] = 0;
+    s16 = utf8_to_XChar2b (s2, &s16_len);
+    free (s2);
+    XDrawString16 (draw->dpy, draw->drawable, draw->gc, x, y, s16, s16_len);
+    free (s16);
+  }
+# endif
+}
+
+#else  /* HAVE_XFT */
+
+const int Wempty_translation_unit_is_a_dumb_warning = 0;
+
+#endif /* HAVE_XFT */