Convert (most) functions in src to standard C.
[bpt/emacs.git] / src / xftfont.c
index 75cc061..68dd0af 100644 (file)
@@ -1,15 +1,15 @@
 /* xftfont.c -- XFT font driver.
-   Copyright (C) 2006 Free Software Foundation, Inc.
-   Copyright (C) 2006
+   Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H13PRO009
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -17,12 +17,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include <stdio.h>
+#include <setjmp.h>
 #include <X11/Xlib.h>
 #include <X11/Xft/Xft.h>
 
@@ -35,10 +34,13 @@ Boston, MA 02110-1301, USA.  */
 #include "charset.h"
 #include "fontset.h"
 #include "font.h"
+#include "ftfont.h"
 
 /* Xft font driver.  */
 
 static Lisp_Object Qxft;
+static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden,
+  QClcdfilter;
 
 /* The actual structure for Xft font that can be casted to struct
    font.  */
@@ -46,10 +48,18 @@ static Lisp_Object Qxft;
 struct xftfont_info
 {
   struct font font;
+  /* The following five members must be here in this order to be
+     compatible with struct ftfont_info (in ftfont.c).  */
+#ifdef HAVE_LIBOTF
+  int maybe_otf;         /* Flag to tell if this may be OTF or not.  */
+  OTF *otf;
+#endif /* HAVE_LIBOTF */
+  FT_Size ft_size;
+  int index;
+  FT_Matrix matrix;
   Display *display;
   int screen;
   XftFont *xftfont;
-  FT_Face ft_face;             /* set to XftLockFace (xftfont) */
 };
 
 /* Structure pointed by (struct face *)->extra  */
@@ -58,13 +68,11 @@ struct xftface_info
 {
   XftColor xft_fg;             /* color for face->foreground */
   XftColor xft_bg;             /* color for face->background */
-  XftDraw *xft_draw;
 };
 
-static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc,
-                                   struct xftface_info *,
-                                   XftColor *fg, XftColor *bg));
-static Font xftfont_default_fid P_ ((FRAME_PTR));
+static void xftfont_get_colors (FRAME_PTR, struct face *, GC gc,
+                                struct xftface_info *,
+                                XftColor *fg, XftColor *bg);
 
 
 /* Setup foreground and background colors of GC into FG and BG.  If
@@ -72,12 +80,7 @@ static Font xftfont_default_fid P_ ((FRAME_PTR));
    may be NULL.  */
 
 static void
-xftfont_get_colors (f, face, gc, xftface_info, fg, bg)
-     FRAME_PTR f;
-     struct face *face;
-     GC gc;
-     struct xftface_info *xftface_info;
-     XftColor *fg, *bg;
+xftfont_get_colors (FRAME_PTR f, struct face *face, GC gc, struct xftface_info *xftface_info, XftColor *fg, XftColor *bg)
 {
   if (xftface_info && face->gc == gc)
     {
@@ -132,163 +135,277 @@ xftfont_get_colors (f, face, gc, xftface_info, fg, bg)
     }
 }
 
-/* Return the default Font ID on frame F.  The Returned Font ID is
-   stored in the GC of the frame F, but the font is never used.  So,
-   any ID is ok as long as it is valid.  */
-
-static Font
-xftfont_default_fid (f)
-     FRAME_PTR f;
-{
-  static int fid_known;
-  static Font fid;
-
-  if (! fid_known)
-    {
-      fid = XLoadFont (FRAME_X_DISPLAY (f), "fixed");
-      if (! fid)
-       {
-         fid = XLoadFont (FRAME_X_DISPLAY (f), "*");
-         if (! fid)
-           abort ();
-       }
-      fid_known = 1;
-    }
-  return fid;
-}
-
-
-static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
-static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
-static struct font *xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
-static void xftfont_close P_ ((FRAME_PTR, struct font *));
-static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
-static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
-static unsigned xftfont_encode_char P_ ((struct font *, int));
-static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
-                                    struct font_metrics *));
-static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
 
