*** empty log message ***
[m17n/m17n-lib.git] / src / font-ft.c
index 1ce8825..dd62e6e 100644 (file)
@@ -1,5 +1,5 @@
 /* font-ft.c -- FreeType interface sub-module.
-   Copyright (C) 2003, 2004
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -17,7 +17,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 #include "config.h"
@@ -37,6 +37,7 @@
 #include "plist.h"
 #include "symbol.h"
 #include "language.h"
+#include "internal-flt.h"
 #include "internal-gui.h"
 #include "font.h"
 #include "face.h"
 #ifdef HAVE_FREETYPE
 
 #ifdef HAVE_FTBDF_H
-#include <freetype/ftbdf.h>
+#include FT_BDF_H
 #endif
 
-static int mdebug_mask = MDEBUG_FONT;
+static int mdebug_flag = MDEBUG_FONT;
 
 #ifdef HAVE_FONTCONFIG
+#include <fontconfig/fcfreetype.h>
+
 static FcConfig *fc_config;
 static MSymbol Mgeneric_family;
 #endif /* HAVE_FONTCONFIG */
@@ -57,18 +60,18 @@ static MSymbol Mgeneric_family;
 /* Font properties; Mnormal is already defined in face.c.  */
 static MSymbol Mmedium, Mr, Mnull;
 
-static MSymbol M0_3, M3_1, M1_0;
+static MSymbol M0[5], M3_1, M1_0;
 
 static FT_Library ft_library;
 
 #ifdef HAVE_OTF
 static OTF *invalid_otf = (OTF *) "";
+static OTF *get_otf (MFLTFont *font, FT_Face *ft_face);
 #endif /* HAVE_OTF */
 
 typedef struct
 {
   MFont font;
-  MPlist *lang;
 #ifdef HAVE_OTF
   /* NULL if not yet opened.  invalid_otf if not OTF.  */
   OTF *otf;
@@ -82,8 +85,9 @@ typedef struct
 typedef struct
 {
   M17NObject control;
-  FT_Face ft_face;
+  FT_Face ft_face;             /* This must be the 2nd member. */
   MPlist *charmap_list;
+  int face_encapsulated;
 } MRealizedFontFT;
 
 typedef struct
@@ -135,29 +139,38 @@ static int all_fonts_scaned;
       (s1) = alloca (len), (size) = len;                       \
     for (p1 = (s1), p2 = (s2); *p2; p1++, p2++)                        \
       *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2);        \
-    while (p1 > (s1) && p1[-1] == ' ') p1--;                   \
     *p1 = '\0';                                                        \
   } while (0)
 
 
+static MPlist *ft_list_family (MSymbol, int, int);
+
 static void
 free_ft_rfont (void *object)
 {
   MRealizedFontFT *ft_rfont = object;
 
-  M17N_OBJECT_UNREF (ft_rfont->charmap_list);
-  FT_Done_Face (ft_rfont->ft_face);
+  if (! ft_rfont->face_encapsulated)
+    {
+      M17N_OBJECT_UNREF (ft_rfont->charmap_list);
+      FT_Done_Face (ft_rfont->ft_face);
+    }
   free (ft_rfont);
 }
 
 static void
 free_ft_info (MFontFT *ft_info)
 {
-  M17N_OBJECT_UNREF (ft_info->lang);
 #ifdef HAVE_OTF
   if (ft_info->otf && ft_info->otf != invalid_otf)
     OTF_close (ft_info->otf);
 #endif /* HAVE_OTF */
+#ifdef HAVE_FONTCONFIG
+  if (ft_info->langset)
+    FcLangSetDestroy (ft_info->langset);
+  if (ft_info->charset)
+    FcCharSetDestroy (ft_info->charset);
+#endif /* HAVE_FONTCONFIG */
   free (ft_info);
 }
 
@@ -175,9 +188,9 @@ ft_get_charmaps (FT_Face ft_face)
 
       if (ft_face->charmaps[i]->platform_id == 0)
        {
-         if (ft_face->charmaps[i]->encoding_id == 3)
-           registry = M0_3, unicode_bmp = i;
-         else if (ft_face->charmaps[i]->encoding_id == 4)
+         if (ft_face->charmaps[i]->encoding_id <= 4)
+           registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
+         if (ft_face->charmaps[i]->encoding_id == 4)
            unicode_bmp = unicode_full = i;
        }
       else if (ft_face->charmaps[i]->platform_id == 3)
@@ -224,6 +237,74 @@ ft_get_charmaps (FT_Face ft_face)
   return plist;
 }
 
+static MFontFT *
+ft_gen_font (FT_Face ft_face)
+{
+  MFontFT *ft_info;
+  MFont *font;
+  char *buf;
+  int bufsize = 0;
+  char *stylename;
+  MSymbol family;
+  int size;
+
+  if (FT_IS_SCALABLE (ft_face))
+    size = ft_face->size->metrics.y_ppem;
+  else if (ft_face->num_fixed_sizes == 0)
+    return NULL;
+  else
+    size = ft_face->available_sizes[0].height;
+
+  MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
+  font = &ft_info->font;
+  STRDUP_LOWER (buf, bufsize, ft_face->family_name);
+  family = msymbol (buf);
+  mfont__set_property (font, MFONT_FAMILY, family);
+  mfont__set_property (font, MFONT_WEIGHT, Mmedium);
+  mfont__set_property (font, MFONT_STYLE, Mr);
+  mfont__set_property (font, MFONT_STRETCH, Mnormal);
+  mfont__set_property (font, MFONT_ADSTYLE, Mnull);
+  mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
+  font->size = size * 10;
+  font->type = MFONT_TYPE_OBJECT;
+  font->source = MFONT_SOURCE_FT;
+  font->file = NULL;
+
+  stylename = ft_face->style_name;
+  while (*stylename)
+    {
+      int i;
+
+      for (i = 0; i < ft_to_prop_size; i++)
+       if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
+                          ft_to_prop[i].len))
+         {
+           mfont__set_property (font, ft_to_prop[i].prop,
+                                msymbol (ft_to_prop[i].val));
+           stylename += ft_to_prop[i].len;
+           break;
+         }
+      if (i == ft_to_prop_size)
+       {
+         char *p1 = stylename + 1;
+         MSymbol sym;
+
+         while (*p1 >= 'a' && *p1 <= 'z') p1++;
+         sym = msymbol__with_len (stylename, p1 - stylename);
+         for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
+           if (msymbol_get (sym, mfont__property_table[i].property))
+             {
+               mfont__set_property (font, i, sym);
+               break;
+             }
+         stylename = p1;
+       }
+      while (*stylename && ! isalpha (*stylename))
+       stylename++;
+    }
+  return ft_info;
+}
+
 #ifdef HAVE_FONTCONFIG
 
 typedef struct
@@ -344,7 +425,7 @@ fc_get_pattern (MFont *font)
 }
 
 static void
-fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
+fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
 {
   FcChar8 *str;
   int val;
@@ -353,6 +434,8 @@ fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
   int bufsize = 0;
   MSymbol sym;
   FcLangSet *ls;
+  FcCharSet *cs;
+  MFont *font = &ft_info->font;
 
   MFONT_INIT (font);
   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
@@ -384,13 +467,14 @@ fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
     }
   if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
     {
-      if (FcLangSetHasLang (ls, (FcChar8 *) "ja") == FcLangEqual
-         || FcLangSetHasLang (ls, (FcChar8 *) "zh-cn") == FcLangEqual
-         || FcLangSetHasLang (ls, (FcChar8 *) "zh-hk") == FcLangEqual
-         || FcLangSetHasLang (ls, (FcChar8 *) "zh-tw") == FcLangEqual
-         || FcLangSetHasLang (ls, (FcChar8 *) "ko") == FcLangEqual)
+      if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
+         || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
+         || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
        font->for_full_width = 1;
+      ft_info->langset = FcLangSetCopy (ls);
     }
+  if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
+    ft_info->charset = FcCharSetCopy (cs);
 
   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
   font->type = MFONT_TYPE_SPEC;
@@ -408,11 +492,131 @@ fc_gen_font (FcPattern *pat, char *family)
   MFontFT *ft_info;
 
   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
-  fc_parse_pattern (pat, family, &ft_info->font);
+  fc_parse_pattern (pat, family, ft_info);
   ft_info->font.type = MFONT_TYPE_OBJECT;
   return ft_info;
 }
 
+static void
+fc_init_font_list (void)
+{
+  FcPattern *pattern = FcPatternCreate ();
+  FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
+  FcFontSet *fs = FcFontList (fc_config, pattern, os);
+  MPlist *plist = mplist ();
+  char *buf;
+  int bufsize = 0;
+  int i;
+
+  ft_font_list = plist;
+  for (i = 0; i < fs->nfont; i++)
+    {
+      char *fam;
+
+      if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
+                             (FcChar8 **) &fam) != FcResultMatch)
+       continue;
+      STRDUP_LOWER (buf, bufsize, fam);
+      plist = mplist_add (plist, msymbol (buf), NULL);
+    }
+  FcFontSetDestroy (fs);
+  FcObjectSetDestroy (os);
+  FcPatternDestroy (pattern);
+}
+
+static MPlist *
+fc_list_pattern (FcPattern *pattern)
+{
+  FcObjectSet *os = NULL;
+  FcFontSet *fs = NULL;
+  MSymbol last_family = Mnil;
+  MPlist *plist = NULL, *pl = NULL;
+  char *buf;
+  int bufsize = 0;
+  int i;
+
+  if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
+    goto err;
+  if (! (fs = FcFontList (fc_config, pattern, os)))
+    goto err;
+
+  for (i = 0; i < fs->nfont; i++)
+    {
+      MSymbol family, file;
+      char *fam, *filename;
+      MFontFT *ft_info;
+
+      if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
+                             (FcChar8 **) &fam) != FcResultMatch)
+       continue;
+      if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
+                             (FcChar8 **) &filename) != FcResultMatch)
+       continue;
+      STRDUP_LOWER (buf, bufsize, fam);
+      family = msymbol (buf);
+      file = msymbol (filename);
+      if (family != last_family)
+       {
+         pl = MPLIST_PLIST (ft_list_family (family, 0, 1));
+         last_family = family;
+       }
+      ft_info = mplist_get (pl, file);
+      if (ft_info)
+       {
+         if (! plist)
+           plist = mplist ();
+         mplist_add (plist, family, ft_info);
+       }
+    }
+
+ err:
+  if (fs) FcFontSetDestroy (fs);
+  if (os) FcObjectSetDestroy (os);
+  return plist;
+}
+
+/* Return FcCharSet object built from CHAR_LIST or MT.  In the latter
+   case, it is assured that the M-text contains at least one
+   character.  */
+
+static FcCharSet *
+fc_build_charset (MPlist *char_list, MText *mt)
+{
+  FcCharSet *cs = FcCharSetCreate ();
+
+  if (! cs)
+    return NULL;
+  if (char_list)
+    {
+      for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
+       if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
+         {
+           FcCharSetDestroy (cs);
+           return NULL;
+         }
+    }
+  else
+    {
+      int i;
+
+      for (i = mtext_nchars (mt) - 1; i >= 0; i--)
+       if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
+         {
+           FcCharSetDestroy (cs);
+           return NULL;
+         }
+      if (mtext_nchars (mt) > 0
+         && (mt = mtext_get_prop (mt, 0, Mtext)))
+       for (i = mtext_nchars (mt) - 1; i >= 0; i--)
+         if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
+           {
+             FcCharSetDestroy (cs);
+             return NULL;
+           }
+      }
+  return cs;
+}
+
 #else  /* not HAVE_FONTCONFIG */
 
 static MPlist *
