*** empty log message ***
[m17n/m17n-lib.git] / src / font.c
index 4cecfbd..5ebdaa0 100644 (file)
@@ -1,5 +1,5 @@
 /* font.c -- font 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.  */
 
 /***en
     key of a font property must be one of the following symbols:
 
     @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
-    @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype.
+    @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mspacing.
 
     When the key of a font property is @c Msize or @c Mresolution, its
     value is an integer.  Otherwise the value is a symbol.  
 
-    "The font property that belongs to font F and whose key is @c
-    Mxxx" may be shortened to "the xxx property of F".
+    The notation "xxx property of F" means the font property that
+    belongs to font F and whose key is @c Mxxx.
 
     The value of a foundry property is a symbol representing font
     foundry information, e.g. adobe, misc, etc.
@@ -94,7 +94,7 @@
     SLANT                                       style
     SETWIDTH_NAME                               stretch
     ADD_STYLE_NAME                              adstyle
-    POINT_SIZE                                  size
+    PIXEL_SIZE                                  size
     RESOLUTION_Y                                resolution
     CHARSET_REGISTRY-CHARSET_ENCODING           registry
 @endverbatim
     ¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
 
     @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
-    @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype
+    @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mspacing
 
     ¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤¬ @c Msize ¤¢¤ë¤¤¤Ï @c Mresolution 
     ¤Î¾ì¹ç¡¢ÃͤÏÀ°¿ôÃͤǤ¢¤ê¡¢¥­¡¼¤¬¤½¤ì°Ê³°¤Î¾ì¹ç¡¢Ãͤϥ·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
     SLANT                                       style
     SETWIDTH_NAME                               stretch
     ADD_STYLE_NAME                              adstyle
-    POINT_SIZE                                  size
+    PIXEL_SIZE                                  size
     RESOLUTION_Y                                resolution
     CHARSET_REGISTRY-CHARSET_ENCODING           registry
 @endverbatim
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "m17n-gui.h"
 #include "m17n-misc.h"
 #include "symbol.h"
 #include "plist.h"
 #include "charset.h"
+#include "language.h"
 #include "internal-gui.h"
 #include "font.h"
 #include "face.h"
@@ -663,55 +665,17 @@ OTF_tag (char *name)
                          | (! p[2] ? 0
                             : (p[2] << 8) | p[3]))));
 }
-#endif /* not HAVE_OTF */
 
-static MPlist *otf_script_list;
-
-static int
-load_otf_script_list ()
-{
-  MDatabase *mdb;
-  MPlist *plist, *pl;
-
-  otf_script_list = mplist ();
-  mdb = mdatabase_find (msymbol ("standard"), Mscript, msymbol ("otf"), Mnil);
-  if (! mdb
-      || ! (plist = mdatabase_load (mdb)))
-    MERROR (MERROR_FONT, -1);
-  MPLIST_DO (pl, plist)
-    {
-      MPlist *p;
-      MSymbol script, otf_script;
-      OTF_Tag tag;
-
-      if (! MPLIST_PLIST_P (pl))
-       continue;
-      p = MPLIST_PLIST (pl);
-      if (! MPLIST_SYMBOL_P (p))
-       continue;
-      script = MPLIST_SYMBOL (p);
-      p = MPLIST_NEXT (p);
-      if (! MPLIST_SYMBOL_P (p))
-       continue;
-      otf_script = MPLIST_SYMBOL (p);
-      tag = OTF_tag (MSYMBOL_NAME (otf_script));
-      mplist_push (otf_script_list, script, (void *) tag);
-    }
-  M17N_OBJECT_UNREF (plist);
-  return 0;
-}
-
-static MSymbol
-find_script_from_otf_tag (OTF_Tag tag)
+void
+OTF_tag_name (OTF_Tag tag, char *name)
 {
-  MPlist *plist;
-
-  if (! otf_script_list)
-    load_otf_script_list ();
-  plist = mplist_find_by_value (otf_script_list, (void *) tag);
-  return (plist ? MPLIST_KEY (plist) : Mnil);
+  name[0] = (char) (tag >> 24);
+  name[1] = (char) ((tag >> 16) & 0xFF);
+  name[2] = (char) ((tag >> 8) & 0xFF);
+  name[3] = (char) (tag & 0xFF);
+  name[4] = '\0';
 }
-
+#endif /* not HAVE_OTF */
 
 /* XLFD parser/generator */
 
@@ -737,15 +701,15 @@ enum xlfd_field_idx
   };
 
 static int
-xlfd_parse_name (char *name, MFont *font)
+xlfd_parse_name (const char *name, MFont *font)
 {
   char *field[XLFD_FIELD_MAX];
   unsigned short resy, avgwidth;
   unsigned size;
-  MSymbol attrs[MFONT_PROPERTY_MAX];
   char copy[513];
   int i;
   char *p;
+  MSymbol sym;
 
   if (name[0] != '-')
     return -1;
@@ -794,34 +758,53 @@ xlfd_parse_name (char *name, MFont *font)
   else
     size = atoi (field[XLFD_PIXEL]) * 10;
 
-  attrs[MFONT_FOUNDRY]
-    = field[XLFD_FOUNDRY] ? msymbol (field[XLFD_FOUNDRY]) : Mnil;
-  attrs[MFONT_FAMILY]
-    = field[XLFD_FAMILY] ? msymbol (field[XLFD_FAMILY]) : Mnil;
-  attrs[MFONT_WEIGHT]
-    = field[XLFD_WEIGHT] ? msymbol (field[XLFD_WEIGHT]) : Mnil;
-  attrs[MFONT_STYLE]
-    = field[XLFD_SLANT] ? msymbol (field[XLFD_SLANT]) : Mnil;
-  attrs[MFONT_STRETCH]
-    = field[XLFD_SWIDTH] ? msymbol (field[XLFD_SWIDTH]) : Mnil;
-  attrs[MFONT_ADSTYLE]
-    = field[XLFD_ADSTYLE] ? msymbol (field[XLFD_ADSTYLE]) : Mnil;
-  attrs[MFONT_REGISTRY]
-    = field[XLFD_REGISTRY] ? msymbol (field[XLFD_REGISTRY]) : Mnil;
-  mfont__set_spec (font, attrs, size, resy);
+  if (field[XLFD_FOUNDRY])
+    {
+      sym = msymbol (field[XLFD_FOUNDRY]);
+      if (! sym)
+       sym = msymbol ("Nil");
+      mfont__set_property (font, MFONT_FOUNDRY, sym);
+    }
+  if (field[XLFD_FAMILY])
+    {
+      sym = msymbol (field[XLFD_FAMILY]);
+      if (! sym)
+       sym = msymbol ("Nil");
+      mfont__set_property (font, MFONT_FAMILY, sym);
+    }
+  if (field[XLFD_WEIGHT])
+    mfont__set_property (font, MFONT_WEIGHT, msymbol (field[XLFD_WEIGHT]));
+  if (field[XLFD_SLANT])
+    mfont__set_property (font, MFONT_STYLE, msymbol (field[XLFD_SLANT]));
+  if (field[XLFD_SWIDTH])
+    mfont__set_property (font, MFONT_STRETCH, msymbol (field[XLFD_SWIDTH]));
+  if (field[XLFD_ADSTYLE])
+    mfont__set_property (font, MFONT_ADSTYLE, msymbol (field[XLFD_ADSTYLE]));
+  font->property[MFONT_RESY] = resy;
+  font->size = size;
+  if (field[XLFD_SPACING])
+    font->spacing
+      = ((field[XLFD_SPACING][0] == 'p' || field[XLFD_SPACING][0] == 'P')
+        ? MFONT_SPACING_PROPORTIONAL
+        : (field[XLFD_SPACING][0] == 'm' || field[XLFD_SPACING][0] == 'M')
+        ? MFONT_SPACING_MONO : MFONT_SPACING_CHARCELL);
+  if (field[XLFD_REGISTRY])
+    mfont__set_property (font, MFONT_REGISTRY, msymbol (field[XLFD_REGISTRY]));
   font->type = MFONT_TYPE_SPEC;
   font->source = MFONT_SOURCE_X;
   return 0;
 }
 
 static char *
