]> code.delx.au - gnu-emacs/blobdiff - src/xftfont.c
Fix so top -10 and left -10 in frame parameters work.
[gnu-emacs] / src / xftfont.c
index 7d5bf245cb6d3ade28737722235ee3dd82d29aac..5d4581be4e94b37ae6f74762186fcc92a724a611 100644 (file)
@@ -1,6 +1,6 @@
 /* xftfont.c -- XFT font driver.
 /* xftfont.c -- XFT font driver.
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
-   Copyright (C) 2006, 2007, 2008
+   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
 
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H13PRO009
 
@@ -21,6 +21,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include <stdio.h>
 
 #include <config.h>
 #include <stdio.h>
+#include <setjmp.h>
 #include <X11/Xlib.h>
 #include <X11/Xft/Xft.h>
 
 #include <X11/Xlib.h>
 #include <X11/Xft/Xft.h>
 
@@ -38,7 +39,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 /* Xft font driver.  */
 
 static Lisp_Object Qxft;
 /* Xft font driver.  */
 
 static Lisp_Object Qxft;
-static Lisp_Object QChinting , QCautohint, QChintstyle, QCrgba, QCembolden;
+static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden,
+  QClcdfilter;
 
 /* The actual structure for Xft font that can be casted to struct
    font.  */
 
 /* The actual structure for Xft font that can be casted to struct
    font.  */
@@ -46,13 +48,18 @@ static Lisp_Object QChinting , QCautohint, QChintstyle, QCrgba, QCembolden;
 struct xftfont_info
 {
   struct font font;
 struct xftfont_info
 {
   struct font font;
-  Display *display;
-  int screen;
-  XftFont *xftfont;
+  /* 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 */
 #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;
 };
 
 /* Structure pointed by (struct face *)->extra  */
 };
 
 /* Structure pointed by (struct face *)->extra  */
@@ -140,13 +147,11 @@ static Lisp_Object 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 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 int xftfont_has_char P_ ((Lisp_Object, int));
 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 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 int xftfont_end_for_frame P_ ((FRAME_PTR f));
 
 struct font_driver xftfont_driver;
 static int xftfont_end_for_frame P_ ((FRAME_PTR f));
 
 struct font_driver xftfont_driver;
@@ -157,7 +162,7 @@ xftfont_list (frame, spec)
      Lisp_Object spec;
 {
   Lisp_Object list = ftfont_driver.list (frame, spec), tail;
      Lisp_Object spec;
 {
   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;
   for (tail = list; CONSP (tail); tail = XCDR (tail))
     ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
   return list;
@@ -175,11 +180,113 @@ xftfont_match (frame, spec)
   return entity;
 }
 
   return entity;
 }
 
-extern Lisp_Object ftfont_font_format P_ ((FcPattern *));
+extern Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object));
+extern FcCharSet *ftfont_get_fc_charset P_ ((Lisp_Object));
 extern Lisp_Object QCantialias;
 
 static FcChar8 ascii_printable[95];
 
 extern Lisp_Object QCantialias;
 
 static FcChar8 ascii_printable[95];
 
+static void
+xftfont_fix_match (pat, match)
+     FcPattern *pat, *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 (pat, entity)
+     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 (f, entity, pixel_size)
      FRAME_PTR f;
 static Lisp_Object
 xftfont_open (f, entity, pixel_size)
      FRAME_PTR f;