@@ -431,72 +635,14 @@ ft_add_font (char *filename)
 
   if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
     return NULL;
-  if (! FT_IS_SCALABLE (ft_face))
-    {
-      int reject;
-#ifdef HAVE_FTBDF_H
-      BDF_PropertyRec prop;
-
-      reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
-      size = prop.u.integer * 10;
-#else  /* not HAVE_FTBDF_H */
-      reject = 1;
-#endif /* not HAVE_FTBDF_H */
-      if (reject)
-       {
-         FT_Done_Face (ft_face);
-         return NULL;
-       }
-    }
+  ft_info = ft_gen_font (ft_face);
+  FT_Done_Face (ft_face);
+  if (! ft_info)
+    return NULL;
 
-  MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
   font = &ft_info->font;
-  STRDUP_LOWER (buf, bufsize, ft_face->family_name);
-  family = msymbol (buf);
-  mfont__set_property (font, MFONT_FAMILY, family);
-  mfont__set_property (font, MFONT_WEIGHT, Mmedium);
-  mfont__set_property (font, MFONT_STYLE, Mr);
-  mfont__set_property (font, MFONT_STRETCH, Mnormal);
-  mfont__set_property (font, MFONT_ADSTYLE, Mnull);
-  mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
-  font->type = MFONT_TYPE_OBJECT;
-  font->source = MFONT_SOURCE_FT;
-  font->size = size;
   font->file = msymbol (filename);
 
-  stylename = ft_face->style_name;
-  while (*stylename)
-    {
-      for (i = 0; i < ft_to_prop_size; i++)
-       if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
-                          ft_to_prop[i].len))
-         {
-           mfont__set_property (font, ft_to_prop[i].prop,
-                                msymbol (ft_to_prop[i].val));
-           stylename += ft_to_prop[i].len;
-           break;
-         }
-      if (i == ft_to_prop_size)
-       {
-         char *p1 = stylename + 1;
-         MSymbol sym;
-
-         while (*p1 >= 'a' && *p1 <= 'z') p1++;
-         sym = msymbol__with_len (stylename, p1 - stylename);
-         for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
-           if (msymbol_get (sym, mfont__property_table[i].property))
-             {
-               mfont__set_property (font, i, sym);
-               break;
-             }
-         stylename = p1;
-       }
-      while (*stylename && ! isalpha (*stylename))
-       stylename++;
-    }
-
-  FT_Done_Face (ft_face);
-
   plist = mplist_find_by_key (ft_font_list, family);
   if (plist)
     mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
@@ -509,6 +655,115 @@ ft_add_font (char *filename)
   return plist;
 }
 
+static void
+ft_init_font_list (void)
+{
+  MPlist *plist;
+  struct stat buf;
+  char *pathname;
+  char *path;
+  USE_SAFE_ALLOCA;
+
+  ft_font_list = mplist ();
+  MPLIST_DO (plist, mfont_freetype_path)
+    if (MPLIST_STRING_P (plist)
+       && (pathname = MPLIST_STRING (plist))
+       && stat (pathname, &buf) == 0)
+      {
+       if (S_ISREG (buf.st_mode))
+         ft_add_font (pathname);
+       else if (S_ISDIR (buf.st_mode))
+         {
+           DIR *dir = opendir (pathname);
+
+           if (dir)
+             {
+               int len = strlen (pathname);
+               struct dirent *dp;
+
+               while ((dp = readdir (dir)) != NULL)
+                 {
+                   SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
+                   strcpy (path, pathname);
+                   path[len] =  '/';
+                   strcpy (path + len + 1, dp->d_name);
+                   ft_add_font (path);
+                 }
+               closedir (dir);
+             }
+         }
+      }
+  SAFE_FREE (path);
+}
+
+/* Return 1 iff the font pointed by FT_INFO has all characters in
+   CHAR_LIST.  */
+
+static int
+ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
+{
+  FT_Face ft_face;
+  MPlist *cl;
+
+  if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
+    return 0;
+  MPLIST_DO (cl, char_list)
+    if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
+      break;
+  FT_Done_Face (ft_face);
+  return MPLIST_TAIL_P (cl);
+}
+
+/* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT
+   that supports characters in CHAR_LIST or MT.  One of CHAR_LIST or
+   MT must be NULL.  */
+
+static MPlist *
+ft_list_char_list (MPlist *char_list, MText *mt)
+{
+  MPlist *plist = NULL, *pl, *p;
+
+  if (! ft_font_list)
+    ft_list_family (Mnil, 0, 1);
+
+  if (mt)
+    {
+      int len = mtext_nchars (mt);
+      MText *extra = mtext_get_prop (mt, 0, Mtext);
+      int total_len = len + (extra ? mtext_nchars (extra) : 0);
+      int i;
+
+      char_list = mplist ();
+      for (i = 0; i < total_len; i++)
+       {
+         int c = (i < len ? mtext_ref_char (mt, i)
+                  : mtext_ref_char (extra, i - len));
+
+         if (! mplist_find_by_value (char_list, (void *) c))
+           mplist_push (char_list, Minteger, (void *) c);
+       }
+    }
+
+  MPLIST_DO (pl, ft_font_list)
+    {
+      MPLIST_DO (p, MPLIST_PLIST (pl))
+       {
+         MFontFT *ft_info = MPLIST_VAL (p);
+
+         if (ft_has_char_list_p (ft_info, char_list))
+           {
+             MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
+
+             if (! plist)
+               plist = mplist ();
+             mplist_push (plist, family, ft_info);
+           }
+       }
+    }
+  if (mt)
+    M17N_OBJECT_UNREF (char_list);
+  return plist;
+}
 #endif /* not HAVE_FONTCONFIG */
 
 
@@ -516,7 +771,7 @@ ft_add_font (char *filename)
    scan all fonts and return ft_font_list.  */
 
 static MPlist *
-ft_list_family (MSymbol family, int check_generic)
+ft_list_family (MSymbol family, int check_generic, int check_alias)
 {
   MPlist *plist;
 #ifdef HAVE_FONTCONFIG
@@ -560,7 +815,7 @@ ft_list_family (MSymbol family, int check_generic)
          MPLIST_DO (plist, ft_font_list)
            {
              if (! MPLIST_VAL (plist))
-               ft_list_family (MPLIST_KEY (plist), 0);
+               ft_list_family (MPLIST_KEY (plist), 0, 1);
            }
          all_fonts_scaned = 1;
        }
@@ -576,7 +831,8 @@ ft_list_family (MSymbol family, int check_generic)
          pattern = FcPatternCreate ();
          FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
          os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
-                                FC_PIXEL_SIZE, FC_LANG, FC_FILE, NULL);
+                                FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE,
+                                NULL);
          fs = FcFontList (fc_config, pattern, os);
          p = pl = mplist ();
          for (i = 0; i < fs->nfont; i++)
@@ -597,7 +853,7 @@ ft_list_family (MSymbol family, int check_generic)
       FcChar8 *fam8;
       
       if (family != generic)
-       plist = ft_list_family (generic, 1);
+       plist = ft_list_family (generic, 1, 1);
       else
        {
          fam = MSYMBOL_NAME (family);
@@ -614,7 +870,7 @@ ft_list_family (MSymbol family, int check_generic)
              family = msymbol (buf);
              if (msymbol_get (family, Mgeneric_family))
                break;
-             pl = ft_list_family (family, 0);
+             pl = ft_list_family (family, 0, 1);
              if (! pl)
                continue;
              MPLIST_DO (pl, MPLIST_PLIST (pl))
@@ -623,7 +879,7 @@ ft_list_family (MSymbol family, int check_generic)
          plist = ft_font_list;
        }
     }
-  else
+  else if (check_alias)
     {
       /* Check if there exist an alias.  */
       pl = mplist ();
@@ -659,54 +915,24 @@ ft_list_family (MSymbol family, int check_generic)
              FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
              STRDUP_LOWER (buf, bufsize, fam);
              sym = msymbol (buf);
-             p = MPLIST_PLIST (ft_list_family (sym, 0));
+             p = MPLIST_PLIST (ft_list_family (sym, 0, 0));
              if (! MPLIST_TAIL_P (p))
                MPLIST_DO (p, p)
                  mplist_push (pl, Mt, MPLIST_VAL (p));
            }
        }
     }