-static int xftfont_anchor_point P_ ((struct font *, unsigned, int,
-                                    int *, int *));
+static Lisp_Object xftfont_list (Lisp_Object, Lisp_Object);
+static Lisp_Object xftfont_match (Lisp_Object, Lisp_Object);
+static Lisp_Object xftfont_open (FRAME_PTR, Lisp_Object, int);
+static void xftfont_close (FRAME_PTR, struct font *);
+static int xftfont_prepare_face (FRAME_PTR, struct face *);
+static void xftfont_done_face (FRAME_PTR, struct face *);
+static int xftfont_has_char (Lisp_Object, int);
+static unsigned xftfont_encode_char (struct font *, int);
+static int xftfont_text_extents (struct font *, unsigned *, int,
+                                 struct font_metrics *);
+static int xftfont_draw (struct glyph_string *, int, int, int, int, int);
+static int xftfont_end_for_frame (FRAME_PTR f);
 
 struct font_driver xftfont_driver;
 
 static Lisp_Object
-xftfont_list (frame, spec)
-     Lisp_Object frame;
-     Lisp_Object spec;
+xftfont_list (Lisp_Object frame, Lisp_Object spec)
 {
-  Lisp_Object val = ftfont_driver.list (frame, spec);
-  int i;
-  
-  if (! NILP (val))
-    for (i = 0; i < ASIZE (val); i++)
-      ASET (AREF (val, i), FONT_TYPE_INDEX, Qxft);
-  return val;
+  Lisp_Object list = ftfont_driver.list (frame, spec), tail;
+
+  for (tail = list; CONSP (tail); tail = XCDR (tail))
+    ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
+  return list;
 }
 
 static Lisp_Object
-xftfont_match (frame, spec)
-     Lisp_Object frame;
-     Lisp_Object spec;
+xftfont_match (Lisp_Object frame, Lisp_Object spec)
 {
   Lisp_Object entity = ftfont_driver.match (frame, spec);
 
-  if (VECTORP (entity))
+  if (! NILP (entity))
     ASET (entity, FONT_TYPE_INDEX, Qxft);
   return entity;
 }
 
-extern Lisp_Object ftfont_font_format P_ ((FcPattern *));
+extern Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object);
+extern FcCharSet *ftfont_get_fc_charset (Lisp_Object);
+extern Lisp_Object QCantialias;
 
 static FcChar8 ascii_printable[95];
 
-static struct font *
-xftfont_open (f, entity, pixel_size)
-     FRAME_PTR f;
-     Lisp_Object entity;
-     int pixel_size;
+static void
+xftfont_fix_match (FcPattern *pat, FcPattern *match)
+{
+  /*  These values are not used for matching (except antialias), but for
+      rendering, so make sure they are carried over to the match.
+      We also put antialias here because most fonts are antialiased, so
+      the match will have antialias true.  */
+
+  FcBool b = FcTrue;
+  int i;
+  double dpi;
+
+  FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b);
+  if (! b) 
+    {
+      FcPatternDel (match, FC_ANTIALIAS);
+      FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
+    }
+  FcPatternGetBool (pat, FC_HINTING, 0, &b);
+  if (! b) 
+    {
+      FcPatternDel (match, FC_HINTING);
+      FcPatternAddBool (match, FC_HINTING, FcFalse);
+    }
+  if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i))
+    {
+      FcPatternDel (match, FC_HINT_STYLE);
+      FcPatternAddInteger (match, FC_HINT_STYLE, i);
+    }
+#ifndef FC_LCD_FILTER
+  /* Older fontconfig versions don't have FC_LCD_FILTER. */
+#define FC_LCD_FILTER "lcdfilter"
+#endif
+  if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i))
+    {
+      FcPatternDel (match, FC_LCD_FILTER);
+      FcPatternAddInteger (match, FC_LCD_FILTER, i);
+    }
+  if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i))
+    {
+      FcPatternDel (match, FC_RGBA);
+      FcPatternAddInteger (match, FC_RGBA, i);
+    }
+  if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi))
+    {
+      FcPatternDel (match, FC_DPI);
+      FcPatternAddDouble (match, FC_DPI, dpi);
+    }
+}
+
+static void
+xftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity)
+{
+  Lisp_Object tail;
+  int ival;
+
+  for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
+    {
+      Lisp_Object key = XCAR (XCAR (tail));
+      Lisp_Object val = XCDR (XCAR (tail));
+
+      if (EQ (key, QCantialias))
+          FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QChinting))
+       FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QCautohint))
+       FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QChintstyle))
+       {
+         if (INTEGERP (val))
+           FcPatternAddInteger (pat, FC_HINT_STYLE, XINT (val));
+          else if (SYMBOLP (val)
+                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+           FcPatternAddInteger (pat, FC_HINT_STYLE, ival);
+       }
+      else if (EQ (key, QCrgba))
+       {
+         if (INTEGERP (val))
+           FcPatternAddInteger (pat, FC_RGBA, XINT (val));
+          else if (SYMBOLP (val)
+                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+           FcPatternAddInteger (pat, FC_RGBA, ival);
+       }
+      else if (EQ (key, QClcdfilter))
+       {
+         if (INTEGERP (val))
+           FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XINT (val));
+          else if (SYMBOLP (val)
+                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+           FcPatternAddInteger (pat, FC_LCD_FILTER, ival);
+       }
+#ifdef FC_EMBOLDEN
+      else if (EQ (key, QCembolden))
+       FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
+#endif
+    }
+}
+
+static Lisp_Object
+xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  FcResult result;
   Display *display = FRAME_X_DISPLAY (f);