@@ -188,7 +295,7 @@ xftfont_open (f, entity, pixel_size)
 {
   FcResult result;
   Display *display = FRAME_X_DISPLAY (f);
 {
   FcResult result;
   Display *display = FRAME_X_DISPLAY (f);
-  Lisp_Object val, filename, tail, font_object;
+  Lisp_Object val, filename, index, font_object;
   FcPattern *pat = NULL, *match;
   struct xftfont_info *xftfont_info = NULL;
   struct font *font;
   FcPattern *pat = NULL, *match;
   struct xftfont_info *xftfont_info = NULL;
   struct font *font;
@@ -199,17 +306,18 @@ xftfont_open (f, entity, pixel_size)
   int len, i;
   XGlyphInfo extents;
   FT_Face ft_face;
   int len, i;
   XGlyphInfo extents;
   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);
 
   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 ();
   size = XINT (AREF (entity, FONT_SIZE_INDEX));
   if (size == 0)
     size = pixel_size;
   pat = FcPatternCreate ();
-  FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
   FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
   i = FONT_SLANT_NUMERIC (entity) - 100;
   if (i < 0) i = 0;
   FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
   i = FONT_SLANT_NUMERIC (entity) - 100;
   if (i < 0) i = 0;
@@ -219,60 +327,76 @@ xftfont_open (f, entity, pixel_size)
   val = AREF (entity, FONT_FAMILY_INDEX);
   if (! NILP (val))
     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
   val = AREF (entity, FONT_FAMILY_INDEX);
   if (! NILP (val))
     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
-  for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
+  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))
     {
     {
-      Lisp_Object key, val;
+      double dbl = XINT (val);
 
 
-      key = XCAR (XCAR (tail)), 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_RGBA, XINT (val));
-       }
-      else if (EQ (key, QCrgba))
-       {
-         if (INTEGERP (val))
-           FcPatternAddInteger (pat, FC_RGBA, XINT (val));
-       }
-      else if (EQ (key, QCembolden))
-       FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
+      FcPatternAddDouble (pat, FC_DPI, dbl);
     }
     }
-  FcConfigSubstitute (NULL, pat, FcMatchPattern);
+  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;
 
   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);
   match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
   XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
   match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
+  xftfont_fix_match (pat, match);
+
   FcPatternDestroy (pat);
   xftfont = XftFontOpenPattern (display, match);
   FcPatternDestroy (pat);
   xftfont = XftFontOpenPattern (display, match);
+  if (!xftfont)
+    {
+      UNBLOCK_INPUT;
+      XftPatternDestroy (match);
+      return Qnil;
+    }
+  ft_face = XftLockFace (xftfont);
   UNBLOCK_INPUT;
 
   UNBLOCK_INPUT;
 
-  if (! xftfont)
-    return Qnil;
   /* We should not destroy PAT here because it is kept in XFTFONT and
      destroyed automatically when XFTFONT is closed.  */
   /* We should not destroy PAT here because it is kept in XFTFONT and
      destroyed automatically when XFTFONT is closed.  */
-  font_object = font_make_object (VECSIZE (struct xftfont_info));
+  font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
   ASET (font_object, FONT_TYPE_INDEX, Qxft);
   ASET (font_object, FONT_TYPE_INDEX, Qxft);
-  for (i = 1; i < FONT_ENTITY_MAX; i++)
-    ASET (font_object, i, AREF (entity, i));
-  ASET (font_object, FONT_SIZE_INDEX, make_number (size));
   len = font_unparse_xlfd (entity, size, name, 256);
   if (len > 0)
   len = font_unparse_xlfd (entity, size, name, 256);
   if (len > 0)
-    ASET (font_object, FONT_NAME_INDEX, make_unibyte_string (name, len));
+    ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
   len = font_unparse_fcname (entity, size, name, 256);
   if (len > 0)
   len = font_unparse_fcname (entity, size, name, 256);
   if (len > 0)
-    ASET (font_object, FONT_FULLNAME_INDEX, make_unibyte_string (name, len));
+    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,
   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));
+       ftfont_font_format (xftfont->pattern, filename));
   font = XFONT_OBJECT (font_object);
   font->pixel_size = pixel_size;
   font->driver = &xftfont_driver;
   font = XFONT_OBJECT (font_object);
   font->pixel_size = pixel_size;
   font->driver = &xftfont_driver;
@@ -282,6 +406,16 @@ xftfont_open (f, entity, pixel_size)
   xftfont_info->display = display;
   xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
   xftfont_info->xftfont = xftfont;
   xftfont_info->display = display;
   xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
   xftfont_info->xftfont = xftfont;
+  /* This means that there's no need of transformation.  */
+  xftfont_info->matrix.xx = 0;
+  if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix)
+      == FcResultMatch)
+    {
+      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;
+    }
   font->pixel_size = size;
   font->driver = &xftfont_driver;
   if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
   font->pixel_size = size;
   font->driver = &xftfont_driver;
   if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