-xlfd_unparse_name (MFont *font)
+xlfd_unparse_name (MFont *font, int full_xlfd)
 {
   MSymbol prop[7];
   char name[513];
   char *str[7];
   int len, i;
-  unsigned short size, resy;
+  char spacing;
+  int size, resy;
+  int all_nil = 1;
 
   prop[0] = (MSymbol) mfont_get_prop (font, Mfoundry);
   prop[1] = (MSymbol) mfont_get_prop (font, Mfamily);
@@ -836,6 +819,7 @@ xlfd_unparse_name (MFont *font)
        {
          str[i] = msymbol_name (prop[i]);
          len += strlen (str[i]);
+         all_nil = 0;
        }
       else
        {
@@ -843,24 +827,71 @@ xlfd_unparse_name (MFont *font)
          len++;
        }
     }
+  spacing = (font->spacing == MFONT_SPACING_UNDECIDED ? '*'
+            : font->spacing == MFONT_SPACING_PROPORTIONAL ? 'p'
+            : font->spacing == MFONT_SPACING_MONO ? 'm'
+            : 'c');
+
   if ((len
-       + 12                    /* 12 dashes */
-       + 3                     /* 3 asterisks */
+       + 13                    /* 13 dashes */
+       + 2                     /* 2 asterisks */
        + 30                    /* 3 integers (each 10 digits) */
+       + 1                     /* 1 spacing char */
        + 1)                    /* '\0' terminal */
       > 513)
     return NULL;
 
   resy = (int) mfont_get_prop (font, Mresolution);
   size = font->size;
-  if ((size % 10) < 5)
-    size /= 10;
+  if (size >= 0)
+    {
+      if (font->multiple_sizes)
+       {
+         for (size = 0; size < 24; size++)
+           if (font->size & (1 << size))
+             break;
+         size += 6;
+       }
+      else if ((size % 10) < 5)
+       size /= 10;
+      else
+       size = size / 10 + 1;
+    }
+  else
+    size = - size;
+
+  if (full_xlfd)
+    {
+      if (font->size >= 0)
+       sprintf (name, "-%s-%s-%s-%s-%s-%s-%d-*-%d-%d-%c-*-%s",
+                str[0], str[1], str[2], str[3], str[4], str[5],
+                size, resy, resy, spacing, str[6]);
+      else
+       sprintf (name, "-%s-%s-%s-%s-%s-%s-*-%d-%d-%d-%c-*-%s",
+                str[0], str[1], str[2], str[3], str[4], str[5],
+                size, resy, resy, spacing, str[6]);
+    }
+  else if (all_nil && size == 0)
+    sprintf (name, "*");
   else
-    size = size / 10 + 1;
+    {
+      char *p = name;
+
+      p += sprintf (p, "-%s", str[0]);
+      for (i = 1; i < 6; i++)
+       if (p[-1] != '*' || str[i][0] != '*')
+         p += sprintf (p, "-%s", str[i]);
+      if (p[-1] != '*' || font->size > 0)
+       {
+         if (font->size > 0)
+           p += sprintf (p, "-%d-*", size);
+         else
+           p += sprintf (p, "-*");
+       }
+      if (str[6][0] != '*')
+       sprintf (p, "-%s", str[6]);
+    }
 
-  sprintf (name, "-%s-%s-%s-%s-%s-%s-%d-*-%d-%d-*-*-%s",
-          str[0], str[1], str[2], str[3], str[4], str[5],
-          size, resy, resy,  str[6]);
   return strdup (name);
 }
 
@@ -881,7 +912,21 @@ font_score (MFont *font, MFont *request)
        {
          if (font->size && request->size)
            {
-             val = font->size - request->size;
+             if (font->multiple_sizes)
+               {
+                 int j, closest = 23;
+
+                 for (j = 23; j >= 0; j--)
+                   if (font->size & (1 << j))
+                     {
+                       closest = j;
+                       if (request->size >= (j + 6) * 10)
+                         break;
+                     }
+                 val = request->size - (closest + 6) * 10;
+               }
+             else
+               val = font->size - request->size;
              if (val)
                {
                  if (val < 0)
@@ -924,6 +969,82 @@ font_score (MFont *font, MFont *request)
   return score;
 }
 
+static MSymbol
+merge_capability (MSymbol capability, MSymbol key, MSymbol val, int overwrite)
+{
+  MFontCapability *cap = NULL;
+  char *lang = NULL, *script = NULL, *otf = NULL, *buf, *p;
+  int lang_len = 0, script_len = 0, otf_len = 0;
+
+  if (key == Mlanguage)
+    lang = MSYMBOL_NAME (val), lang_len = MSYMBOL_NAMELEN (val) + 6;
+  else if (key == Mscript)
+    script = MSYMBOL_NAME (val), script_len = MSYMBOL_NAMELEN (val) + 7;
+  else if (key == Motf)
+    otf = MSYMBOL_NAME (val), otf_len = MSYMBOL_NAMELEN (val) + 5;
+  else
+    return capability;
+
+  if (capability != Mnil)
+    {
+      cap = mfont__get_capability (capability);
+      if (! overwrite)
+       {
+         if (cap->language)
+           lang = NULL;
+         if (cap->script)
+           script = NULL;
+         if (cap->script_tag)
+           otf = NULL;
+         if (! lang && !script && !otf)
+           return capability;
+       }
+    }
+
+  if (! lang && cap && cap->language)
+    {
+      lang_len = MSYMBOL_NAMELEN (cap->language);
+      lang = MSYMBOL_NAME (cap->language);
+    }
+  if (! script && cap && cap->script != Mnil)
+    {
+      script_len = MSYMBOL_NAMELEN (cap->script);
+      script = MSYMBOL_NAME (cap->script);
+    }
+  if (! otf && cap && cap->script_tag)
+    {
+      int i;
+
+      otf_len = 4;                     /* for script_tag */
+      if (cap->langsys_tag)
+       otf_len += 5;           /* for "/XXXX */
+      for (i = 0; i < MFONT_OTT_MAX; i++)
+       if (cap->features[i].str)
+         otf_len += strlen (cap->features[i].str) + 1; /* for "[=+]..." */
+      otf = p = alloca (otf_len + 1);
+      OTF_tag_name (cap->script_tag, otf);
+      p += 4;
+      if (cap->langsys_tag)
+       {
+         *p++ = '/';
+         OTF_tag_name (cap->langsys_tag, p);
+         p += 4;
+       }
+      if (cap->features[MFONT_OTT_GSUB].str)
+       p += sprintf (p, "=%s", cap->features[MFONT_OTT_GSUB].str);
+      if (cap->features[MFONT_OTT_GPOS].str)
+       p += sprintf (p, "=%s", cap->features[MFONT_OTT_GSUB].str);
+    }
+  buf = p = alloca (lang_len + script_len + otf_len + 1);
+  if (lang_len)
+    p += sprintf (p, ":lang=%s", lang);
+  if (script_len)
+    p += sprintf (p, ":script=%s", script);
+  if (otf_len)
+    p += sprintf (p, ":otf=%s", otf);
+  return msymbol (buf);
+}
+
 \f
 /* Internal API */
 
@@ -956,8 +1077,10 @@ mfont__init ()
   Mregistry = msymbol ("registry");
   mfont__property_table[MFONT_REGISTRY].property = Mregistry;
 
+  Mspacing = msymbol ("spacing");
   Msize = msymbol ("size");
   Mresolution = msymbol ("resolution");
+  Mmax_advance = msymbol ("max-advance");
   Mfontfile = msymbol ("fontfile");
 
   Mfontconfig = msymbol ("fontconfig");
@@ -972,6 +1095,8 @@ mfont__init ()
   Municode_full = msymbol ("unicode-full");
   Mapple_roman = msymbol ("apple-roman");
 
+  Motf = msymbol ("otf");
+
   /* The first entry of each mfont__property_table must be Mnil so
      that actual properties get positive numeric numbers.  */
   for (i = 0; i <= MFONT_REGISTRY; i++)
@@ -1029,7 +1154,7 @@ mfont__init ()
   default_encoding.repertory_name = Mnil;
   default_encoding.repertory_charset = NULL;
   {
-    char *path, *buf;
+    char *path, *buf = NULL;
     int bufsize;
     USE_SAFE_ALLOCA;
 
@@ -1053,8 +1178,6 @@ mfont__init ()
   if (mfont__ft_init () < 0)
     return -1;
 #endif /* HAVE_FREETYPE */
-  if (mfont__flt_init () < 0)
-    return -1;
 
   return 0;
 }
@@ -1065,7 +1188,6 @@ mfont__fini ()
   MPlist *plist;
   int i;
 
-  mfont__flt_fini ();
 #ifdef HAVE_FREETYPE
   mfont__ft_fini ();
 #endif /* HAVE_FREETYPE */
@@ -1088,11 +1210,6 @@ mfont__fini ()
       M17N_OBJECT_UNREF (font_encoding_list);
       font_encoding_list = NULL;
     }
-  if (otf_script_list)
-    {
-      M17N_OBJECT_UNREF (otf_script_list);
-      otf_script_list = NULL;
-    }
 
   for (i = 0; i <= MFONT_REGISTRY; i++)
     MLIST_FREE1 (&mfont__property_table[i], names);
@@ -1102,12 +1219,12 @@ mfont__fini ()
 MSymbol
 mfont__id (MFont *font)
 {
-  char *buf, *p;
+  char *buf = NULL, *p;
   int i;
   int file_len = (font->file == Mnil ? 0 : MSYMBOL_NAMELEN (font->file));
   int capability_len  = (font->capability == Mnil ? 0
                         : MSYMBOL_NAMELEN (font->capability));
-  int total_len = MFONT_PROPERTY_MAX * 5 + 7 + file_len + capability_len;
+  int total_len = MFONT_PROPERTY_MAX * 5 + 9 + file_len + capability_len;
   MSymbol id;
   USE_SAFE_ALLOCA;
 
@@ -1124,6 +1241,8 @@ mfont__id (MFont *font)
     }
   if (font->size)
     p += sprintf (p, "-%X", font->size);
+  if (font->spacing)
+    p += sprintf (p, "-%X", font->spacing);
   if (capability_len > 0)
     {
       *p++ = '-';
@@ -1147,8 +1266,17 @@ int
 mfont__match_p (MFont *font, MFont *spec, int prop)
 {
   if (spec->capability != font->capability
-      && spec->capability != Mnil && font->capability != Mnil)
-    return 0;
+      && spec->capability != Mnil)
+    {
+      MRealizedFont *rfont;
+
+      if (font->type != MFONT_TYPE_REALIZED)
+       return (font->capability == Mnil);
+      rfont = (MRealizedFont *) font;
+      return (rfont->driver->check_capability
+             && (rfont->driver->check_capability (rfont, spec->capability)
+                 >= 0));
+    }
   if (spec->file != font->file
       && spec->file != Mnil && font->file != Mnil)
     return 0;
@@ -1176,6 +1304,12 @@ mfont__merge (MFont *dst, MFont *src, int error_on_conflict)
               && dst->property[i] != src->property[i])
        return -1;
     }