-  Lisp_Object val;
-  FcPattern *pattern, *pat = NULL;
-  FcChar8 *file;
+  Lisp_Object val, filename, index, font_object;
+  FcPattern *pat = NULL, *match;
   struct xftfont_info *xftfont_info = NULL;
-  XFontStruct *xfont = NULL;
   struct font *font;
   double size = 0;
   XftFont *xftfont = NULL;
   int spacing;
-  char *name;
-  int len;
+  char name[256];
+  int len, i;
   XGlyphInfo extents;
-
-  val = AREF (entity, FONT_EXTRA_INDEX);
-  if (XTYPE (val) != Lisp_Misc
-      || XMISCTYPE (val) != Lisp_Misc_Save_Value)
-    return NULL;
-  pattern = XSAVE_VALUE (val)->pointer;
-  if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
-    return NULL;
-
+  FT_Face ft_face;
+  FcMatrix *matrix;
+
+  val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+  if (! CONSP (val))
+    return Qnil;
+  val = XCDR (val);
+  filename = XCAR (val);
+  index = XCDR (val);
   size = XINT (AREF (entity, FONT_SIZE_INDEX));
   if (size == 0)
     size = pixel_size;
-
   pat = FcPatternCreate ();
-  FcPatternAddString (pat, FC_FILE, file);
+  FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
+  i = FONT_SLANT_NUMERIC (entity) - 100;
+  if (i < 0) i = 0;
+  FcPatternAddInteger (pat, FC_SLANT, i);
+  FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
   FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
-  /*FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);*/
   val = AREF (entity, FONT_FAMILY_INDEX);
   if (! NILP (val))
     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
-  FcConfigSubstitute (NULL, pat, FcMatchPattern);
+  val = AREF (entity, FONT_FOUNDRY_INDEX);
+  if (! NILP (val))
+    FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
+  val = AREF (entity, FONT_SPACING_INDEX);
+  if (! NILP (val))
+    FcPatternAddInteger (pat, FC_SPACING, XINT (val));
+  val = AREF (entity, FONT_DPI_INDEX);
+  if (! NILP (val))
+    {
+      double dbl = XINT (val);
+
+      FcPatternAddDouble (pat, FC_DPI, dbl);
+    }
+  val = AREF (entity, FONT_AVGWIDTH_INDEX);
+  if (INTEGERP (val) && XINT (val) == 0)
+    FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
+  /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
+     over 10x20-ISO8859-1.pcf.gz).  */
+  FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
+
+  xftfont_add_rendering_parameters (pat, entity);
+
+  FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
+  FcPatternAddInteger (pat, FC_INDEX, XINT (index));
+
 
   BLOCK_INPUT;