+  else
+    {
+      pl = mplist ();
+      plist = mplist_add (ft_font_list, family, pl);
+    }
 
 #else  /* not HAVE_FONTCONFIG */
 
   if (! all_fonts_scaned)
     {
-      MPlist *plist;
-      struct stat buf;
-      char *pathname;
-      char *path;
-      USE_SAFE_ALLOCA;
-
-      ft_font_list = mplist ();
-      MPLIST_DO (plist, mfont_freetype_path)
-       if (MPLIST_STRING_P (plist)
-           && (pathname = MPLIST_STRING (plist))
-           && stat (pathname, &buf) == 0)
-         {
-           if (S_ISREG (buf.st_mode))
-             ft_add_font (pathname);
-           else if (S_ISDIR (buf.st_mode))
-             {
-               DIR *dir = opendir (pathname);
-
-               if (dir)
-                 {
-                   int len = strlen (pathname);
-                   struct dirent *dp;
-
-                   while ((dp = readdir (dir)) != NULL)
-                     {
-                       SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
-                       strcpy (path, pathname);
-                       path[len] =  '/';
-                       strcpy (path + len + 1, dp->d_name);
-                       ft_add_font (path);
-                     }
-                   closedir (dir);
-                 }
-             }
-         }
-      SAFE_FREE (path);
+      ft_init_font_list ();
       all_fonts_scaned = 1;
     }
   if (family == Mnil)
@@ -727,185 +953,105 @@ ft_list_language (MSymbol language)
 {
   MPlist *plist = NULL;
   MText *mt;
-  int step;
 
   if (! ft_language_list)
     ft_language_list = mplist ();
   else if ((plist = mplist_find_by_key (ft_language_list, language)))
     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
 
+  mt = mlanguage_text (language);
+
 #ifdef HAVE_FONTCONFIG
-  for (step = 0; step < 2; step++)
-    {
-      FcPattern *pattern = NULL;
-      FcObjectSet *os = NULL;
-      FcFontSet *fs = NULL;
-      char *buf;
-      int bufsize = 0;
-      int i;
+  {
+    FcPattern *pattern = NULL;
+    FcCharSet *cs = NULL;
+    FcLangSet *ls = NULL;
 
-      if (! (pattern = FcPatternCreate ())
-         || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
-       goto err;
-      if (step == 0)
-       {
-         FcLangSet *ls = FcLangSetCreate ();
-
-         if (! ls)
-           goto err;
-         if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
-             && FcPatternAddLangSet (pattern, FC_LANG, ls))
-           fs = FcFontList (fc_config, pattern, os);
-         FcLangSetDestroy (ls);
-         if (! fs)
-           goto err;
-       }
-      else
-       {
-         FcCharSet *cs;
+    if (! (pattern = FcPatternCreate ()))
+      goto err;
 
-         if (! (mt = msymbol_get (language, Mtext)))
-           break;
-         if (! (cs = FcCharSetCreate ()))
-           goto err;
-         for (i = mtext_nchars (mt) - 1; i >= 0; i--)
-           if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
-             break;
-         if (i < 0)
-           {
-             if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
-               fs = FcFontList (fc_config, pattern, os);
-           }
-         FcCharSetDestroy (cs);
-         if (! fs)
-           goto err;
-       }
-
-      for (i = 0; i < fs->nfont; i++)
-       {
-         MSymbol family, file;
-         char *fam, *filename;
-         MPlist *pl;
-         MFontFT *ft_info;
-
-         if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
-                                 (FcChar8 **) &fam) != FcResultMatch)
-           continue;
-         if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
-                                 (FcChar8 **) &filename) != FcResultMatch)
-           continue;
-         STRDUP_LOWER (buf, bufsize, fam);
-         family = msymbol (buf);
-         file = msymbol (filename);
-         pl = MPLIST_PLIST (ft_list_family (family, 0));
-         ft_info = mplist_get (pl, file);
-         if (ft_info)
-           {
-             if (! plist)
-               plist = mplist ();
-             mplist_add (plist, family, ft_info);
-           }
-       }
-      FcFontSetDestroy (fs);
-      FcObjectSetDestroy (os);
-      FcPatternDestroy (pattern);
-      if (language == msymbol ("en"))
-       break;
-      continue;
-
-    err:
-      if (os)
-       FcObjectSetDestroy (os);
-      if (pattern)
-       FcPatternDestroy (pattern);
-      MEMORY_FULL (MERROR_FONT_FT);
-      return NULL;
-    }
-
-  mplist_push (ft_language_list, language, plist);
-  return plist;
+    if (mt && mtext_nchars (mt) > 0)
+      {
+       cs = fc_build_charset (NULL, mt);       
+       if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
+         goto err;
+      }
+    else
+      {
+       if (! (ls = FcLangSetCreate ()))
+         goto err;
+       if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
+           || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
+         goto err;
+      }
 
+    plist = fc_list_pattern (pattern);
+  err:
+    if (cs) FcCharSetDestroy (cs);
+    if (ls) FcLangSetDestroy (ls);
+    if (pattern) FcPatternDestroy (pattern);
+  }
 #else  /* not HAVE_FONTCONFIG */
-  
-  if ((mt = msymbol_get (language, Mtext)))
-    {
-      MPlist *pl, *p;
-      int len = mtext_nchars (mt);
-      int i;
-
-      if (! ft_font_list)
-       ft_list_family (Mnil, 0);
-      MPLIST_DO (pl, ft_font_list)
-       {
-         MPLIST_DO (p, MPLIST_PLIST (pl))
-           {
-             MFontFT *ft_info = MPLIST_VAL (p);
-             MSymbol family; 
-             FT_Face ft_face;
+  if (mt && mtext_nchars (mt) > 0)
+    plist = ft_list_char_list (NULL, mt);
+#endif  /* not HAVE_FONTCONFIG */
 
-             if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
-                              0, &ft_face) != 0)
-               continue;
-             for (i = 0; i < len; i++)
-               if (FT_Get_Char_Index (ft_face, 
-                                      (FT_ULong) mtext_ref_char (mt, i)) == 0)
-                 break;
-             FT_Done_Face (ft_face);
-             if (i < len)
-               continue;
-             if (! plist)
-               plist = mplist ();
-             family = mfont_get_prop (&ft_info->font, Mfamily);
-             mplist_push (plist, family, ft_info);
-           }
-       }
-    }
+  mplist_push (ft_language_list, language, plist);
   return plist;
-#endif  /* not HAVE_FONTCONFIG */
 }
 
 static MPlist *
 ft_list_script (MSymbol script)
 {
   MPlist *plist = NULL;
-  MPlist *language_list, *pl;
+  MPlist *char_list;
 
   if (! ft_script_list)
     ft_script_list = mplist ();
   else if ((plist = mplist_find_by_key (ft_script_list, script)))
     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
 
-  language_list = mlanguage__list (script);
-  MPLIST_DO (pl, language_list)
+  char_list = mscript__char_list (script);
+
+#ifdef HAVE_FONTCONFIG
+  if (char_list)
     {
-      MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
-      MPlist *p = ft_list_language (language);
-      MSymbol family;
+      FcPattern *pattern = NULL;
+      FcCharSet *cs;
 
-      if (! p)
-       continue;
-      if (! plist)
-       plist = mplist ();
-      MPLIST_DO (p, p)
-       {
-         family = MPLIST_KEY (p);
-         if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
-           mplist_add (plist, family, MPLIST_VAL (p));
-       }
+      if (! (pattern = FcPatternCreate ()))
+       goto err;
+      cs = fc_build_charset (char_list, NULL);
+      if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
+         goto err;
+      plist = fc_list_pattern (pattern);
+    err:
+      if (cs) FcCharSetDestroy (cs);
+      if (pattern) FcPatternDestroy (pattern);
     }
+#else  /* not HAVE_FONTCONFIG */
+  if (char_list)
+    plist = ft_list_char_list (char_list, NULL);
+#endif /* not HAVE_FONTCONFIG */
+
   mplist_push (ft_script_list, script, plist);
-  M17N_OBJECT_UNREF (language_list);
   return (plist);
 }
 
 static int
-ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
+ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
 {
+#ifdef HAVE_OTF
   if (ft_info->otf == invalid_otf)
     return -1;
   if (! ft_info->otf)
     {
-      ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
+#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
+      if (ft_face)
+       ft_info->otf = OTF_open_ft_face (ft_face);
+      else
+#endif
+       ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
       if (! ft_info->otf)
        {
          ft_info->otf = invalid_otf;
@@ -913,7 +1059,6 @@ ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
        }
     }
   if (cap->features[MFONT_OTT_GSUB].nfeatures
-      && cap->features[MFONT_OTT_GSUB].tags[0]
       && (OTF_check_features
          (ft_info->otf, 1,
           cap->script_tag, cap->langsys_tag,
@@ -921,7 +1066,6 @@ ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
           cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
     return -1;
   if (cap->features[MFONT_OTT_GPOS].nfeatures
-      && cap->features[MFONT_OTT_GPOS].tags[0]
       && (OTF_check_features
          (ft_info->otf, 0,
           cap->script_tag, cap->langsys_tag,
@@ -929,73 +1073,103 @@ ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
           cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
     return -1;
   return 0;
+#else  /* not HAVE_OTF */
+  return -1;
+#endif /* not HAVE_OTF */
 }
 
 static int
-ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
+ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face)
 {
-#ifdef HAVE_FONTCONFIG
-  MPlist *plist;
   MText *mt;
-  int i, j;
+  MText *extra;
+  int ft_face_allocaed = 0;
+  int len, total_len;
+  int i;
+
+#ifdef HAVE_FONTCONFIG
+  if (ft_info->langset
+      && (FcLangSetHasLang (ft_info->langset,
+                           (FcChar8 *) MSYMBOL_NAME (language))
+         != FcLangDifferentLang))
+    return 0;
+#endif /* HAVE_FONTCONFIG */
+
+  mt = mlanguage_text (language);
+  if (! mt || mtext_nchars (mt) == 0)
+    return -1;
 
-  for (i = 0; cap->lang[i] != Mnil; i++)
+  if (! ft_face)
     {
-      if (ft_info->lang
-         && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
-       {
-         if (MPLIST_VAL (plist))
-           return 0;
-         continue;
-       }
+      char *filename = MSYMBOL_NAME (ft_info->font.file);
 
-      if (! ft_info->langset)
-       {
-         FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
-                                          MSYMBOL_NAME (ft_info->font.file),
-                                          NULL);
-         FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
-         FcFontSet *fs = FcFontList (fc_config, pat, os);
+      if (FT_New_Face (ft_library, filename, 0, &ft_face))
+       return -1;
+      ft_face_allocaed = 1;
+    }
 
-         if (fs->nfont == 0)
-           return -1;
-         if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
-             == FcResultMatch)
-           ft_info->langset = FcLangSetCopy (ft_info->langset);
-         else
-           ft_info->langset = FcLangSetCreate ();
-         FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
-         FcFontSetDestroy (fs);
-         FcObjectSetDestroy (os);
-         FcPatternDestroy (pat);
-       }
-      if (! ft_info->lang)
-       ft_info->lang = mplist ();
-      if (FcLangSetHasLang (ft_info->langset,
-                           (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
-         == FcLangEqual)
-       {
-         mplist_push (ft_info->lang, cap->lang[i], Mt);
-         return 0;
-       }
+  len = mtext_nchars (mt);
+  extra = mtext_get_prop (mt, 0, Mtext);
+  total_len = len + (extra ? mtext_nchars (extra) : 0);
+
+  for (i = 0; i < total_len; i++)
+    {
+      int c = (i < len ? mtext_ref_char (mt, i)
+              : mtext_ref_char (extra, i - len));
+
+#ifdef HAVE_FONTCONFIG
+      if (ft_info->charset
+         && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
+       break;
+#endif /* HAVE_FONTCONFIG */
+      if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
+       break;
+    }
+
+  if (ft_face_allocaed)
+    FT_Done_Face (ft_face);
+
+  return (i == total_len ? 0 : -1);
+}
+
+static int
+ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face)
+{
+  MPlist *char_list = mscript__char_list (script);
+
+  if (! char_list)
+    return -1;
+#ifdef HAVE_FONTCONFIG
+  if (ft_info->charset)
+    {
+      MPLIST_DO (char_list, char_list)
+       if (FcCharSetHasChar (ft_info->charset,
+                             (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
+         break;
+    }
+  else
+#endif /* HAVE_FONTCONFIG */
+    {
+      int ft_face_allocaed = 0;
 
-      mt = msymbol_get (cap->lang[i], Mtext);
-      if (! mt)
+      if (! ft_face)
        {
-         mplist_push (ft_info->lang, cap->lang[i], Mnil);
-         continue;
+         char *filename = MSYMBOL_NAME (ft_info->font.file);
+
+         if (FT_New_Face (ft_library, filename, 0, &ft_face))
+           return -1;
+         ft_face_allocaed = 1;
        }
 
-      for (j = mtext_nchars (mt) - 1; j >= 0; j--)
-       if (! FcCharSetAddChar (ft_info->charset,
-                               (FcChar32) mtext_ref_char (mt, j)))
+      MPLIST_DO (char_list, char_list)
+       if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
+           == 0)
          break;
-      mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
-      if (j < 0)
-       return 0;
+      if (ft_face_allocaed)
+       FT_Done_Face (ft_face);
     }
-#endif /* HAVE_FONTCONFIG */
-  return -1;
+
+  return (MPLIST_TAIL_P (char_list) ? 0 : -1);
 }
 
 static MPlist *ft_default_list;
@@ -1025,7 +1199,7 @@ ft_list_default ()
        family = msymbol (buf);
        if (msymbol_get (family, Mgeneric_family))
          continue;
-       plist = MPLIST_PLIST (ft_list_family (family, 0));
+       plist = MPLIST_PLIST (ft_list_family (family, 0, 1));
        MPLIST_DO (plist, plist)
          mplist_add (ft_default_list, family, MPLIST_VAL (plist));
       }
@@ -1034,7 +1208,7 @@ ft_list_default ()
   {
     MPlist *plist, *pl;
 
-    MPLIST_DO (plist, ft_list_family (Mnil, 0))
+    MPLIST_DO (plist, ft_list_family (Mnil, 0, 1))
       {
        pl = MPLIST_PLIST (plist);
        if (! MPLIST_TAIL_P (pl))
@@ -1049,60 +1223,65 @@ ft_list_default ()
 static MPlist *ft_capability_list;
 
 static MPlist *
-ft_list_capability (MSymbol sym)
+ft_list_capability (MSymbol capability)
 {
-  MPlist *plist, *pl, *p;
-  MFontCapability *cap = mfont__get_capability (sym);
+  MFontCapability *cap;
+  MPlist *plist = NULL, *pl;
 
-  if (! cap)
-    return NULL;
-  if (ft_capability_list)
-    {
-      plist = mplist_find_by_key (ft_capability_list, sym);
-      if (plist)
-       return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
-    }
-  else
-    {
-      plist = NULL;
-      ft_capability_list = mplist ();
-    }
+  if (! ft_capability_list)
+    ft_capability_list = mplist ();
+  else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
+    return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
 
-  if (cap->script != Mnil)
+  cap = mfont__get_capability (capability);
+
+  if (cap && cap->language != Mnil)
     {
-      pl = ft_list_script (cap->script);
-      if (pl)
-       MPLIST_DO (pl, pl)
-         {
-           if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
-             continue;
-           if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
-             continue;
-           if (! plist)
-             plist = mplist ();
-           mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
-       }
-      mplist_push (ft_capability_list, sym, plist);
-      return plist;
+      plist = ft_list_language (cap->language);
+      if (! plist)
+       return NULL;
+      plist = mplist_copy (plist);
     }
 
-  if (cap->lang)
+  if (cap && cap->script != Mnil)
     {
-      int i;
+      if (! plist)
+       {
+         plist = ft_list_script (cap->script);
+         if (! plist)
+           return NULL;
+         plist = mplist_copy (plist);
+       }
+      else
+       {
+         for (pl = plist; ! MPLIST_TAIL_P (pl);)
+           {
+             if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
+               mplist_pop (pl);
+             else
+               pl = MPLIST_NEXT (pl);
+           }
+       }
 
-      for (i = 0; cap->lang[i] != Mnil; i++)
+      if (cap->script_tag)
        {
-         p = ft_list_language (cap->lang[i]);
-         if (p)
+         for (pl = plist; ! MPLIST_TAIL_P (pl);)
            {
-             if (! plist)
-               plist = mplist ();
-             MPLIST_DO (p, p)
-               mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
+             if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
+               mplist_pop (pl);
+             else
+               pl = MPLIST_NEXT (pl);
            }
        }
+
+      if (MPLIST_TAIL_P (plist))
+       {
+         M17N_OBJECT_UNREF (plist);
+         plist = NULL;
+       }
     }
-  mplist_push (ft_capability_list, sym, plist);
+
+  mplist_push (ft_capability_list, capability, plist);
   return plist;
 }
 
@@ -1140,7 +1319,7 @@ ft_list_file (MSymbol filename)
 
            STRDUP_LOWER (buf, bufsize, fam);
            family = msymbol (buf);
-           pl = ft_list_family (family, 0);
+           pl = ft_list_family (family, 0, 1);
            MPLIST_DO (pl, MPLIST_PLIST (pl))
              {
                MFontFT *ft_info = MPLIST_VAL (pl);
@@ -1159,7 +1338,7 @@ ft_list_file (MSymbol filename)
   {
     MPlist *pl, *p;
 
-    MPLIST_DO (pl, ft_list_family (Mnil, 0))
+    MPLIST_DO (pl, ft_list_family (Mnil, 0, 1))
       {
        MPLIST_DO (p, MPLIST_PLIST (pl))
          {
@@ -1205,7 +1384,7 @@ ft_select (MFrame *frame, MFont *font, int limited_size)
       MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
 
       if (family)
-       plist = MPLIST_PLIST (ft_list_family (family, 1));
+       plist = MPLIST_PLIST (ft_list_family (family, 1, 1));
       else
        plist = ft_list_default ();
       if (MPLIST_TAIL_P (plist))
@@ -1220,8 +1399,13 @@ ft_select (MFrame *frame, MFont *font, int limited_size)
 
       for (pl = plist; ! MPLIST_TAIL_P (pl);)
        {
-         if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
-             || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0))
+         if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
+           {
+             mplist_pop (pl);
+             continue;
+           }
+         if (cap->language
+             && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
            mplist_pop (pl);
          else
            pl = MPLIST_NEXT (pl);
@@ -1272,7 +1456,7 @@ ft_select (MFrame *frame, MFont *font, int limited_size)
        }
     }
   M17N_OBJECT_UNREF (plist);
-#endif
+#endif /* HAVE_FONTCONFIG */
   return found;
 }
 
@@ -1287,7 +1471,19 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   FT_Face ft_face;
   MPlist *plist, *charmap_list = NULL;
   int charmap_index;
-  int size = font->size ? font->size : spec->size;
+  int size;
+
+  if (font->size)
+    /* non-scalable font */
+    size = font->size;
+  else if (spec->size)
+    {
+      int ratio = mfont_resize_ratio (font);
+
+      size = ratio == 100 ? spec->size : spec->size * ratio / 100;
+    }
+  else
+    size = 120;
 
   if (rfont)
     {
@@ -1301,13 +1497,13 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
          return rfont;
     }
 
-  MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (spec));
+  MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
 
   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
                   &ft_face))
     {
       font->type = MFONT_TYPE_FAILURE;
-      MDEBUG_PRINT ("  no\n");
+      MDEBUG_PRINT ("  no (FT_New_Face)\n");
       return NULL;
     }
   if (charmap_list)
@@ -1321,7 +1517,7 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
     {
       FT_Done_Face (ft_face);
       M17N_OBJECT_UNREF (charmap_list);
-      MDEBUG_PRINT ("  no\n");
+      MDEBUG_PRINT1 ("  no (%s)\n", MSYMBOL_NAME (registry));
       return NULL;
     }
   charmap_index = (int) MPLIST_VAL (plist);
@@ -1332,7 +1528,7 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
       FT_Done_Face (ft_face);
       M17N_OBJECT_UNREF (charmap_list);
       font->type = MFONT_TYPE_FAILURE;
-      MDEBUG_PRINT ("  no\n");
+      MDEBUG_PRINT1 ("  no (size %d)\n", size);
       return NULL;
     }
 
@@ -1340,6 +1536,7 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   ft_rfont->ft_face = ft_face;
   ft_rfont->charmap_list = charmap_list;
   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
+  rfont->id = ft_info->font.file;
   rfont->spec = *font;
   rfont->spec.type = MFONT_TYPE_REALIZED;
   rfont->spec.property[MFONT_REGISTRY] = reg;
@@ -1349,10 +1546,12 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   rfont->driver = &mfont__ft_driver;
   rfont->info = ft_rfont;
   rfont->fontp = ft_face;
-  rfont->ascent = ft_face->size->metrics.ascender >> 6;
-  rfont->descent = - ft_face->size->metrics.descender >> 6;
-  rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
+  rfont->ascent = ft_face->size->metrics.ascender;
+  rfont->descent = - ft_face->size->metrics.descender;
+  rfont->max_advance = ft_face->size->metrics.max_advance;
   rfont->baseline_offset = 0;
+  rfont->x_ppem = ft_face->size->metrics.x_ppem;
+  rfont->y_ppem = ft_face->size->metrics.y_ppem;
 #ifdef HAVE_FTBDF_H
   {
     BDF_PropertyRec prop;
@@ -1360,16 +1559,16 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
     if (! FT_IS_SCALABLE (ft_face)
        && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
       {
-       rfont->baseline_offset = prop.u.integer;
-       rfont->ascent += prop.u.integer;
-       rfont->descent -= prop.u.integer;
+       rfont->baseline_offset = prop.u.integer << 6;
+       rfont->ascent += prop.u.integer << 6;
+       rfont->descent -= prop.u.integer << 6;
       }
   }
-#endif
+#endif /* HAVE_FTBDF_H */
   if (FT_IS_SCALABLE (ft_face))
     rfont->average_width = 0;
   else
-    rfont->average_width = ft_face->available_sizes->width;
+    rfont->average_width = ft_face->available_sizes->width << 6;
   rfont->next = MPLIST_VAL (frame->realized_font_list);
   MPLIST_VAL (frame->realized_font_list) = rfont;
   MDEBUG_PRINT ("  ok\n");
@@ -1387,45 +1586,44 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
 
   for (; g != gend; g++)
     {
-      if (g->code == MCHAR_INVALID_CODE)
+      if (g->g.measured)
+       continue;
+      if (g->g.code == MCHAR_INVALID_CODE)
        {
          if (FT_IS_SCALABLE (ft_face))
            {
-             unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
-             int size = rfont->spec.size;
-
-             g->lbearing = 0;
-             g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
-             g->width = g->rbearing;
-             g->ascent = ft_face->ascender * size / unitsPerEm10;
-             g->descent = (- ft_face->descender) * size / unitsPerEm10;
+             g->g.lbearing = 0;
+             g->g.rbearing = ft_face->size->metrics.max_advance;
+             g->g.xadv = g->g.rbearing;
+             g->g.ascent = ft_face->size->metrics.ascender;
+             g->g.descent = - ft_face->size->metrics.descender;
            }
          else
            {
 #ifdef HAVE_FTBDF_H
              BDF_PropertyRec prop;
-#endif
+#endif /* HAVE_FTBDF_H */
 
-             g->lbearing = 0;
-             g->rbearing = g->width = ft_face->available_sizes->width;
+             g->g.lbearing = 0;
+             g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
 #ifdef HAVE_FTBDF_H
              if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
                {
-                 g->ascent = prop.u.integer;
+                 g->g.ascent = prop.u.integer << 6;
                  FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
-                 g->descent = prop.u.integer;
+                 g->g.descent = prop.u.integer << 6;
                  if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
                                           & prop) == 0)
                    {
-                     g->ascent += prop.u.integer;
-                     g->descent -= prop.u.integer;
+                     g->g.ascent += prop.u.integer << 6;
+                     g->g.descent -= prop.u.integer << 6;
                    }
                }
              else
-#endif
+#endif /* HAVE_FTBDF_H */
                {
-                 g->ascent = ft_face->available_sizes->height;
-                 g->descent = 0;
+                 g->g.ascent = ft_face->available_sizes->height << 6;
+                 g->g.descent = 0;
                }
            }
        }
@@ -1433,16 +1631,18 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
        {
          FT_Glyph_Metrics *metrics;
 
-         FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
+         FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, FT_LOAD_DEFAULT);
          metrics = &ft_face->glyph->metrics;
-         g->lbearing = (metrics->horiBearingX >> 6);
-         g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
-         g->width = metrics->horiAdvance >> 6;
-         g->ascent = metrics->horiBearingY >> 6;
-         g->descent = (metrics->height - metrics->horiBearingY) >> 6;
+         g->g.lbearing = metrics->horiBearingX;
+         g->g.rbearing = metrics->horiBearingX + metrics->width;
+         g->g.xadv = metrics->horiAdvance;
+         g->g.ascent = metrics->horiBearingY;
+         g->g.descent = metrics->height - metrics->horiBearingY;
        }
-      g->ascent += rfont->baseline_offset;
-      g->descent -= rfont->baseline_offset;
+      g->g.yadv = 0;
+      g->g.ascent += rfont->baseline_offset;
+      g->g.descent -= rfont->baseline_offset;
+      g->g.measured = 1;
     }
 }
 
@@ -1554,6 +1754,7 @@ ft_render (MDrawWindow win, int x, int y,
   int i, j;
   MPointTable point_table[8];
   int baseline_offset;
+  int pixel_mode = -1;
 
   if (from == to)
     return;
@@ -1561,7 +1762,7 @@ ft_render (MDrawWindow win, int x, int y,
   /* It is assured that the all glyphs in the current range use the
      same realized face.  */
   ft_face = rface->rfont->fontp;
-  baseline_offset = rface->rfont->baseline_offset;
+  baseline_offset = rface->rfont->baseline_offset >> 6;
 
   if (! gstring->anti_alias)
     {
@@ -1575,7 +1776,7 @@ ft_render (MDrawWindow win, int x, int y,
   for (i = 0; i < 8; i++)
     point_table[i].p = point_table[i].points;
 
-  for (g = from; g < to; x += g++->width)
+  for (g = from; g < to; x += g++->g.xadv)
     {
       unsigned char *bmp;
       int intensity;
@@ -1583,21 +1784,19 @@ ft_render (MDrawWindow win, int x, int y,
       int xoff, yoff;
       int width, pitch;
 
-      FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
-      yoff = y - ft_face->glyph->bitmap_top + g->yoff;
+      FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
+      if (pixel_mode < 0)
+       pixel_mode = ft_face->glyph->bitmap.pixel_mode;
+      yoff = y - ft_face->glyph->bitmap_top + g->g.yoff;
       bmp = ft_face->glyph->bitmap.buffer;
       width = ft_face->glyph->bitmap.width;
       pitch = ft_face->glyph->bitmap.pitch;
-      if (! gstring->anti_alias)
-       pitch *= 8;
-      if (width > pitch)
-       width = pitch;
 
-      if (gstring->anti_alias)
+      if (pixel_mode != FT_PIXEL_MODE_MONO)
        for (i = 0; i < ft_face->glyph->bitmap.rows;
             i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
          {
-           xoff = x + ft_face->glyph->bitmap_left + g->xoff;
+           xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
            for (j = 0; j < width; j++, xoff++)
              {
                intensity = bmp[j] >> 5;
@@ -1622,7 +1821,7 @@ ft_render (MDrawWindow win, int x, int y,
        for (i = 0; i < ft_face->glyph->bitmap.rows;
             i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
          {
-           xoff = x + ft_face->glyph->bitmap_left + g->xoff;
+           xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
            for (j = 0; j < width; j++, xoff++)
              {
                intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
@@ -1644,7 +1843,7 @@ ft_render (MDrawWindow win, int x, int y,
        }
     }
 
-  if (gstring->anti_alias)
+  if (pixel_mode != FT_PIXEL_MODE_MONO)
     {
       for (i = 1; i < 8; i++)
        if (point_table[i].p != point_table[i].points)
@@ -1692,7 +1891,7 @@ ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
        goto done;
       family = FONT_PROPERTY (font, MFONT_FAMILY);
       if (family != Mnil
-         && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
+         && (family_list = MPLIST_PLIST (ft_list_family (family, 1, 1)))
          && MPLIST_TAIL_P (family_list))
        goto done;
       if (font->capability != Mnil)
@@ -1701,17 +1900,13 @@ ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
          if (! capability_list || MPLIST_TAIL_P (capability_list))
            goto done;
        }
-      else if (family == Mnil)
-       {
-         capability_list = ft_list_default ();
-       }
     }
 
   if (! file_list && ! family_list && ! capability_list)
     {
       /* No restriction.  Get all fonts.  */
       pl = mplist ();
-      MPLIST_DO (family_list, ft_list_family (Mnil, 0))
+      MPLIST_DO (family_list, ft_list_family (Mnil, 0, 1))
        {
          MPLIST_DO (p, MPLIST_PLIST (family_list))
            mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
@@ -1803,59 +1998,718 @@ ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
   return num;
 }
 
-\f
-/* Internal API */
+static void
+ft_list_family_names (MFrame *frame, MPlist *plist)
+{
+  MPlist *pl;
 
-MFontDriver mfont__ft_driver =
-  { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
-    ft_render, ft_list };
+  if (! ft_font_list)
+    {
+#ifdef HAVE_FONTCONFIG
+      fc_init_font_list ();
+#else  /* not HAVE_FONTCONFIG */
+      ft_init_font_list ();
+#endif /* not HAVE_FONTCONFIG */
+    }
 
-int
-mfont__ft_init ()
-{
-  int i;
+  MPLIST_DO (pl, ft_font_list)
+    {
+      MSymbol family = MPLIST_KEY (pl);
+      MPlist *p;
 
-  if (FT_Init_FreeType (&ft_library) != 0)
-    MERROR (MERROR_FONT_FT, -1);
+#ifdef HAVE_FONTCONFIG
+      if (msymbol_get (family, Mgeneric_family) != Mnil)
+       continue;
+#endif /* HAVE_FONTCONFIG */
+      MPLIST_DO (p, plist)
+       {
+         MSymbol sym = MPLIST_SYMBOL (p);
 
-  for (i = 0; i < ft_to_prop_size; i++)
-    ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
+         if (sym == family)
+           break;
+         if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
+           {
+             mplist_push (p, Msymbol, family);
+             break;
+           }
+       }
+      if (MPLIST_TAIL_P (p))
+       mplist_push (p, Msymbol, family);
+    }
+}
 
-  Mmedium = msymbol ("medium");
-  Mr = msymbol ("r");
-  Mnull = msymbol ("");
+static int 
+ft_check_capability (MRealizedFont *rfont, MSymbol capability)
+{
+  MFontFT *ft_info = (MFontFT *) rfont->font;
+  MRealizedFontFT *ft_rfont = rfont->info;
+  MFontCapability *cap = mfont__get_capability (capability);
 
-  M0_3 = msymbol ("0-3");
-  M3_1 = msymbol ("3-1");
-  M1_0 = msymbol ("1-0");
+  if (cap->script_tag)
+    {
+      if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
+       return -1;
+    }
+  else if (cap->script != Mnil
+          && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
+    return -1;
+  if (cap->language != Mnil
+      && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
+    return -1;
+  return 0;
+}
 
-#ifdef HAVE_FONTCONFIG
-  for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
+static MRealizedFont *
+ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
+{
+  MFontFT *ft_info;
+  MRealizedFont *rfont;
+  MRealizedFontFT *ft_rfont;
+  FT_Face ft_face;
+
+  if (data_type == Mfontconfig)
     {
-      FC_vs_M17N_font_prop *table = fc_all_table[i];
-      int j;
+#ifdef HAVE_FONTCONFIG
+      FcPattern *pattern = data;
 
-      for (j = 0; table[j].m17n_value; j++)
-       table[j].sym = msymbol (table[j].m17n_value);
-      table[j].sym = table[j - 1].sym;
+      if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
+         != FcResultMatch)
+       return NULL;
+      ft_info = fc_gen_font (pattern, NULL);
+#else  /* not HAVE_FONTCONFIG */
+      return NULL;
+#endif /* not HAVE_FONTCONFIG */
+    }
+  else if (data_type == Mfreetype)
+    {
+      ft_face = data;
+      ft_info = ft_gen_font (ft_face);
     }
+  else
+    return NULL;
 
-  {
-    char *pathname;
-    struct stat buf;
-    MPlist *plist;
-    MSymbol serif, sans_serif, monospace;
+  M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
+  ft_rfont->ft_face = ft_face;
+  ft_rfont->face_encapsulated = 1;
 
-    fc_config = FcInitLoadConfigAndFonts ();
-    if (mfont_freetype_path)
-      {
-       MPLIST_DO (plist, mfont_freetype_path)
-         if (MPLIST_STRING_P (plist)
-             && (pathname = MPLIST_STRING (plist))
-             && stat (pathname, &buf) == 0)
-           {
-             FcStrList *strlist = FcConfigGetFontDirs (fc_config);
-             FcChar8 *dir;
+  MDEBUG_PRINT1 (" [FONT-FT] encapsulating %s", (char *) ft_face->family_name);
+
+  MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
+  rfont->id = ft_info->font.file;
+  rfont->font = (MFont *) ft_info;
+  rfont->info = ft_rfont;
+  rfont->fontp = ft_face;
+  rfont->driver = &mfont__ft_driver;
+  rfont->spec = ft_info->font;
+  rfont->spec.type = MFONT_TYPE_REALIZED;
+  rfont->frame = frame;
+  rfont->ascent = ft_face->size->metrics.ascender >> 6;
+  rfont->descent = - ft_face->size->metrics.descender >> 6;
+  rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
+  rfont->baseline_offset = 0;
+  rfont->x_ppem = ft_face->size->metrics.x_ppem;
+  rfont->y_ppem = ft_face->size->metrics.y_ppem;
+#ifdef HAVE_FTBDF_H
+  {
+    BDF_PropertyRec prop;
+
+    if (! FT_IS_SCALABLE (ft_face)
+       && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
+      {
+       rfont->baseline_offset = prop.u.integer << 6;
+       rfont->ascent += prop.u.integer << 6;
+       rfont->descent -= prop.u.integer << 6;
+      }
+  }
+#endif /* HAVE_FTBDF_H */
+  if (FT_IS_SCALABLE (ft_face))
+    rfont->average_width = 0;
+  else
+    rfont->average_width = ft_face->available_sizes->width << 6;
+  rfont->next = MPLIST_VAL (frame->realized_font_list);
+  MPLIST_VAL (frame->realized_font_list) = rfont;
+
+  return rfont;
+}
+
+static void
+ft_close (MRealizedFont *rfont)
+{
+  if (! rfont->encapsulating)
+    return;
+  free (rfont->font);
+  M17N_OBJECT_UNREF (rfont->info);
+  free (rfont);
+}
+
+static int 
+ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
+{
+#ifdef HAVE_OTF
+  OTF_Tag *tags;
+  int i, n, negative;
+  OTF *otf = get_otf (font, NULL);
+
+  if (! otf)
+    goto not_otf;
+  for (i = 0; i < 2; i++)
+    {
+      if (! spec->features[i])
+       continue;
+      for (n = 0; spec->features[i][n]; n++);
+      tags = alloca (sizeof (OTF_Tag) * n);
+      for (n = 0, negative = 0; spec->features[i][n]; n++)
+       {
+         if (spec->features[i][n] == 0xFFFFFFFF)
+           negative = 1;
+         else if (negative)
+           tags[n - 1] = spec->features[i][n] | 0x80000000;
+         else
+           tags[n] = spec->features[i][n];
+       }
+      if (n - negative > 0
+         && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
+                                tags, n - negative) != 1)
+       return 0;
+    }
+  return 1;
+ not_otf:
+#endif /* HAVE_OTF */
+  return ((! spec->features[0] || spec->features[0][0] == 0xFFFFFFFF)
+         && (! spec->features[1] || spec->features[1][0] == 0xFFFFFFFF));
+}
+
+#ifdef HAVE_OTF
+
+static OTF *
+get_otf (MFLTFont *font, FT_Face *ft_face)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MFontFT *ft_info = (MFontFT *) rfont->font;
+  MRealizedFontFT *ft_rfont = rfont->info;
+  OTF *otf = ft_info->otf;
+
+  if (! otf)
+    {
+#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
+      otf = OTF_open_ft_face (ft_rfont->ft_face);
+#else
+      otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
+#endif
+      if (! otf || OTF_get_table (otf, "head") < 0)
+       otf = invalid_otf;
+      ft_info->otf = otf;
+    }
+  if (ft_face)
+    *ft_face = ft_rfont->ft_face;
+  return (otf == invalid_otf ? NULL : otf);
+}
+
+#define DEVICE_DELTA(table, size)                              \
+  (((size) >= (table).StartSize && (size) <= (table).EndSize)  \
+   ? (table).DeltaValue[(size) - (table).StartSize] << 6       \
+   : 0)
+
+void
+adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
+              unsigned code, int x_ppem, int y_ppem, int *x, int *y)
+{
+  if (anchor->AnchorFormat == 2)
+    {
+      FT_Outline *outline;
+      int ap = anchor->f.f1.AnchorPoint;
+
+      FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
+      outline = &ft_face->glyph->outline;
+      if (ap < outline->n_points)
+       {
+         *x = outline->points[ap].x << 6;
+         *y = outline->points[ap].y << 6;
+       }
+    }
+  else if (anchor->AnchorFormat == 3)
+    {
+      if (anchor->f.f2.XDeviceTable.offset)
+       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
+      if (anchor->f.f2.YDeviceTable.offset)
+       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
+    }
+}
+#endif /* HAVE_OTF */
+
+static int 
+ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
+             MFLTGlyphString *in, int from, int to,
+             MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
+{
+  int len = to - from;
+#ifdef HAVE_OTF
+  int i, j, gidx;
+  MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
+  MGlyph *out_glyphs = out ? (MGlyph *) (out->glyphs) : NULL;
+  OTF *otf;
+  FT_Face face;
+  OTF_GlyphString otf_gstring;
+  OTF_Glyph *otfg;
+  char script[5], *langsys = NULL;
+  char *gsub_features = NULL, *gpos_features = NULL;
+  unsigned int tag;
+
+  if (len == 0)
+    return from;
+  otf = get_otf (font, &face);
+  if (! otf)
+    goto simple_copy;
+  OTF_tag_name (spec->script, script);
+  if (spec->langsys)
+    {
+      langsys = alloca (5);
+      OTF_tag_name (spec->langsys, langsys);
+    }
+  for (i = 0; i < 2; i++)
+    {
+      char *p;
+
+      if (spec->features[i])
+       {
+         for (j = 0; spec->features[i][j]; j++);
+         if (i == 0)
+           p = gsub_features = alloca (6 * j);
+         else
+           p = gpos_features = alloca (6 * j);
+         for (j = 0; spec->features[i][j]; j++)
+           {
+             if (spec->features[i][j] == 0xFFFFFFFF)
+               *p++ = '*', *p++ = ',';
+             else
+               {
+                 OTF_tag_name (spec->features[i][j], p);
+                 p[4] = ',';
+                 p += 5;
+               }
+           }
+         *--p = '\0';
+       }
+    }
+
+  otf_gstring.size = otf_gstring.used = len;
+  otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
+  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
+  for (i = 0; i < len; i++)
+    {
+      otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c & 0x11FFFF;
+      otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
+    }
+
+  OTF_drive_gdef (otf, &otf_gstring);
+  gidx = out ? out->used : from;
+
+  if (gsub_features)
+    {
+      OTF_Feature *features;
+      MGlyph *g;
+
+      if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
+                                  gsub_features) < 0)
+       goto simple_copy;
+      features = otf->gsub->FeatureList.Feature;
+      if (out)
+       {
+         if (out->allocated < gidx + otf_gstring.used)
+           return -2;
+         for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
+              i < otf_gstring.used; i++, otfg++, g++, out->used++)
+           {
+             int feature_idx = otfg->positioning_type >> 4;
+             int j;
+             int min_from, max_to;
+
+             *g = in_glyphs[from + otfg->f.index.from];
+             min_from = g->g.from, max_to = g->g.to;
+             g->g.c = 0;
+             for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
+               if (in_glyphs[from + j].g.code == otfg->glyph_id)
+                 {
+                   g->g.c = in_glyphs[from + j].g.c;
+                   break;
+                 }
+             if (feature_idx)
+               {
+                 tag = features[feature_idx - 1].FeatureTag;
+                 tag = PACK_OTF_TAG (tag);
+                 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+               }
+             for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
+               {
+                 if (min_from > in_glyphs[from + j].g.from)
+                   min_from = in_glyphs[from + j].g.from;
+                 if (max_to < in_glyphs[from + j].g.to)
+                   max_to = in_glyphs[from + j].g.to;
+               }
+             if (g->g.code != otfg->glyph_id)
+               {
+                 g->g.code = otfg->glyph_id;
+                 g->g.measured = 0;
+               }
+             g->g.from = min_from, g->g.to = max_to;
+           }
+       }
+      else
+       {
+         for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
+              i++, otfg++)
+           {
+             int feature_idx = otfg->positioning_type >> 4;
+
+             if (feature_idx)
+               {
+                 tag = features[feature_idx - 1].FeatureTag;
+                 tag = PACK_OTF_TAG (tag);
+                 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
+                   {
+                     g = in_glyphs + (from + j);
+                     g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+                   }
+               }
+           }
+       }
+    }
+  else if (out)
+    {
+      if (out->allocated < gidx + len)
+       return -2;
+      for (i = 0; i < len; i++)
+       out_glyphs[out->used++] = in_glyphs[from + i];
+    }
+
+  if (gpos_features)
+    {
+      OTF_Feature *features;
+      MGlyph *g;
+
+      if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
+                                  gpos_features) < 0)
+       return to;
+      features = otf->gpos->FeatureList.Feature;
+      if (out)
+       {
+         MGlyph *base = NULL, *mark = NULL;
+         int x_ppem = face->size->metrics.x_ppem;
+         int y_ppem = face->size->metrics.y_ppem;
+         int x_scale = face->size->metrics.x_scale;
+         int y_scale = face->size->metrics.y_scale;
+
+         for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
+              i < otf_gstring.used; i++, otfg++)
+           {
+             MGlyph *prev;
+             int adjust_idx = otfg->glyph_id ? j : j - 1;
+             int feature_idx = otfg->positioning_type >> 4;
+
+             if (feature_idx)
+               {
+                 tag = features[feature_idx - 1].FeatureTag;
+                 tag = PACK_OTF_TAG (tag);
+                 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+               }
+             switch (otfg->positioning_type & 0xF)
+               {
+               case 0:
+                 break;
+               case 1:                 /* Single */
+               case 2:                 /* Pair */
+                 {
+                   int format = otfg->f.f1.format;
+
+                   if (format & OTF_XPlacement)
+                     adjustment[adjust_idx].xoff
+                       += otfg->f.f1.value->XPlacement * x_scale / 0x10000;
+                   if (format & OTF_XPlaDevice)
+                     adjustment[adjust_idx].xoff
+                       += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
+                   if (format & OTF_YPlacement)
+                     adjustment[adjust_idx].yoff
+                       -= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
+                   if (format & OTF_YPlaDevice)
+                     adjustment[adjust_idx].yoff
+                       -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
+                   if (format & OTF_XAdvance)
+                     adjustment[adjust_idx].xadv
+                       += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
+                   if (format & OTF_XAdvDevice)
+                     adjustment[adjust_idx].xadv
+                       += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
+                   if (format & OTF_YAdvance)
+                     adjustment[adjust_idx].yadv
+                       += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
+                   if (format & OTF_YAdvDevice)
+                     adjustment[adjust_idx].yadv
+                       += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
+                   adjustment[adjust_idx].set = 1;
+                 }
+                 break;
+               case 3:         /* Cursive */
+                 /* Not yet supported.  */
+                 break;
+               case 4:         /* Mark-to-Base */
+               case 5:         /* Mark-to-Ligature */
+                 if (! base)
+                   break;
+                 prev = base;
+                 goto label_adjust_anchor;
+               default:                /* i.e. case 6 Mark-to-Mark */
+                 if (! mark)
+                   break;
+                 prev = mark;
+
+               label_adjust_anchor:
+                 {
+                   int base_x, base_y, mark_x, mark_y;
+                   int this_from, this_to;
+                   int k;
+
+                   base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
+                   base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
+                   mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
+                   mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
+
+                   if (otfg->f.f4.base_anchor->AnchorFormat != 1)
+                     adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
+                                    x_ppem, y_ppem, &base_x, &base_y);
+                   if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
+                     adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
+                                    x_ppem, y_ppem, &mark_x, &mark_y);
+                   adjustment[adjust_idx].xoff = base_x - mark_x;
+                   adjustment[adjust_idx].yoff = - (base_y - mark_y);
+                   adjustment[adjust_idx].back = (g - prev);
+                   adjustment[adjust_idx].xadv = 0;
+                   adjustment[adjust_idx].advance_is_absolute = 1;
+                   adjustment[adjust_idx].set = 1;
+                   this_from = g->g.from;
+                   this_to = g->g.to;
+                   for (k = 0; prev + k < g; k++)
+                     {
+                       if (this_from > prev[k].g.from)
+                         this_from = prev[k].g.from;
+                       if (this_to < prev[k].g.to)
+                         this_to = prev[k].g.to;
+                     }
+                   for (; prev <= g; prev++)
+                     {
+                       prev->g.from = this_from;
+                       prev->g.to = this_to;
+                     }
+                 }
+               }
+             if (otfg->glyph_id)
+               {
+                 if (otfg->GlyphClass == OTF_GlyphClass0)
+                   base = mark = g;
+                 else if (otfg->GlyphClass == OTF_GlyphClassMark)
+                   mark = g;
+                 else
+                   base = g;
+                 j++, g++;
+               }
+           }
+       }
+      else
+       {
+         for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
+              i++, otfg++)
+           if (otfg->positioning_type & 0xF)
+             {
+               int feature_idx = otfg->positioning_type >> 4;
+
+               if (feature_idx)
+                 {
+                   tag = features[feature_idx - 1].FeatureTag;
+                   tag = PACK_OTF_TAG (tag);
+                   for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
+                     {
+                       g = in_glyphs + (from + j);
+                       g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
+                     }
+                 }
+             }
+       }
+    }
+
+  free (otf_gstring.glyphs);
+  return to;
+
+ simple_copy:
+  if (otf_gstring.glyphs)
+    free (otf_gstring.glyphs);
+#endif /* HAVE_OTF */
+  if (out)
+    {
+      if (out->allocated < out->used + len)
+       return -2;
+      font->get_metrics (font, in, from, to);
+      memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
+             sizeof (MGlyph) * len);
+      out->used += len;
+    }
+  return to;
+}
+
+static int 
+ft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
+           MFLTGlyphString *in, int from, int to)
+{
+  return ft_drive_otf (font, spec, in, from, to, NULL, NULL);
+}
+
+
+#ifdef HAVE_OTF
+static unsigned char *iterate_bitmap;
+
+static int
+iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
+{
+  if (glyph_id <= otf->cmap->max_glyph_id)
+    iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
+  return 0;
+}
+
+static int
+ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
+                       int from, int to, unsigned char *table)
+{
+  OTF *otf = get_otf (font, NULL);
+  char id[13];
+  int bmp_size;
+  unsigned char *bitmap = NULL;
+  int i, j;
+  char script[5], *langsys = NULL;
+
+  if (! otf)
+    return -1;
+  if (OTF_get_table (otf, "cmap") < 0)
+    return -1;
+  if (! spec->features[0])
+    return -1;
+  strcpy (id, "feature-");
+  id[12] = '\0';
+  OTF_tag_name (spec->script, script);
+  if (spec->langsys)
+    {
+      langsys = alloca (5);
+      OTF_tag_name (spec->langsys, langsys);
+    }
+  bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
+  for (i = 0; spec->features[0][i]; i++)
+    {
+      unsigned char *bmp;
+
+      OTF_tag_name (spec->features[0][i], id + 8);
+      bmp = OTF_get_data (otf, id);
+      if (! bmp)
+       {
+         iterate_bitmap = bmp = calloc (bmp_size, 1);
+         OTF_iterate_gsub_feature (otf, iterate_callback,
+                                   script, langsys, id + 8);
+         OTF_put_data (otf, id, bmp, free);
+       }
+      if (i == 0 && ! spec->features[0][1])
+       /* Single feature */
+       bitmap = bmp;
+      else
+       {
+         if (! bitmap)
+           {
+             bitmap = alloca (bmp_size);
+             memcpy (bitmap, bmp, bmp_size);
+           }
+         else
+           {
+             int j;
+
+             for (j = 0; j < bmp_size; j++)
+               bitmap[j] &= bmp[j];
+           }
+       }
+    }
+  for (i = 0; i < bmp_size; i++)
+    if (bitmap[i])
+      {
+       for (j = 0; j < 8; j++)
+         if (bitmap[i] & (1 << j))
+           {
+             int c = OTF_get_unicode (otf, (i * 8) + j);
+
+             if (c >= from && c <= to)
+               table[c - from] = 1;
+           }
+      }
+  return 0;
+}
+#endif
+
+
+\f
+/* Internal API */
+
+MFontDriver mfont__ft_driver =
+  { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
+    ft_render, ft_list, ft_list_family_names, ft_check_capability,
+    ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf, ft_try_otf,
+#ifdef HAVE_OTF
+    ft_iterate_otf_feature
+#endif /* HAVE_OTF */
+  };
+
+int
+mfont__ft_init ()
+{
+  int i;
+
+  if (FT_Init_FreeType (&ft_library) != 0)
+    MERROR (MERROR_FONT_FT, -1);
+
+  for (i = 0; i < ft_to_prop_size; i++)
+    ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
+
+  Mmedium = msymbol ("medium");
+  Mr = msymbol ("r");
+  Mnull = msymbol ("");
+
+  M0[0] = msymbol ("0-0");
+  M0[1] = msymbol ("0-1");
+  M0[2] = msymbol ("0-2");
+  M0[3] = msymbol ("0-3");
+  M0[4] = msymbol ("0-4");
+  M3_1 = msymbol ("3-1");
+  M1_0 = msymbol ("1-0");
+
+#ifdef HAVE_FONTCONFIG
+  for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
+    {
+      FC_vs_M17N_font_prop *table = fc_all_table[i];
+      int j;
+
+      for (j = 0; table[j].m17n_value; j++)
+       table[j].sym = msymbol (table[j].m17n_value);
+      table[j].sym = table[j - 1].sym;
+    }
+
+  {
+    char *pathname;
+    struct stat buf;
+    MPlist *plist;
+    MSymbol serif, sans_serif, monospace;
+
+    fc_config = FcInitLoadConfigAndFonts ();
+    if (mfont_freetype_path)
+      {
+       MPLIST_DO (plist, mfont_freetype_path)
+         if (MPLIST_STRING_P (plist)
+             && (pathname = MPLIST_STRING (plist))
+             && stat (pathname, &buf) == 0)
+           {
+             FcStrList *strlist = FcConfigGetFontDirs (fc_config);
+             FcChar8 *dir;
 
              while ((dir = FcStrListNext (strlist)))
                if (strcmp ((char *) dir, pathname) == 0)
@@ -1876,7 +2730,7 @@ mfont__ft_init ()
     msymbol_put (monospace, Mgeneric_family, monospace);
     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
   }
-#endif
+#endif /* HAVE_FONTCONFIG */
 
   return 0;
 }
@@ -1886,6 +2740,12 @@ mfont__ft_fini ()
 {
   MPlist *plist, *p;
 
+  if (ft_default_list)
+    {
+      M17N_OBJECT_UNREF (ft_default_list);
+      ft_default_list = NULL;
+    }
+
   if (ft_font_list)
     {
       MPLIST_DO (plist, ft_font_list)
@@ -1899,12 +2759,14 @@ mfont__ft_fini ()
          M17N_OBJECT_UNREF (MPLIST_VAL (plist));
        }
       M17N_OBJECT_UNREF (ft_font_list);
+      ft_font_list = NULL;
 
       if (ft_language_list)
        {
          MPLIST_DO (plist, ft_language_list)
            M17N_OBJECT_UNREF (MPLIST_VAL (plist));
          M17N_OBJECT_UNREF (ft_language_list);
+         ft_language_list = NULL;
        }
 
       if (ft_script_list)
@@ -1912,6 +2774,7 @@ mfont__ft_fini ()
          MPLIST_DO (plist, ft_script_list)
            M17N_OBJECT_UNREF (MPLIST_VAL (plist));
          M17N_OBJECT_UNREF (ft_script_list);
+         ft_script_list = NULL;
        }
 
       if (ft_capability_list)
@@ -1919,6 +2782,7 @@ mfont__ft_fini ()
          MPLIST_DO (plist, ft_capability_list)
            M17N_OBJECT_UNREF (MPLIST_VAL (plist));
          M17N_OBJECT_UNREF (ft_capability_list);
+         ft_capability_list = NULL;
        }
 
       if (ft_file_list)
@@ -1926,8 +2790,8 @@ mfont__ft_fini ()
          MPLIST_DO (plist, ft_file_list)
            M17N_OBJECT_UNREF (MPLIST_VAL (plist));
          M17N_OBJECT_UNREF (ft_file_list);
+         ft_file_list = NULL;
        }
-
     }
   FT_Done_FreeType (ft_library);
 #ifdef HAVE_FONTCONFIG
@@ -1998,279 +2862,4 @@ mfont__ft_unparse_name (MFont *font)
 }
 #endif /* HAVE_FONTCONFIG */
 
-\f
-#ifdef HAVE_OTF
-
-#define DEVICE_DELTA(table, size)                              \
-  (((size) >= (table).StartSize && (size) <= (table).EndSize)  \
-   ? (table).DeltaValue[(size) >= (table).StartSize]           \
-   : 0)
-
-void
-adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
-              unsigned code, int size, int *x, int *y)
-{
-  if (anchor->AnchorFormat == 2)
-    {
-      FT_Outline *outline;
-      int ap = anchor->f.f1.AnchorPoint;
-
-      FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
-      outline = &ft_face->glyph->outline;
-      if (ap < outline->n_points)
-       {
-         *x = outline->points[ap].x;
-         *y = outline->points[ap].y;
-       }
-    }
-  else if (anchor->AnchorFormat == 3)
-    {
-      if (anchor->f.f2.XDeviceTable.offset)
-       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
-      if (anchor->f.f2.YDeviceTable.offset)
-      *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
-    }
-}
-
-int
-mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
-                    MFontCapability *cap)
-{
-  int len = to - from;
-  MGlyph *g = MGLYPH (from);
-  int i, gidx;
-  MRealizedFont *rfont;
-  MFontFT *ft_info;
-  OTF *otf;
-  OTF_GlyphString otf_gstring;
-  OTF_Glyph *otfg;
-  char *script, *langsys;
-  char *gsub_features, *gpos_features;
-  int need_cmap;
-
-  if (len == 0)
-    return from;
-
-  otf_gstring.glyphs = NULL;
-  rfont = g->rface->rfont;
-  ft_info = (MFontFT *) rfont->font;
-  if (ft_info->otf == invalid_otf)
-    goto simple_copy;
-  otf = ft_info->otf;
-  if (! otf)
-    {
-      otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
-      if (! otf)
-       {
-         ft_info->otf = invalid_otf;
-         goto simple_copy;
-       }
-      ft_info->otf = otf;
-    }
-  if (OTF_get_table (otf, "head") < 0)
-    {
-      OTF_close (otf);
-      ft_info->otf = invalid_otf;
-      goto simple_copy;
-    }
-
-  if (cap->script_tag)
-    {
-      script = alloca (5);
-      OTF_tag_name (cap->script_tag, script);
-    }
-  else
-    script = NULL;
-  if (cap->langsys_tag)
-    {
-      langsys = alloca (5);
-      OTF_tag_name (cap->langsys_tag, langsys);
-    }
-  else
-    langsys = NULL;
-  gsub_features = cap->features[MFONT_OTT_GSUB].str;
-  if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
-    gsub_features = NULL;
-  gpos_features = cap->features[MFONT_OTT_GPOS].str;
-  if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
-    gpos_features = NULL;
-
-  otf_gstring.size = otf_gstring.used = len;
-  otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
-  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
-  for (i = 0, need_cmap = 0; i < len; i++)
-    {
-      if (gstring->glyphs[from + i].otf_encoded)
-       {
-         otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
-         otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
-       }
-      else
-       {
-         otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
-         need_cmap++;
-       }
-    }
-  if (need_cmap
-      && OTF_drive_cmap (otf, &otf_gstring) < 0)
-    goto simple_copy;
-
-  OTF_drive_gdef (otf, &otf_gstring);
-  gidx = gstring->used;
-
-  if (gsub_features)
-    {
-      if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
-         < 0)
-       goto simple_copy;
-      for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
-       {
-         MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
-
-         temp.c = otfg->c;
-         temp.combining_code = 0;
-         if (otfg->glyph_id)
-           {
-             temp.code = otfg->glyph_id;
-             temp.otf_encoded = 1;
-           }
-         else
-           {
-             temp.code = temp.c;
-             temp.otf_encoded = 0;
-           }
-         temp.to = MGLYPH (from + otfg->f.index.to)->to;
-         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
-       }
-    }
-  else
-    for (i = 0; i < len; i++)
-      {
-       MGlyph temp = gstring->glyphs[from + i];
-
-       if (otf_gstring.glyphs[i].glyph_id)
-         {
-           temp.code = otf_gstring.glyphs[i].glyph_id;
-           temp.otf_encoded = 1;
-         }
-       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
-      }
-
-  (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
-
-  if (gpos_features)
-    {
-      int u;
-      int size10, size;
-      MGlyph *base = NULL, *mark = NULL;
-
-      if (OTF_check_features (otf, 1,
-                             cap->script_tag, cap->langsys_tag,
-                             cap->features[MFONT_OTT_GPOS].tags,
-                             cap->features[MFONT_OTT_GPOS].nfeatures) != 1
-         || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
-                             gpos_features) < 0))
-       return to;
-
-      u = otf->head->unitsPerEm;
-      size10 = rfont->spec.size;
-      size = size10 / 10;
-
-      for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
-          i < otf_gstring.used; i++, otfg++, g++)
-       {
-         MGlyph *prev;
-
-         if (! otfg->glyph_id)
-           continue;
-         switch (otfg->positioning_type)
-           {
-           case 0:
-             break;
-           case 1: case 2:
-             {
-               int format = otfg->f.f1.format;
-
-               if (format & OTF_XPlacement)
-                 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
-               if (format & OTF_XPlaDevice)
-                 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
-               if (format & OTF_YPlacement)
-                 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
-               if (format & OTF_YPlaDevice)
-                 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
-               if (format & OTF_XAdvance)
-                 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
-               if (format & OTF_XAdvDevice)
-                 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
-             }
-             break;
-           case 3:
-             /* Not yet supported.  */
-             break;
-           case 4: case 5:
-             if (! base)
-               break;
-             prev = base;
-             goto label_adjust_anchor;
-           default:            /* i.e. case 6 */
-             if (! mark)
-               break;
-             prev = mark;
-
-           label_adjust_anchor:
-             {
-               int base_x, base_y, mark_x, mark_y;
-
-               base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
-               base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
-               mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
-               mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
-
-               if (otfg->f.f4.base_anchor->AnchorFormat != 1)
-                 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
-                                prev->code, size, &base_x, &base_y);
-               if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
-                 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
-                                g->code, size, &mark_x, &mark_y);
-               g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
-               g->yoff = prev->yoff + mark_y - base_y;
-               g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
-             }
-           }
-         if (otfg->GlyphClass == OTF_GlyphClass0)
-           base = mark = g;
-         else if (otfg->GlyphClass == OTF_GlyphClassMark)
-           mark = g;
-         else
-           base = g;
-       }
-    }
-  free (otf_gstring.glyphs);
-  return to;
-
- simple_copy:
-  ft_find_metric (rfont, gstring, from, to);
-  for (i = 0; i < len; i++)
-    {
-      MGlyph temp = gstring->glyphs[from + i];
-      MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
-    }
-  if (otf_gstring.glyphs)
-    free (otf_gstring.glyphs);
-  return to;
-}
-
-
-int
-mfont__ft_decode_otf (MGlyph *g)
-{
-  MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
-  int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
-
-  return (c ? c : -1);
-}
-
-#endif /* HAVE_OTF */
-
 #endif /* HAVE_FREETYPE */