+  if (! dst->spacing)
+    dst->spacing = src->spacing;
+  else if (error_on_conflict
+          && src->spacing
+          && dst->spacing != src->spacing)
+    return -1;
   if (! dst->size)
     dst->size = src->size;
   else if (error_on_conflict
@@ -1206,6 +1340,7 @@ mfont__set_spec_from_face (MFont *spec, MFace *face)
     mfont__set_property (spec, i, face->property[i]);
   spec->property[MFONT_REGISTRY] = 0;
   spec->property[MFONT_RESY] = 0;
+  spec->multiple_sizes = 0;
   spec->size = (int) (face->property[MFACE_SIZE]);
   spec->type = MFONT_TYPE_SPEC;
   spec->source = MFONT_SOURCE_UNDECIDED;
@@ -1297,7 +1432,11 @@ mfont__available (MFrame *frame, MFont *font)
 static int
 compare_font_score (const void *e1, const void *e2)
 {
-  return (((MFontScore *) e1)->score > ((MFontScore *) e2)->score);
+  MFontScore *s1 = (MFontScore *) e1, *s2 = (MFontScore *) e2;
+
+  return (s1->font->for_full_width == s2->font->for_full_width
+         ? s1->score > s2->score
+         : s1->font->for_full_width);
 }
 
 void
@@ -1364,15 +1503,29 @@ mfont__list (MFrame *frame, MFont *spec, MFont *request, int max_size)
   MTABLE_MALLOC (list->fonts, num, MERROR_FONT);
   for (i = 0; num > 0; num--, pl = MPLIST_NEXT (pl))
     {
-      MFont *font = MPLIST_VAL (pl);
+      MFont *font = MPLIST_VAL (pl), *adjusted = font;
 
       if (max_size == 0
          || font->size == 0
          || font->size < max_size)
        {
          list->fonts[i].font = font;
-         list->fonts[i].score
-           = spec == request ? 0 : font_score (font, request);
+         if (spec == request)
+           list->fonts[i].score = 0;
+         else
+           {
+             int resize_ratio;
+             MFont resized;
+
+             if (font->size > 0
+                 && (resize_ratio = mfont_resize_ratio (font)) != 100)
+               {
+                 resized = *font;
+                 resized.size = font->size * 100 / resize_ratio;
+                 adjusted = &resized;
+               }
+             list->fonts[i].score = font_score (adjusted, request);
+           }
          i++;
        }
     }
@@ -1422,37 +1575,6 @@ mfont__open (MFrame *frame, MFont *font, MFont *spec)
   return (driver->open) (frame, font, spec, rfont);
 }
 
-void
-mfont__resize (MFont *spec, MFont *request)
-{
-  MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
-  MFontResize *resize;
-  MPlist *plist;
-
-  if (! font_resize_list)
-    load_font_resize_table ();
-  if (! MPLIST_TAIL_P (font_resize_list))
-    while (1)
-      {
-       plist = font_resize_list;
-       while (registry ? (plist = mplist_find_by_key (plist, registry))
-              : plist)
-         {
-           resize = (MFontResize *) MPLIST_VAL (plist);
-           if (mfont__match_p (spec, &resize->spec, MFONT_ADSTYLE))
-             {
-               request->size = request->size * resize->resize / 100;
-               return;
-             }
-           plist = MPLIST_NEXT (plist);
-         }
-       if (registry == Mt)
-         break;
-       registry = Mt;
-      }
-}
-
-
 int
 mfont__has_char (MFrame *frame, MFont *font, MFont *spec, int c)
 {
@@ -1497,7 +1619,7 @@ mfont__encode_char (MFrame *frame, MFont *font, MFont *spec, int c)
   encoding = (font->encoding ? font->encoding : find_encoding (font));
   if (! encoding->encoding_charset)
     return MCHAR_INVALID_CODE;
-  if (encoding->repertory_charset)
+  if (font->source == MFONT_SOURCE_X && encoding->repertory_charset)
     return (ENCODE_CHAR (encoding->repertory_charset, c));
   code = ENCODE_CHAR (encoding->encoding_charset, c);
   if (code == MCHAR_INVALID_CODE)
@@ -1520,19 +1642,97 @@ mfont__get_metric (MGlyphString *gstring, int from, int to)
   MGlyph *from_g = MGLYPH (from), *to_g = MGLYPH (to), *g;
   MRealizedFont *rfont = from_g->rface->rfont;
 
-  for (g = from_g; g != to_g; g++)
-    if (g->rface->rfont != rfont)
+  for (g = from_g; ; g++)
+    if (g == to_g || g->rface->rfont != rfont)
       {
        int idx = GLYPH_INDEX (g);
 
        (rfont->driver->find_metric) (rfont, gstring, from, idx);
-       from_g = g;
+       while (from_g < g)
+         {
+           from_g->g.xadv >>= 6;
+           from_g->g.yadv >>= 6;
+           from_g->g.xoff >>= 6;
+           from_g->g.yoff >>= 6;
+           from_g->g.ascent >>= 6;
+           from_g->g.descent >>= 6;
+           from_g->g.lbearing >>= 6;
+           from_g->g.rbearing >>= 6;
+           from_g++;
+         }
+       if (g == to_g)
+         break;
        rfont = g->rface->rfont;
        from = idx;
       }
-  (rfont->driver->find_metric) (rfont, gstring, from, GLYPH_INDEX (g));
 }
 