+  /* Make sure that the Xrender extension is added before the Xft one.
+     Otherwise, the close-display hook set by Xft is called after the
+     one for Xrender, and the former tries to re-add the latter.  This
+     results in inconsistency of internal states and leads to X
+     protocol error when one reconnects to the same X server.
+     (Bug#1696)  */
+  {
+    int event_base, error_base;
+    XRenderQueryExtension (display, &event_base, &error_base);
+  }
+
+  /* Substitute in values from X resources and XftDefaultSet.  */
   XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
-  xftfont = XftFontOpenPattern (display, pat);
+  match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
+  xftfont_fix_match (pat, match);
+
+  FcPatternDestroy (pat);
+  xftfont = XftFontOpenPattern (display, match);
+  if (!xftfont)
+    {
+      UNBLOCK_INPUT;
+      XftPatternDestroy (match);
+      return Qnil;
+    }
+  ft_face = XftLockFace (xftfont);
+  UNBLOCK_INPUT;
+
   /* We should not destroy PAT here because it is kept in XFTFONT and
      destroyed automatically when XFTFONT is closed.  */
-  if (! xftfont)
-    goto err;
-
-  xftfont_info = malloc (sizeof (struct xftfont_info));
-  if (! xftfont_info)
-    goto err;
-  xfont = malloc (sizeof (XFontStruct));
-  if (! xfont)
-    goto err;
+  font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
+  ASET (font_object, FONT_TYPE_INDEX, Qxft);
+  len = font_unparse_xlfd (entity, size, name, 256);
+  if (len > 0)
+    ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
+  len = font_unparse_fcname (entity, size, name, 256);
+  if (len > 0)
+    ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
+  else
+    ASET (font_object, FONT_FULLNAME_INDEX,
+         AREF (font_object, FONT_NAME_INDEX));
+  ASET (font_object, FONT_FILE_INDEX, filename);
+  ASET (font_object, FONT_FORMAT_INDEX,
+       ftfont_font_format (xftfont->pattern, filename));
+  font = XFONT_OBJECT (font_object);
+  font->pixel_size = pixel_size;
+  font->driver = &xftfont_driver;
+  font->encoding_charset = font->repertory_charset = -1;
+
+  xftfont_info = (struct xftfont_info *) font;
   xftfont_info->display = display;
   xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
   xftfont_info->xftfont = xftfont;
-  xftfont_info->ft_face = XftLockFace (xftfont);
-
-  font = (struct font *) xftfont_info;
-  font->format = ftfont_font_format (xftfont->pattern);
-  font->entity = entity;
-  font->pixel_size = size;
-  font->driver = &xftfont_driver;
-  len = 96;
-  name = malloc (len);
-  while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
+  /* This means that there's no need of transformation.  */
+  xftfont_info->matrix.xx = 0;
+  if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix)
+      == FcResultMatch)
     {
-      char *new = realloc (name, len += 32);
-
-      if (! new)
-       free (name);
-      name = new;
+      xftfont_info->matrix.xx = 0x10000L * matrix->xx;
+      xftfont_info->matrix.yy = 0x10000L * matrix->yy;
+      xftfont_info->matrix.xy = 0x10000L * matrix->xy;
+      xftfont_info->matrix.yx = 0x10000L * matrix->yx;
     }
-  if (! name)
-    goto err;
-  font->font.full_name = font->font.name = name;
-  font->file_name = (char *) file;
-  font->font.size = xftfont->max_advance_width;
-  font->font.charset = font->encoding_charset = font->repertory_charset = -1;
-
-  if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing)
-      != FcResultMatch)
+  font->pixel_size = size;
+  font->driver = &xftfont_driver;
+  if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
+    spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
+  else
     spacing = FC_PROPORTIONAL;
   if (! ascii_printable[0])
     {
@@ -296,102 +413,104 @@ xftfont_open (f, entity, pixel_size)
       for (i = 0; i < 95; i++)
        ascii_printable[i] = ' ' + i;
     }