@@ -307,7 +441,7 @@ xftfont_open (f, entity, pixel_size)
       font->space_width = extents.xOff;
       if (font->space_width <= 0)
        /* dirty workaround */
       font->space_width = extents.xOff;
       if (font->space_width <= 0)
        /* dirty workaround */
-       font->space_width = pixel_size; 
+       font->space_width = pixel_size;
       XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
       font->average_width = (font->space_width + extents.xOff) / 95;
     }
       XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
       font->average_width = (font->space_width + extents.xOff) / 95;
     }
@@ -327,13 +461,12 @@ xftfont_open (f, entity, pixel_size)
     }
   font->height = font->ascent + font->descent;
 
     }
   font->height = font->ascent + font->descent;
 
-  ft_face = XftLockFace (xftfont);
   if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
     {
       int upEM = ft_face->units_per_EM;
 
       font->underline_position = -ft_face->underline_position * size / upEM;
   if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
     {
       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;
+      font->underline_thickness = ft_face->underline_thickness * size / upEM;
       if (font->underline_thickness > 2)
        font->underline_position -= font->underline_thickness / 2;
     }
       if (font->underline_thickness > 2)
        font->underline_position -= font->underline_thickness / 2;
     }
@@ -346,7 +479,7 @@ xftfont_open (f, entity, pixel_size)
   xftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
   xftfont_info->otf = NULL;
 #endif /* HAVE_LIBOTF */
   xftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
   xftfont_info->otf = NULL;
 #endif /* HAVE_LIBOTF */
-  XftUnlockFace (xftfont);
+  xftfont_info->ft_size = ft_face->size;
 
   /* Unfortunately Xft doesn't provide a way to get minimum char
      width.  So, we use space_width instead.  */
 
   /* Unfortunately Xft doesn't provide a way to get minimum char
      width.  So, we use space_width instead.  */
@@ -356,6 +489,22 @@ xftfont_open (f, entity, pixel_size)
   font->relative_compose = 0;
   font->default_ascent = 0;
   font->vertical_centering = 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
 
   return font_object;
 }
 
   return font_object;
 }
@@ -372,6 +521,7 @@ xftfont_close (f, font)
     OTF_close (xftfont_info->otf);
 #endif
   BLOCK_INPUT;
     OTF_close (xftfont_info->otf);
 #endif
   BLOCK_INPUT;
+  XftUnlockFace (xftfont_info->xftfont);
   XftFontClose (xftfont_info->display, xftfont_info->xftfont);
   UNBLOCK_INPUT;
 }
   XftFontClose (xftfont_info->display, xftfont_info->xftfont);
   UNBLOCK_INPUT;
 }
@@ -407,7 +557,7 @@ xftfont_done_face (f, face)
      struct face *face;
 {
   struct xftface_info *xftface_info;
      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
 #if 0
   /* This doesn't work if face->ascii_face doesn't use an Xft font. */
   if (face != face->ascii_face
@@ -423,6 +573,32 @@ xftfont_done_face (f, face)
     }
 }
 
     }
 }
 
+extern Lisp_Object Qja, Qko;
+
+static int
+xftfont_has_char (font, c)
+     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;
 static unsigned
 xftfont_encode_char (font, c)
      struct font *font;
@@ -431,7 +607,7 @@ xftfont_encode_char (font, c)
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
   unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
                                (FcChar32) c);
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
   unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
                                (FcChar32) c);
-  
+
   return (code ? code : FONT_INVALID_CODE);
 }
 
   return (code ? code : FONT_INVALID_CODE);
 }
 