+int
+mfont__get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
+                    int from, int to)
+{
+  MFont *mfont = (MFont *) ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MFontEncoding *encoding;
+  MFontDriver *driver = NULL;
+  MGlyph *glyphs = (MGlyph *) gstring->glyphs;
+  int result = 0;
+
+  encoding = mfont->encoding ? mfont->encoding : find_encoding (mfont);
+  for (; from < to; from++)
+    {
+      MGlyph *g = glyphs + from;
+
+      if (g->g.encoded)
+       continue;
+      if (mfont->source == MFONT_SOURCE_X && encoding->repertory_charset)
+       g->g.code = ENCODE_CHAR (encoding->repertory_charset, g->g.c);
+      else
+       {
+         unsigned code;
+
+         if (encoding->encoding_charset)
+           code = ENCODE_CHAR (encoding->encoding_charset, g->g.c);
+         else
+           code = g->g.code;
+
+         if (code != MCHAR_INVALID_CODE)
+           {
+             if (! driver)
+               {
+                 if (mfont->type == MFONT_TYPE_REALIZED)
+                   driver = rfont->driver;
+                 else
+                   {
+                     driver = mplist_get (rfont->frame->font_driver_list,
+                                          mfont->source == MFONT_SOURCE_X
+                                          ? Mx : Mfreetype);
+                     if (! driver)
+                       MFATAL (MERROR_FONT);
+                   }
+               }
+             g->g.code = (driver->encode_char) (rfont->frame, rfont->font,
+                                                mfont, code);
+           }
+       }
+      g->g.encoded = 1;
+      if (g->g.code == MCHAR_INVALID_CODE)
+       result = -1;
+    }
+  return result;
+}
+
+int
+mfont__get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
+                   int from, int to)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MGlyphString gstr;
+
+  gstr.glyphs = (MGlyph *) gstring->glyphs;
+  (rfont->driver->find_metric) (rfont, &gstr, from, to);
+  return 0;
+}
 
 /* KEY <= MFONT_REGISTRY */
 
@@ -1556,27 +1756,15 @@ mfont__set_property (MFont *font, enum MFontProperty key, MSymbol val)
   font->property[key] = numeric;
 }
 
-void
-mfont__set_spec (MFont *font, MSymbol *attrs,
-                unsigned size, unsigned short resy)
-{
-  int i;
-
-  for (i = 0; i <= MFONT_REGISTRY; i++)
-    mfont__set_property (font, i, attrs[i]);
-  font->property[MFONT_RESY] = resy;
-  font->size = size;
-}
-
 int