-  if (spacing != FC_PROPORTIONAL)
+  BLOCK_INPUT;
+  if (spacing != FC_PROPORTIONAL && spacing != FC_DUAL)
     {
-      font->font.average_width = font->font.space_width
+      font->min_width = font->average_width = font->space_width
        = xftfont->max_advance_width;
       XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
     }
   else
     {
       XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
-      font->font.space_width = extents.xOff;
-      if (font->font.space_width <= 0)
+      font->space_width = extents.xOff;
+      if (font->space_width <= 0)
        /* dirty workaround */
-       font->font.space_width = pixel_size;    
+       font->space_width = pixel_size;
       XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
-      font->font.average_width = (font->font.space_width + extents.xOff) / 95;
+      font->average_width = (font->space_width + extents.xOff) / 95;
     }
   UNBLOCK_INPUT;
 
   font->ascent = xftfont->ascent;
-  if (font->ascent < extents.y)
-    font->ascent = extents.y;
   font->descent = xftfont->descent;
-  if (font->descent < extents.height - extents.y)
-    font->descent = extents.height - extents.y;
-  font->font.height = font->ascent + font->descent;
+  if (pixel_size >= 5)
+    {
+      /* The above condition is a dirty workaround because
+        XftTextExtents8 behaves strangely for some fonts
+        (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */
+      if (font->ascent < extents.y)
+       font->ascent = extents.y;
+      if (font->descent < extents.height - extents.y)
+       font->descent = extents.height - extents.y;
+    }
+  font->height = font->ascent + font->descent;
 
-  /* Unfortunately Xft doesn't provide a way to get minimum char
-     width.  So, we use space_width instead.  */
-  font->min_width = font->font.space_width;
-
-  font->font.baseline_offset = 0;
-  font->font.relative_compose = 0;
-  font->font.default_ascent = 0;
-  font->font.vertical_centering = 0;
-
-  /* Setup pseudo XFontStruct */
-  xfont->fid = xftfont_default_fid (f);
-  xfont->ascent = font->ascent;
-  xfont->descent = font->descent;
-  xfont->max_bounds.descent = font->descent;
-  xfont->max_bounds.width = xftfont->max_advance_width;
-  xfont->min_bounds.width = font->font.space_width;
-  font->font.font = xfont;
-
-  dpyinfo->n_fonts++;
-
-  /* Set global flag fonts_changed_p to non-zero if the font loaded
-     has a character with a smaller width than any other character
-     before, or if the font loaded has a smaller height than any other
-     font loaded before.  If this happens, it will make a glyph matrix
-     reallocation necessary.  */
-  if (dpyinfo->n_fonts == 1)
+  if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
     {
-      dpyinfo->smallest_font_height = font->font.height;
-      dpyinfo->smallest_char_width = font->min_width;
-      fonts_changed_p = 1;
+      int upEM = ft_face->units_per_EM;
+
+      font->underline_position = -ft_face->underline_position * size / upEM;
+      font->underline_thickness = ft_face->underline_thickness * size / upEM;
+      if (font->underline_thickness > 2)
+       font->underline_position -= font->underline_thickness / 2;
     }
   else
     {
-      if (dpyinfo->smallest_font_height > font->font.height)
-       dpyinfo->smallest_font_height = font->font.height,
-         fonts_changed_p |= 1;
-      if (dpyinfo->smallest_char_width > font->min_width)
-       dpyinfo->smallest_char_width = font->min_width,
-         fonts_changed_p |= 1;
+      font->underline_position = -1;
+      font->underline_thickness = 0;
     }
+#ifdef HAVE_LIBOTF
+  xftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
+  xftfont_info->otf = NULL;
+#endif /* HAVE_LIBOTF */
+  xftfont_info->ft_size = ft_face->size;
 