@@ -464,7 +640,7 @@ static XftDraw *
 xftfont_get_xft_draw (f)
      FRAME_PTR f;
 {
 xftfont_get_xft_draw (f)
      FRAME_PTR f;
 {
-  XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);;
+  XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
 
   if (! xft_draw)
     {
 
   if (! xft_draw)
     {
@@ -526,37 +702,16 @@ xftfont_draw (s, from, to, x, y, with_background)
   return len;
 }
 
   return len;
 }
 
-static int
-xftfont_anchor_point (font, code, index, x, y)
-     struct font *font;
-     unsigned code;
-     int index;
-     int *x, *y;
-{
-  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
-  FT_Face ft_face = XftLockFace (xftfont_info->xftfont);
-  int result;
-
-  if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
-    result = -1;
-  else if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
-    result = -1;
-  else if (index >= ft_face->glyph->outline.n_points)
-    result = -1;
-  else
-    {
-      *x = ft_face->glyph->outline.points[index].x;
-      *y = ft_face->glyph->outline.points[index].y;
-    }
-  XftUnlockFace (xftfont_info->xftfont);
-  return result;
-}
-
 static int
 xftfont_end_for_frame (f)
      FRAME_PTR f;
 {
 static int
 xftfont_end_for_frame (f)
      FRAME_PTR f;
 {
-  XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
+  XftDraw *xft_draw;
+
+  /* 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)
     {
 
   if (xft_draw)
     {
@@ -568,53 +723,63 @@ xftfont_end_for_frame (f)
   return 0;
 }
 
   return 0;
 }
 
-#ifdef HAVE_LIBOTF
-#ifdef HAVE_M17N_FLT
-static Lisp_Object
-xftfont_shape (lgstring)
-     Lisp_Object lgstring;
-{
-  struct font *font;
-  struct xftfont_info *xftfont_info;
-  Lisp_Object result;
-  FT_Face ft_face;
+static int
+xftfont_cached_font_ok (f, font_object, entity)
+     struct frame *f;
+     Lisp_Object font_object;
+     Lisp_Object entity;
 
 
-  CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
-  xftfont_info = (struct xftfont_info *) font;
-  if (! xftfont_info->maybe_otf)
-    return Qnil;
-  ft_face = XftLockFace (xftfont_info->xftfont);
-  if (! xftfont_info->otf)
-    {
-      OTF *otf = OTF_open_ft_face (ft_face);
+{
+  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;
 
 
-      if (! otf || OTF_get_table (otf, "head") < 0)
-       {
-         if (otf)
-           OTF_close (otf);
-         xftfont_info->maybe_otf = 0;
-         XftUnlockFace (xftfont_info->xftfont);
-         return Qnil;
-       }
-      xftfont_info->otf = otf;
-    }
+  xftfont_add_rendering_parameters (pat, entity);
+  XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
 
 
-  result = ftfont_shape_by_flt (lgstring, font, ft_face, xftfont_info->otf);
-  XftUnlockFace (xftfont_info->xftfont);
-  return result;
+  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;
 }
 }
-#endif /* HAVE_M17N_FLT */
-#endif /* HAVE_LIBOTF */
 
 void
 syms_of_xftfont ()
 {
   DEFSYM (Qxft, "xft");
   DEFSYM (QChinting, ":hinting");
 
 void
 syms_of_xftfont ()
 {
   DEFSYM (Qxft, "xft");
   DEFSYM (QChinting, ":hinting");
-  DEFSYM (QCautohint, ":autohing");
+  DEFSYM (QCautohint, ":autohint");
   DEFSYM (QChintstyle, ":hintstyle");
   DEFSYM (QCrgba, ":rgba");
   DEFSYM (QCembolden, ":embolden");
   DEFSYM (QChintstyle, ":hintstyle");
   DEFSYM (QCrgba, ":rgba");
   DEFSYM (QCembolden, ":embolden");
+  DEFSYM (QClcdfilter, ":lcdfilter");
 
   xftfont_driver = ftfont_driver;
   xftfont_driver.type = Qxft;
 
   xftfont_driver = ftfont_driver;
   xftfont_driver.type = Qxft;
@@ -625,16 +790,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.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.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.end_for_frame = xftfont_end_for_frame;
-#ifdef HAVE_LIBOTF
-#ifdef HAVE_M17N_FLT
-  xftfont_driver.shape = xftfont_shape;
-#endif /* HAVE_M17N_FLT */
-#endif /* HAVE_LIBOTF */
+  xftfont_driver.cached_font_ok = xftfont_cached_font_ok;
 
   register_font_driver (&xftfont_driver, NULL);
 }
 
   register_font_driver (&xftfont_driver, NULL);
 }