-mfont__parse_name_into_font (char *name, MSymbol format, MFont *font)
+mfont__parse_name_into_font (const char *name, MSymbol format, MFont *font)
 {
   int result = -1;
 
   if (format == Mx || format == Mnil)
     result = xlfd_parse_name (name, font);
 #ifdef HAVE_FONTCONFIG
-  if (format == Mfontconfig || (! result && format == Mnil))
+  if (format == Mfontconfig || (result < 0 && format == Mnil))
     result = mfont__ft_parse_name (name, font);
 #endif /* HAVE_FONTCONFIG */
   return result;
@@ -1594,20 +1782,18 @@ static void
 free_font_capability (void *object)
 {
   MFontCapability *cap = object;
-  int i;
   
-  if (cap->lang)
-    free (cap->lang);
-#ifdef HAVE_OTF
-  if (cap->script)
-    for (i = 0; i < MFONT_OTT_MAX; i++)
-      {
-       if (cap->features[i].str)
-         free (cap->features[i].str);
-       if (cap->features[i].tags)
-         free (cap->features[i].tags);
-      }
-#endif /* HAVE_OTF */
+  if (cap->script_tag)
+    {
+      int i;
+      for (i = 0; i < MFONT_OTT_MAX; i++)
+       {
+         if (cap->features[i].str)
+           free (cap->features[i].str);
+         if (cap->features[i].tags)
+           free (cap->features[i].tags);
+       }
+    }
   free (cap);
 }
 
@@ -1616,7 +1802,6 @@ mfont__get_capability (MSymbol sym)
 {
   MFontCapability *cap = msymbol_get (sym, M_font_capability);
   char *str, *p, *endp;
-  int i;
 
   if (cap)
     return cap;
@@ -1631,21 +1816,29 @@ mfont__get_capability (MSymbol sym)
     {
       if (*str++ != ':')
        continue;
-#ifdef HAVE_OTF
-      if (str[0] == 'o' && str[1] == 't' && str[2] == 'f' && str[3] == '=')
+      if (str[0] == 'o' && strncmp (str + 1, "tf=", 3) == 0)
        {
+         char *beg;
+         MSymbol sym;
+         int i;
+
          str += 4;
+         beg = str;
          for (i = 0, p = str; i < 4 && p < endp; i++, p++);
          if (i < 4)
            break;
+         sym = msymbol__with_len (str, 4);
+         cap->script = mscript__from_otf_tag (sym);
+         if (cap->script == Mnil)
+           break;
          cap->script_tag = OTF_tag (str);
-         cap->script = find_script_from_otf_tag (cap->script_tag);
          if (*p == '/')
            {
              for (i = 0, str = ++p; i < 4 && p < endp; i++, p++);
              if (i < 4)
                {
                  cap->script = Mnil;
+                 cap->script_tag = 0;
                  break;
                }
              cap->langsys_tag = OTF_tag (str);
@@ -1710,40 +1903,18 @@ mfont__get_capability (MSymbol sym)
                cap->features[i].tags = malloc (sizeof (OTF_Tag));
                cap->features[i].tags[0] = 0;
              }
+         cap->otf = msymbol__with_len (beg, p - beg);
          str = p;
-         continue;
        }
-#endif /* HAVE_OTF */
-      if (str[0] == 'l' && str[1] == 'a' && str[2] == 'n' && str[3] == 'g'
-         && str[4] == '=')
+      else if (str[0] == 'l' && strncmp (str + 1, "ang=", 4) == 0)
        {
-         int count;
-
          str += 5;
-         for (p = str, count = 2; p < endp && *p != ':'; p++)
-           if (*p == ',')
-             count++;
-         MTABLE_MALLOC (cap->lang, count, MERROR_FONT);
-         for (p = str, count = 0; p < endp && *p != ':'; p++)
-           if (*p == ',')
-             {
-               MSymbol lang = msymbol__with_len (str, p - str), sym;
-
-               if (msymbol_get (lang, Miso639_2))
-                 cap->lang[count++] = lang;
-               else if ((sym = msymbol_get (lang, Miso639_1)) != Mnil)
-                 cap->lang[count++] = sym;
-               else if (msymbol_get (lang, Mlanguage))
-                 cap->lang[count++] = lang;
-               str = p + 1;
-             }
+         for (p = str; p < endp && *p != ':'; p++);
          if (str < p)
-           cap->lang[count++] = msymbol__with_len (str, p - str);
-         cap->lang[count] = Mnil;
+           cap->language = msymbol__with_len (str, p - str);
          str = p;
        }
-      else if (str[0] == 's' && str[1] == 'c' && str[2] == 'r' && str[3] == 'i'
-              && str[4] == 'p' && str[5] == 't' && str[6] == '=')
+      else if (str[0] == 's' && strncmp (str + 1, "cript=", 6) == 0)
        {
          str += 7;
          for (p = str; p < endp && *p != ':'; p++);
@@ -1755,6 +1926,13 @@ mfont__get_capability (MSymbol sym)
   return cap;
 }
 
+int
+mfont__check_capability (MRealizedFont *rfont, MSymbol capability)
+{
+  return (rfont->driver->check_capability (rfont, capability));
+}
+
+
 /*** @} */
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
@@ -1780,7 +1958,7 @@ mfont__get_capability (MSymbol sym)
 /***ja
     @brief ³«È¯¸µ¤ò»ØÄꤹ¤ë¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼.
     
-    ÊÑ¿ô #Mfoundry ¤Ï <tt>"fonudry"</tt> 
+    ÊÑ¿ô #Mfoundry ¤Ï <tt>"foundry"</tt> 
     ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤È¥Õ¥§¡¼¥¹¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£
     Ãͤϡ¢¥Õ¥©¥ó¥È¤Î³«È¯¸µÌ¾¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£    */
 
@@ -1866,6 +2044,22 @@ MSymbol Mstretch;
 MSymbol Madstyle;
 
 /***en
+    @brief Key of font property specifying spacing.
+
+    The variable #Madstyle is a symbol of name <tt>"spacing"</tt> and
+    is used as a key of font property.  The property value must be a
+    symbol whose name specifies the spacing of a font (e.g "p" for
+    proportional, "m" for monospaced).  */ 
+/***ja
+    @brief spacing ¤ò»ØÄꤹ¤ë¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼.
+    
+    ÊÑ¿ô #Mspacing ¤Ï <tt>"spacing"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢
+    ¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£Ãͤϡ¢¥Õ¥©¥ó¥È¤Î spacing
+    ÆÃÀ­¤ò¼¨¤¹Ì¾Á° ("p", "m" Åù)¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£  */
+
+MSymbol Mspacing;
+
+/***en
     @brief Key of font property specifying registry.
 
     The variable #Mregistry is a symbol of name <tt>"registry"</tt>
@@ -1906,6 +2100,14 @@ MSymbol Msize;
     The variable #Mfontfile is a symbol of name <tt>"fontfile"</tt>
     and is used as a key of font property.  The property value must be
     a symbol whose name is a font file name.  */ 
+MSymbol Motf;
+
+/***en
+    @brief Key of font property specifying file name.
+
+    The variable #Mfontfile is a symbol of name <tt>"fontfile"</tt>
+    and is used as a key of font property.  The property value must be
+    a symbol whose name is a font file name.  */ 
 /***ja
     @brief ¥Õ¥©¥ó¥È¥Õ¥¡¥¤¥ë¤ò»ØÄꤹ¤ë¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼.
     
@@ -1932,6 +2134,17 @@ MSymbol Mfontfile;
 MSymbol Mresolution;
 
 /***en
+    @brief Key of font property specifying max advance width.
+
+    The variable #Mmax_advance is a symbol of name
+    <tt>"max-advance"</tt> and is used as a key of font property.  The
+    property value must be an integer specifying a font's max advance
+    value by pixels.  */ 
+
+MSymbol Mmax_advance;
+
+
+/***en
     @brief Symbol of name "fontconfig".
 
     The variable #Mfontconfig is to be used as an argument of the
@@ -1947,42 +2160,42 @@ MSymbol Mfontconfig;
 /***en
     @brief Symbol of name "x".
 
-    The variable #Mx is to be used for a value of <type> member of the
-    structure #MDrawGlyph to specify the type of <fontp> member is
+    The variable #Mx is to be used for a value of \<type\> member of the
+    structure #MDrawGlyph to specify the type of \<fontp\> member is
     actually (XFontStruct *).  */
 /***ja
     @brief "x" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë.
 
-    ÊÑ¿ô #Mx ¤Ï¹½Â¤ #MDrawGlyph ¤Î¥á¥ó¥Ð <type> 
-    ¤ÎÃͤȤ·¤ÆÍѤ¤¤é¤ì¡¢¥á¥ó¥Ð <fontp> ¤Î·¿¤¬¼ÂºÝ¤Ë¤Ï (XFontStruct *) ¤Ç¤¢¤ë¤³¤È¤òɽ¤¹.  */
+    ÊÑ¿ô #Mx ¤Ï¹½Â¤ #MDrawGlyph ¤Î¥á¥ó¥Ð \<type\> 
+    ¤ÎÃͤȤ·¤ÆÍѤ¤¤é¤ì¡¢¥á¥ó¥Ð \<fontp\> ¤Î·¿¤¬¼ÂºÝ¤Ë¤Ï (XFontStruct *) ¤Ç¤¢¤ë¤³¤È¤òɽ¤¹.  */
 
 MSymbol Mx;
 
 /***en
     @brief Symbol of name "freetype".
 
-    The variable #Mfreetype is to be used for a value of <type> member
-    of the structure #MDrawGlyph to specify the type of <fontp> member
+    The variable #Mfreetype is to be used for a value of \<type\> member
+    of the structure #MDrawGlyph to specify the type of \<fontp\> member
     is actually FT_Face.  */
 /***ja
     @brief "freetype" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë.
 
-    ÊÑ¿ô #Mfreetype ¤Ï¹½Â¤ #MDrawGlyph ¤Î¥á¥ó¥Ð <type> 
-    ¤ÎÃͤȤ·¤ÆÍѤ¤¤é¤ì¡¢¥á¥ó¥Ð <fontp> ¤Î·¿¤¬¼ÂºÝ¤Ë¤Ï FT_Face ¤Ç¤¢¤ë¤³¤È¤òɽ¤¹¡£  */
+    ÊÑ¿ô #Mfreetype ¤Ï¹½Â¤ #MDrawGlyph ¤Î¥á¥ó¥Ð \<type\> 
+    ¤ÎÃͤȤ·¤ÆÍѤ¤¤é¤ì¡¢¥á¥ó¥Ð \<fontp\> ¤Î·¿¤¬¼ÂºÝ¤Ë¤Ï FT_Face ¤Ç¤¢¤ë¤³¤È¤òɽ¤¹¡£  */
 
 MSymbol Mfreetype;
 
 /***en
     @brief Symbol of name "xft".
 
-    The variable #Mxft is to be used for a value of <type> member of the
-    structure #MDrawGlyph to specify the type of <fontp> member
+    The variable #Mxft is to be used for a value of \<type\> member of the
+    structure #MDrawGlyph to specify the type of \<fontp\> member
     is actually (XftFont *).  */
 /***ja
     @brief  "xft" ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë.
 
-    ÊÑ¿ô #Mxft ¤Ï¹½Â¤ #MDrawGlyph ¤Î¥á¥ó¥Ð <type> 
-    ¤ÎÃͤȤ·¤ÆÍѤ¤¤é¤ì¡¢¥á¥ó¥Ð <fontp> ¤Î·¿¤¬¼ÂºÝ¤Ë¤Ï (XftFont *) ¤Ç¤¢¤ë¤³¤È¤òɽ¤¹¡£  */
+    ÊÑ¿ô #Mxft ¤Ï¹½Â¤ #MDrawGlyph ¤Î¥á¥ó¥Ð \<type\> 
+    ¤ÎÃͤȤ·¤ÆÍѤ¤¤é¤ì¡¢¥á¥ó¥Ð \<fontp\> ¤Î·¿¤¬¼ÂºÝ¤Ë¤Ï (XftFont *) ¤Ç¤¢¤ë¤³¤È¤òɽ¤¹¡£  */
 
 MSymbol Mxft;
 
@@ -2089,7 +2302,7 @@ mfont ()
     ¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
 
 MFont *
-mfont_parse_name (char *name, MSymbol format)
+mfont_parse_name (const char *name, MSymbol format)
 {
   MFont template, *font;
   
@@ -2138,7 +2351,7 @@ mfont_unparse_name (MFont *font, MSymbol format)
   char *name;
 
   if (format == Mx)
-    name = xlfd_unparse_name (font);
+    name = xlfd_unparse_name (font, 1);
 #ifdef HAVE_FONTCONFIG
   else if (format == Mfontconfig)
     name = mfont__ft_unparse_name (font);
@@ -2178,17 +2391,22 @@ mfont_copy (MFont *font)
     The mfont_get_prop () function gets the value of $KEY property of
     font $FONT.  $KEY must be one of the following symbols:
 
-       @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
-       @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype.
+       @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
+       @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mspacing.
 
-    @return
-    If $KEY is @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch, @c
-    Madstyle, @c Mregistry, or @c Mtype, this function returns the
-    corresponding value as a symbol.  If the font does not have $KEY
-    property, it returns @c Mnil.
-    If $KEY is @c Msize or @c Mresolution, this function returns the
-    corresponding value as an integer.  If the font does not have $KEY
-    property, it returns 0.
+    If $FONT is a return value of mfont_find (), $KEY can also be one
+    of the following symbols:
+
+       @b Mfont_ascent, @b Mfont_descent, #Mmax_advance.
+
+    @return 
+    If $KEY is @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle,
+    @c Mstretch, @c Madstyle, @c Mregistry, or @c Mspacing, this
+    function returns the corresponding value as a symbol.  If the font
+    does not have $KEY property, it returns @c Mnil.  If $KEY is @c
+    Msize, @c Mresolution, @b Mfont_ascent, Mfont_descent, or
+    #Mmax_advance, this function returns the corresponding value as an
+    integer.  If the font does not have $KEY property, it returns 0.
     If $KEY is something else, it returns @c NULL and assigns an error
     code to the external variable #merror_code.  */
  
@@ -2199,21 +2417,26 @@ mfont_copy (MFont *font)
     $KEY ¤Ç¤¢¤ë¤â¤Î¤ÎÃͤòÊÖ¤¹¡£$KEY ¤Ï°Ê²¼¤Î¥·¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤Ê¤±¤ì
     ¤Ð¤Ê¤é¤Ê¤¤¡£
 
-       @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
-       @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype.
+       @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
+       @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mspacing.
 
     @return 
-    $KEY ¤¬ @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch, @c
-    Madstyle, @c Mregistry, @c Mtype ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ì¤Ð¡¢ÁêÅö¤¹¤ëÃͤò¥·
-    ¥ó¥Ü¥ë¤È¤·¤ÆÊÖ¤¹¡£¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¾ì¹ç¤Ë¤Ï @c
-    Mnil ¤òÊÖ¤¹¡£$KEY ¤¬ @c Msize ¤¢¤ë¤¤¤Ï @c Mresolution ¤Î¾ì¹ç¤Ë¤Ï¡¢
-    ÁêÅö¤¹¤ëÃͤò¤ÏÀ°¿ôÃͤȤ·¤ÆÊÖ¤¹¡£¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤
-    ¾ì¹ç¤Ë¤Ï 0 ¤òÊÖ¤¹¡£$KEY ¤¬¤½¤ì°Ê³°¤Î¤â¤Î¤Ç¤¢¤ì¤Ð¡¢@c NULL ¤òÊÖ¤·¡¢
-    ³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
+    $KEY ¤¬ @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c
+    Mstretch, @c Madstyle, @c Mregistry, @c Mspacing ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ì¤Ð¡¢
+    ÁêÅö¤¹¤ëÃͤò¥·¥ó¥Ü¥ë¤È¤·¤ÆÊÖ¤¹¡£¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤
+    ¾ì¹ç¤Ë¤Ï@c Mnil ¤òÊÖ¤¹¡£$KEY ¤¬ @c Msize ¤¢¤ë¤¤¤Ï @c Mresolution ¤Î
+    ¾ì¹ç¤Ë¤Ï¡¢ÁêÅö¤¹¤ëÃͤò¤ÏÀ°¿ôÃͤȤ·¤ÆÊÖ¤¹¡£¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£
+    ¤ò»ý¤¿¤Ê¤¤¾ì¹ç¤Ë¤Ï 0 ¤òÊÖ¤¹¡£$KEY ¤¬¤½¤ì°Ê³°¤Î¤â¤Î¤Ç¤¢¤ì¤Ð¡¢@c
+    NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
 
 void *
 mfont_get_prop (MFont *font, MSymbol key)
 {
+  MRealizedFont *rfont = NULL;
+
+  if (font->type == MFONT_TYPE_REALIZED)
+    rfont = (MRealizedFont *) font;
+
   if (key == Mfoundry)
     return (void *) FONT_PROPERTY (font, MFONT_FOUNDRY);
   if (key == Mfamily)
@@ -2238,8 +2461,35 @@ mfont_get_prop (MFont *font, MSymbol key)
       int resy = font->property[MFONT_RESY];
       return (void *) resy;
     }
+  if (key == Mlanguage || key == Mscript || key == Motf)
+    {
+      MFontCapability *cap;
+
+      if (! font->capability)
+       return NULL;
+      cap = mfont__get_capability (font->capability);
+      if (key == Mlanguage)
+       return cap->language;
+      if (key == Mscript)
+       return cap->script;
+      return cap->otf;
+    }
+
   if (key == Mfontfile)
     return (void *) font->file;
+  if (key == Mspacing)
+    return (font->spacing == MFONT_SPACING_UNDECIDED ? Mnil
+           : msymbol (font->spacing == MFONT_SPACING_PROPORTIONAL ? "p"
+                      : font->spacing == MFONT_SPACING_MONO ? "m" : "c"));
+  if (rfont)
+    {
+      if (key == Mfont_ascent)
+       return (void *) rfont->ascent;
+      if (key == Mfont_descent)
+       return (void *) rfont->descent;
+      if (key == Mmax_advance)
+       return (void *) rfont->max_advance;
+    }
   MERROR (MERROR_FONT, NULL);
 }
 
@@ -2252,22 +2502,26 @@ mfont_get_prop (MFont *font, MSymbol key)
     $KEY and value is $VAL to font $FONT.  $KEY must be one of the
     following symbols:
 
-       @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
+       @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
        @c Madstyle, @c Mregistry, @c Msize, @c Mresolution.
 
     If $KEY is @c Msize or @c Mresolution, $VAL must be an integer.
-    Otherwise, $VAL must be a symbol.  */
+    Otherwise, $VAL must be a symbol of a property value name.  But,
+    if the name is "nil", a symbol of name "Nil" must be
+    specified.  */
  /***ja
     @brief ¥Õ¥©¥ó¥È¤Î¥×¥í¥Ñ¥Æ¥£¤ËÃͤòÀßÄꤹ¤ë.
 
-    ´Ø¿ô mfont_put_prop () ¤Ï¡¢¥Õ¥©¥ó¥È $FONT ¤Î¥­¡¼¤¬$KEY 
-    ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤò $VAL ¤ËÀßÄꤹ¤ë¡£$KEY ¤Ï°Ê²¼¤Î¥·¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
+    ´Ø¿ô mfont_put_prop () ¤Ï¡¢¥Õ¥©¥ó¥È $FONT ¤Î¥­¡¼¤¬$KEY ¤Ç¤¢¤ë¥×¥í¥Ñ
+    ¥Æ¥£¤ÎÃͤò $VAL ¤ËÀßÄꤹ¤ë¡£$KEY ¤Ï°Ê²¼¤Î¥·¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
 
-       @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
+       @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
        @c Madstyle, @c Mregistry, @c Msize, @c Mresolution.
 
-    $KEY ¤¬ @c Msize ¤« @c Mresolution ¤Ç¤¢¤ì¤Ð $VAL 
-    ¤ÏÀ°¿ôÃͤǤʤ¯¤Æ¤Ï¤é¤Ê¤¤¡£¤½¤ì°Ê³°¤Î¾ì¹ç¡¢$VAL ¤Ï¥·¥ó¥Ü¥ë¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
+    $KEY ¤¬ @c Msize ¤« @c Mresolution ¤Ç¤¢¤ì¤Ð $VAL ¤ÏÀ°¿ôÃͤǤʤ¯¤Æ¤Ï
+    ¤é¤Ê¤¤¡£¤½¤ì°Ê³°¤Î¾ì¹ç¡¢$VAL ¤Ï¥×¥í¥Ñ¥Æ¥£ÃͤÎ̾Á°¤Î¥·¥ó¥Ü¥ë¤Ç¤Ê¤¯¤Æ
+    ¤Ï¤Ê¤é¤Ê¤¤¡£¤¿¤À¤·¤â¤·¤½¤Î̾Á°¤¬ "nil" ¤Î¾ì¹ç¤Ï¡¢Ì¾Á°¤¬ "Nil" ¤Î¥·
+    ¥ó¥Ü¥ë¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
 
 int
 mfont_put_prop (MFont *font, MSymbol key, void *val)
@@ -2288,7 +2542,7 @@ mfont_put_prop (MFont *font, MSymbol key, void *val)
     mfont__set_property (font, MFONT_REGISTRY, (MSymbol) val);
   else if (key == Msize)
     {
-      unsigned size = (unsigned) val;
+      int size = (int) val;
       font->size = size;
     }
   else if (key == Mresolution)
@@ -2296,6 +2550,11 @@ mfont_put_prop (MFont *font, MSymbol key, void *val)
       unsigned resy = (unsigned) val;
       font->property[MFONT_RESY] = resy;
     }
+  else if (key == Mlanguage || key == Mscript || key == Motf)
+    {
+      font->capability = merge_capability (font->capability,
+                                          key, (MSymbol) val, 1);
+    }
   else if (key == Mfontfile)
     {
       font->file = (MSymbol) val;
@@ -2472,7 +2731,17 @@ mfont_find (MFrame *frame, MFont *spec, int *score, int max_size)
   MFont spec_copy;
   MFont *best;
   MFontList *list;
+  MRealizedFont *rfont;
+  MFont adjusted;
+
+  if (spec->size < 0)
+    {
+      double pt = - spec->size;
 
+      adjusted = *spec;
+      adjusted.size = pt * frame->dpi / 72.27 + 0.5;
+      spec = &adjusted;
+    }
   MFONT_INIT (&spec_copy);
   spec_copy.property[MFONT_FAMILY] = spec->property[MFONT_FAMILY];
   spec_copy.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
@@ -2488,7 +2757,12 @@ mfont_find (MFrame *frame, MFont *spec, int *score, int max_size)
     *score = list->fonts[0].score;
   free (list->fonts);
   free (list);
-  return best;
+  spec_copy = *best;
+  mfont__merge (&spec_copy, spec, 0);
+  rfont = mfont__open (frame, best, spec);
+  if (! rfont)
+    return NULL;
+  return (MFont *) rfont;
 }
 
 /*=*/
@@ -2597,7 +2871,7 @@ mfont_name (MFont *font)
     ¤³¤ì¤Ï´Ø¿ô¤ÏÇÑ»ßͽÄê¤Ç¤¢¤ë¡£ mfont_parse_name () ¤ò»ÈÍѤΤ³¤È¡£  */
 
 MFont *
-mfont_from_name (char *name)
+mfont_from_name (const char *name)
 {
   return mfont_parse_name (name, Mx);
 }
@@ -2624,10 +2898,29 @@ mfont_from_name (char *name)
 int
 mfont_resize_ratio (MFont *font)
 {
-  MFont request = *font;
+  MSymbol registry = FONT_PROPERTY (font, MFONT_REGISTRY);
+  MFontResize *resize;
+  MPlist *plist;
 
-  mfont__resize (font, &request);
-  return (font->size * 100 / request.size);
+  if (! font_resize_list)
+    load_font_resize_table ();
+  if (! MPLIST_TAIL_P (font_resize_list))
+    while (1)
+      {
+       plist = font_resize_list;
+       while (registry ? (plist = mplist_find_by_key (plist, registry))
+              : plist)
+         {
+           resize = (MFontResize *) MPLIST_VAL (plist);
+           if (mfont__match_p (font, &resize->spec, MFONT_ADSTYLE))
+             return resize->resize;
+           plist = MPLIST_NEXT (plist);
+         }
+       if (registry == Mt)
+         break;
+       registry = Mt;
+      }
+  return 100;
 }
 
 /*=*/
@@ -2641,6 +2934,10 @@ mfont_resize_ratio (MFont *font)
     ones that support $LANGUAGE.  $MAXNUM, if greater than 0, limits
     the number of fonts.
 
+    $LANGUAGE argument exists just for backward compatibility, and the
+    use is deprecated.  Use #Mlanguage font property instead.  If
+    $FONT already has #Mlanguage property, $LANGUAGE is ignored.
+
     @return
     This function returns a plist whose keys are family names and
     values are pointers to the object MFont.  The plist must be freed
@@ -2650,15 +2947,21 @@ mfont_resize_ratio (MFont *font)
 /***ja
     @brief ¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÆÀ¤ë
 
-    ´Ø¿ô mfont_list () ¤Ï¥Õ¥ì¡¼¥à $FRAME ¤ÇÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£
-    $FONT ¤¬ NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢$FONT ¤È¹çÃפ¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£
-    $LANGUAGE ¤¬ @c Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤ò¥µ¥Ý¡¼¥È¤¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£
-    $MAXNUM ¤Ï¡¢0 ¤è¤êÂ礭¤¤¾ì¹ç¤Ë¤Ï¡¢ÊÖ¤¹¥Õ¥©¥ó¥È¤Î¿ô¤Î¾å¸Â¤Ç¤¢¤ë¡£
+    ´Ø¿ô mfont_list () ¤Ï¥Õ¥ì¡¼¥à $FRAME ¤ÇÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤ò
+    ÊÖ¤¹¡£$FONT ¤¬ NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢$FONT ¤È¹çÃפ¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È
+    ¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£$LANGUAGE ¤¬ @c Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤ò¥µ¥Ý¡¼
+    ¥È¤¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£$MAXNUM ¤Ï¡¢0 ¤è¤êÂ礭¤¤¾ì
+    ¹ç¤Ë¤Ï¡¢ÊÖ¤¹¥Õ¥©¥ó¥È¤Î¿ô¤Î¾å¸Â¤Ç¤¢¤ë¡£
+
+    ¤¿¤À¤·¡¢°ú¿ô $LANGUAGE ¤ÏµìÈǤȤÎÀ°¹çÀ­¤Î¤¿¤á¤À¤±¤Ë¤¢¤ê¡¢¤½¤Î»ÈÍѤÏ
+    ´«¤á¤é¤ì¤Ê¤¤¡£¥Õ¥©¥ó¥È¤Î #Mlanguage ¥×¥í¥Ñ¥Æ¥£¤ò»È¤¦¤Ù¤­¤Ç¤¢¤ë¡£¤â
+    ¤· $FONT ¤¬¤¹¤Ç¤Ë¤³¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ã¤Æ¤¤¤¿¤é¡¢°ú¿ô $LANGUAGE ¤Ï̵
+
 
     @return 
-    ¤³¤Î´Ø¿ô¤Ï¥­¡¼¤¬¥Õ¥©¥ó¥È¥Õ¥¡¥ß¥ê̾¤Ç¤¢¤êÃͤ¬ MFont ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤è¤¦¤Ê
-    plist ¤òÊÖ¤¹¡£plist ¤Ï m17n_object_unref () 
-    ¤Ç²òÊü¤¹¤ëɬÍפ¬¤¢¤ë¡£¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤ÐNULL ¤òÊÖ¤¹¡£  */
+    ¤³¤Î´Ø¿ô¤Ï¥­¡¼¤¬¥Õ¥©¥ó¥È¥Õ¥¡¥ß¥ê̾¤Ç¤¢¤êÃͤ¬ MFont ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î
+    ¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤è¤¦¤Êplist ¤òÊÖ¤¹¡£plist ¤Ï m17n_object_unref () ¤Ç
+    ²òÊü¤¹¤ëɬÍפ¬¤¢¤ë¡£¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤ÐNULL ¤òÊÖ¤¹¡£  */
 
 MPlist *
 mfont_list (MFrame *frame, MFont *font, MSymbol language, int maxnum)
@@ -2666,22 +2969,25 @@ mfont_list (MFrame *frame, MFont *font, MSymbol language, int maxnum)
   MPlist *plist, *pl;
   MFontList *font_list;
   int i;
-  MFont *work = NULL;
+  MFont spec;
   
-  if (language != Mnil)
+  if (font)
+    spec = *font;
+  else
+    MFONT_INIT (&spec);
+
+  if (spec.size < 0)
     {
-      /* ":lang=XXX" */
-      char *buf = alloca (MSYMBOL_NAMELEN (language) + 7);
+      double pt = - spec.size;
 
-      sprintf (buf, ":lang=%s", MSYMBOL_NAME (language));
-      if (! font)
-       font = work = mfont ();
-      font->capability = msymbol (buf);
+      spec.size = pt * frame->dpi / 72.27 + 0.5;
     }
 
-  font_list = mfont__list (frame, font, font, 0);
-  if (work)
-    free (work);
+  if (language != Mnil)
+    spec.capability = merge_capability (spec.capability, Mlanguage, language,
+                                       0);
+
+  font_list = mfont__list (frame, &spec, &spec, 0);
   if (! font_list)
     return NULL;
   if (font_list->nfonts == 0)
@@ -2702,63 +3008,171 @@ mfont_list (MFrame *frame, MFont *font, MSymbol language, int maxnum)
   return plist;
 }
 
+/***en
+    @brief Get a list of font famiy names.
+
+    The mfont_list_family_names () functions returns a list of font
+    family names available on frame $FRAME.
+
+    @return
+
+    This function returns a plist whose keys are #Msymbol and values
+    are symbols representing font family names.  The elements are
+    sorted by alphabetical order.  The plist must be freed by
+    m17n_object_unref ().  If not font is found, it returns NULL.  */
+
+MPlist *
+mfont_list_family_names (MFrame *frame)
+{
+  MPlist *plist = mplist (), *p;
+
+  MPLIST_DO (p, frame->font_driver_list)
+    {
+      MFontDriver *driver = MPLIST_VAL (p);
+
+      (driver->list_family_names) (frame, plist);
+    }
+  return plist;
+}
+
 
 /*=*/
 
 /***en
     @brief Check the usability of a font.
 
-    The function mfont_check () checkes if $FONT can be used for
-    $SCRIPT and RLANGUAGE in $FONTSET on $FRAME.
+    The mfont_check () function checkes if $FONT can be used for
+    $SCRIPT and $LANGUAGE in $FONTSET on $FRAME.
 
-    @return If the font is usable, return 1.  Otherwise return 0.
+    @return 
+    If the font is usable, return 1.  Otherwise return 0.
  */
 
 int
-mfont_check (MFrame *frame, MFontset *fontset, MFont *font,
-            MSymbol script, MSymbol language)
+mfont_check (MFrame *frame, MFontset *fontset,
+            MSymbol script, MSymbol language, MFont *font)
 {
-  MFont spec;
-  MPlist *plist, *pl;
-  int result = 0;
+  MRealizedFont *rfont;
+  int best, score;
 
   if (! fontset)
     fontset = frame->face->property[MFACE_FONTSET];
+  rfont = mfontset__get_font (frame, fontset, script, language, font, &best);
+  if (! rfont || ! best)
+    return 0;
+  score = font_score (&rfont->spec, font);
+  return (score == 0 ? 2 : 1);
+}
 
-  plist = mfontset_lookup (fontset, script, Mt, Mnil);
-  if (script != Mnil)
-    {
-      if (language == Mnil)
-       {
-         if (! mplist_find_by_key (plist, Mt))
-           /* No fallback fonts.  */
-           language = MPLIST_KEY (plist);
-       }
-      else if (! mplist_find_by_key (plist, language))
-       {
-         /* Try fallback fonts. */
-         if (mplist_find_by_key (plist, Mt))
-           language = Mnil;
-         else
-           /* No fallback fonts.  */
-           language = MPLIST_KEY (plist);
-       }
+/*=*/
 
-      M17N_OBJECT_UNREF (plist);
-      plist = mfontset_lookup (fontset, script, language, Mnil);
-    }
-  MPLIST_DO (pl, plist)
+/***en
+    @brief Check is a font matches with a font spec.
+
+    The mfont_match_p () function checks if $FONT matches with the
+    font-spec $SPEC.
+
+    @return 
+    If the font matches, 1 is returned.  Otherwise 0 is returned.  */
+
+int
+mfont_match_p (MFont *font, MFont *spec)
+{
+  return mfont__match_p (font, spec, MFONT_REGISTRY);
+}
+
+/*=*/
+/***en
+    @brief Open a font.
+
+    The mfont_open () function opens $FONT on $FRAME, and returns a
+    realized font.
+
+    @return
+    If the font was successfully opened, a realized font is returned.
+    Otherwize NULL is returned.
+
+    @seealso
+    mfont_close ().  */
+
+
+MFont *
+mfont_open (MFrame *frame, MFont *font)
+{
+  enum MFontType font_type = font->type;
+
+  if (font_type == MFONT_TYPE_SPEC)
+    return mfont_find (frame, font, NULL, 0);
+  if (font_type == MFONT_TYPE_OBJECT)
+    return (MFont *) mfont__open (frame, font, font);
+  if (font_type == MFONT_TYPE_REALIZED)
+    return font;
+  MERROR (MERROR_FONT, NULL);
+}
+
+/*=*/
+/***en
+    @brief Encapusulate a font.
+
+    The mfont_encapsulate () functions realizes a font by
+    encapusulating data $DATA or type $DATA_TYPE on $FRAME.  Currently
+    $DATA_TAPE is #Mfontconfig or #Mfreetype, and $DATA points to an
+    object of FcPattern or FT_Face respectively.
+
+    @return
+    If the operation was successful, a realized font is returned.
+    Otherwise NULL is return.
+
+    @seealso
+    mfont_close ().  */
+
+
+MFont *
+mfont_encapsulate (MFrame *frame, MSymbol data_type, void *data)
+{
+  MPlist *p;
+
+  MPLIST_DO (p, frame->font_driver_list)
     {
-      spec = *(MFont *) MPLIST_VAL (pl);         
-      if (mfont__merge (&spec, font, 1) >= 0
-         && mfont__select (frame, &spec, 0))
-       {
-         result = 1;
-         break;
-       }
+      MFontDriver *driver = MPLIST_VAL (p);
+      MRealizedFont *rfont;
+
+      if (driver->encapsulate
+         && (rfont = driver->encapsulate (frame, data_type, data)))
+       return (MFont *) rfont;
     }
-  M17N_OBJECT_UNREF (plist);
-  return result;
+
+  return NULL;
+}
+
+/*=*/
+/***en
+    @brief Close a font.
+
+    The mfont_close () function close a realized font $FONT.  $FONT
+    must be opened previously by mfont_open () or mfont_encapsulate
+    ().
+
+    @return
+    If the operation was successful, 0 is returned.  Otherwise, -1 is
+    returned.
+
+    @seealso
+    mfont_open (), mfont_encapsulate ().  */
+
+int
+mfont_close (MFont *font)
+{
+  enum MFontType font_type = font->type;
+  MRealizedFont *rfont;
+
+  if (font_type != MFONT_TYPE_REALIZED)
+    MERROR (MERROR_FONT, -1);
+  rfont = (MRealizedFont *) font;
+  if (rfont->encapsulating
+      && rfont->driver->close)
+    rfont->driver->close (rfont);
+  return 0;
 }
 
 /*** @} */
@@ -2789,12 +3203,26 @@ mdebug_dump_font (MFont *font)
 {
   char *name;
   
-  name = mfont_unparse_name (font, Mx);
+  name = xlfd_unparse_name (font, 0);
   if (name)
     {
       fprintf (stderr, "%s", name);
       free (name);
     }
+  if (font->file != Mnil)
+    {
+      char *file = MSYMBOL_NAME (font->file);
+      char *lastslash = file, *p;
+
+      for (p = file; *p; p++)
+       if (*p == '/')
+         lastslash = p;
+      if (name)
+       fprintf (stderr, ",");
+      fprintf (stderr, "%s", lastslash + 1);
+    }
+  if (font->capability != Mnil)
+    fprintf (stderr, "%s", MSYMBOL_NAME (font->capability));
   return font;
 }