-  return font;
+  /* Unfortunately Xft doesn't provide a way to get minimum char
+     width.  So, we use space_width instead.  */
+  font->min_width = font->space_width;
+
+  font->baseline_offset = 0;
+  font->relative_compose = 0;
+  font->default_ascent = 0;
+  font->vertical_centering = 0;
+#ifdef FT_BDF_H
+  if (! (ft_face->face_flags & FT_FACE_FLAG_SFNT))
+    {
+      BDF_PropertyRec rec;
+
+      if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &rec) == 0
+         && rec.type == BDF_PROPERTY_TYPE_INTEGER)
+       font->baseline_offset = rec.u.integer;
+      if (FT_Get_BDF_Property (ft_face, "_MULE_RELATIVE_COMPOSE", &rec) == 0
+         && rec.type == BDF_PROPERTY_TYPE_INTEGER)
+       font->relative_compose = rec.u.integer;
+      if (FT_Get_BDF_Property (ft_face, "_MULE_DEFAULT_ASCENT", &rec) == 0
+         && rec.type == BDF_PROPERTY_TYPE_INTEGER)
+       font->default_ascent = rec.u.integer;
+    }
+#endif
 
- err:
-  if (xftfont) XftFontClose (display, xftfont);
-  UNBLOCK_INPUT;
-  if (xftfont_info) free (xftfont_info);
-  if (xfont) free (xfont);
-  return NULL;
+  return font_object;
 }
 
 static void
-xftfont_close (f, font)
-     FRAME_PTR f;
-     struct font *font;
+xftfont_close (FRAME_PTR f, struct font *font)
 {
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
 
+#ifdef HAVE_LIBOTF
+  if (xftfont_info->otf)
+    OTF_close (xftfont_info->otf);
+#endif
+  BLOCK_INPUT;
   XftUnlockFace (xftfont_info->xftfont);
   XftFontClose (xftfont_info->display, xftfont_info->xftfont);
-  if (font->font.name)
-    free (font->font.name);
-  free (font);
-  FRAME_X_DISPLAY_INFO (f)->n_fonts--;
+  UNBLOCK_INPUT;
 }
 
 static int
-xftfont_prepare_face (f, face)
-     FRAME_PTR f;
-     struct face *face;
+xftfont_prepare_face (FRAME_PTR f, struct face *face)
 {
   struct xftface_info *xftface_info;
 
@@ -407,27 +526,17 @@ xftfont_prepare_face (f, face)
   xftface_info = malloc (sizeof (struct xftface_info));
   if (! xftface_info)
     return -1;
-
-  BLOCK_INPUT;
-  xftface_info->xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
-                                         FRAME_X_WINDOW (f),
-                                         FRAME_X_VISUAL (f),
-                                         FRAME_X_COLORMAP (f));
   xftfont_get_colors (f, face, face->gc, NULL,
                      &xftface_info->xft_fg, &xftface_info->xft_bg);
-  UNBLOCK_INPUT;
-
   face->extra = xftface_info;
   return 0;
 }
 
 static void
-xftfont_done_face (f, face)
-     FRAME_PTR f;
-     struct face *face;
+xftfont_done_face (FRAME_PTR f, struct face *face)
 {
   struct xftface_info *xftface_info;
-  
+
 #if 0
   /* This doesn't work if face->ascii_face doesn't use an Xft font. */
   if (face != face->ascii_face
@@ -438,32 +547,47 @@ xftfont_done_face (f, face)
   xftface_info = (struct xftface_info *) face->extra;
   if (xftface_info)
     {
-      BLOCK_INPUT;
-      XftDrawDestroy (xftface_info->xft_draw);
-      UNBLOCK_INPUT;
       free (xftface_info);
+      face->extra = NULL;
     }
-  face->extra = NULL;
+}
+
+extern Lisp_Object Qja, Qko;
+
+static int
+xftfont_has_char (Lisp_Object font, int c)
+{
+  struct xftfont_info *xftfont_info;
+  struct charset *cs = NULL;
+
+  if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
+      && charset_jisx0208 >= 0)
+    cs = CHARSET_FROM_ID (charset_jisx0208);
+  else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
+      && charset_ksc5601 >= 0)
+    cs = CHARSET_FROM_ID (charset_ksc5601);
+  if (cs)
+    return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
+
+  if (FONT_ENTITY_P (font))
+    return ftfont_driver.has_char (font, c);
+  xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font);
+  return (XftCharExists (xftfont_info->display, xftfont_info->xftfont,
+                        (FcChar32) c) == FcTrue);
 }
 
 static unsigned
-xftfont_encode_char (font, c)
-     struct font *font;
-     int c;
+xftfont_encode_char (struct font *font, int c)
 {
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
   unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
                                (FcChar32) c);
-  
-  return (code ? code : 0xFFFFFFFF);
+
+  return (code ? code : FONT_INVALID_CODE);
 }
 
 static int
-xftfont_text_extents (font, code, nglyphs, metrics)
-     struct font *font;
-     unsigned *code;
-     int nglyphs;
-     struct font_metrics *metrics;
+xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
 {
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
   XGlyphInfo extents;
@@ -483,87 +607,142 @@ xftfont_text_extents (font, code, nglyphs, metrics)
   return extents.xOff;
 }
 
+static XftDraw *
+xftfont_get_xft_draw (FRAME_PTR f)
+{
+  XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
+
+  if (! xft_draw)
+    {
+      BLOCK_INPUT;
+      xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
+                              FRAME_X_WINDOW (f),
+                              FRAME_X_VISUAL (f),
+                              FRAME_X_COLORMAP (f));
+      UNBLOCK_INPUT;
+      if (! xft_draw)
+       abort ();
+      font_put_frame_data (f, &xftfont_driver, xft_draw);
+    }
+  return xft_draw;
+}
+
 static int
-xftfont_draw (s, from, to, x, y, with_background)
-     struct glyph_string *s;
-     int from, to, x, y, with_background;
+xftfont_draw (struct glyph_string *s, int from, int to, int x, int y, int with_background)
 {
   FRAME_PTR f = s->f;
   struct face *face = s->face;
-  struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font_info;
+  struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font;
   struct xftface_info *xftface_info = NULL;
-  XftDraw *xft_draw = NULL;
+  XftDraw *xft_draw = xftfont_get_xft_draw (f);
   FT_UInt *code;
   XftColor fg, bg;
-  XRectangle r;
   int len = to - from;
   int i;
 
-  if (s->font_info == face->font_info)
-    {
-      xftface_info = (struct xftface_info *) face->extra;
-      xft_draw = xftface_info->xft_draw;
-    }
+  if (s->font == face->font)
+    xftface_info = (struct xftface_info *) face->extra;
   xftfont_get_colors (f, face, s->gc, xftface_info,
                      &fg, with_background ? &bg : NULL);
   BLOCK_INPUT;
-  if (! xft_draw)
-    xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
-                             FRAME_X_WINDOW (f),
-                             FRAME_X_VISUAL (f),
-                             FRAME_X_COLORMAP (f));
   if (s->num_clips > 0)
     XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips);
   else
     XftDrawSetClip (xft_draw, NULL);
 
   if (with_background)
-    {
-      struct font *font = (struct font *) face->font_info;
-
-      XftDrawRect (xft_draw, &bg,
-                  x, y - face->font->ascent, s->width, font->font.height);
-    }
+    XftDrawRect (xft_draw, &bg,
+                x, y - face->font->ascent, s->width, face->font->height);
   code = alloca (sizeof (FT_UInt) * len);
   for (i = 0; i < len; i++)
     code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
               | XCHAR2B_BYTE2 (s->char2b + from + i));
 
-  XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
-                x, y, code, len);
-  if (s->font_info != face->font_info)
-    XftDrawDestroy (xft_draw);
+  if (s->padding_p)
+    for (i = 0; i < len; i++)
+      XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
+                    x + i, y, code + i, 1);
+  else
+    XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
+                  x, y, code, len);
   UNBLOCK_INPUT;
 
   return len;
 }
 
 static int
-xftfont_anchor_point (font, code, index, x, y)
-     struct font *font;
-     unsigned code;
-     int index;
-     int *x, *y;
+xftfont_end_for_frame (FRAME_PTR f)
 {
-  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
-  FT_Face ft_face = xftfont_info->ft_face;
+  XftDraw *xft_draw;
 
-  if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
-    return -1;
-  if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
-    return -1;
-  if (index >= ft_face->glyph->outline.n_points)
-    return -1;
-  *x = ft_face->glyph->outline.points[index].x;
-  *y = ft_face->glyph->outline.points[index].y;
+  /* Don't do anything if display is dead */
+  if (FRAME_X_DISPLAY (f) == NULL) return 0;
+
+  xft_draw = font_get_frame_data (f, &xftfont_driver);
+
+  if (xft_draw)
+    {
+      BLOCK_INPUT;
+      XftDrawDestroy (xft_draw);
+      UNBLOCK_INPUT;
+      font_put_frame_data (f, &xftfont_driver, NULL);
+    }
   return 0;
 }
 
+static int
+xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object, Lisp_Object entity)
+{
+  struct xftfont_info *info = (struct xftfont_info *) XFONT_OBJECT (font_object);
+  FcPattern *oldpat = info->xftfont->pattern;
+  Display *display = FRAME_X_DISPLAY (f);
+  FcPattern *pat = FcPatternCreate ();
+  FcBool b1, b2;
+  int ok = 0, i1, i2, r1, r2;
+
+  xftfont_add_rendering_parameters (pat, entity);
+  XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
+
+  r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1);
+  r2 = FcPatternGetBool (oldpat, FC_ANTIALIAS, 0, &b2);
+  if (r1 != r2 || b1 != b2) goto out;
+  r1 = FcPatternGetBool (pat, FC_HINTING, 0, &b1);
+  r2 = FcPatternGetBool (oldpat, FC_HINTING, 0, &b2);
+  if (r1 != r2 || b1 != b2) goto out;
+  r1 = FcPatternGetBool (pat, FC_AUTOHINT, 0, &b1);
+  r2 = FcPatternGetBool (oldpat, FC_AUTOHINT, 0, &b2);
+  if (r1 != r2 || b1 != b2) goto out;
+#ifdef FC_EMBOLDEN
+  r1 = FcPatternGetBool (pat, FC_EMBOLDEN, 0, &b1);
+  r2 = FcPatternGetBool (oldpat, FC_EMBOLDEN, 0, &b2);
+  if (r1 != r2 || b1 != b2) goto out;
+#endif
+  r1 = FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i1);
+  r2 = FcPatternGetInteger (oldpat, FC_HINT_STYLE, 0, &i2);
+  if (r1 != r2 || i1 != i2) goto out;
+  r1 = FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i1);
+  r2 = FcPatternGetInteger (oldpat, FC_LCD_FILTER, 0, &i2);
+  if (r1 != r2 || i1 != i2) goto out;
+  r1 = FcPatternGetInteger (pat, FC_RGBA, 0, &i1);
+  r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2);
+  if (r1 != r2 || i1 != i2) goto out;
+
+  ok = 1;
+ out:
+  FcPatternDestroy (pat);
+  return ok;
+}
 
 void
-syms_of_xftfont ()
+syms_of_xftfont (void)
 {
   DEFSYM (Qxft, "xft");
+  DEFSYM (QChinting, ":hinting");
+  DEFSYM (QCautohint, ":autohint");
+  DEFSYM (QChintstyle, ":hintstyle");
+  DEFSYM (QCrgba, ":rgba");
+  DEFSYM (QCembolden, ":embolden");
+  DEFSYM (QClcdfilter, ":lcdfilter");
 
   xftfont_driver = ftfont_driver;
   xftfont_driver.type = Qxft;
@@ -574,10 +753,12 @@ syms_of_xftfont ()
   xftfont_driver.close = xftfont_close;
   xftfont_driver.prepare_face = xftfont_prepare_face;
   xftfont_driver.done_face = xftfont_done_face;
+  xftfont_driver.has_char = xftfont_has_char;
   xftfont_driver.encode_char = xftfont_encode_char;
   xftfont_driver.text_extents = xftfont_text_extents;
   xftfont_driver.draw = xftfont_draw;
-  xftfont_driver.anchor_point = xftfont_anchor_point;
+  xftfont_driver.end_for_frame = xftfont_end_for_frame;
+  xftfont_driver.cached_font_ok = xftfont_cached_font_ok;
 
   register_font_driver (&xftfont_driver, NULL);
 }