Include "fontset.h".
authorhanda <handa>
Wed, 17 Aug 2005 13:00:30 +0000 (13:00 +0000)
committerhanda <handa>
Wed, 17 Aug 2005 13:00:30 +0000 (13:00 +0000)
(M_font_capability, M_font_list, M_font_list_len): New variables.
(font_score_priority): Change order of initial elements.
(font_score_shift_bits): Fix array size.
(common_weight): Add "thin", "semibold", and "heavy".
(common_stretch): Add "ultracondensed", "extracondensed",
"extraexpanded", and "utltraexpand".
(font_weight_regular, font_weight_normal, font_weight_medium): New
variables.
(gen_font_name): This function deleted.
(find_encoding): Set font->encoding.
(OTF_tag): New function.
(otf_script_list): New variable.
(load_otf_script_list): New function.
(find_script_from_otf_tag): New function.
(xlfd_parse_name): Set font->type and font->source.
(mfont__free_realized): Free chains rfonts.
(font_score): Renamed from mfont__score.
(Miso8859_1, Miso10646_1, Municode_bmp, Municode_full)
(Mapple_roman): New variables.
(mfont__init): Initilize new variables.  Initalize
default_encoding.encoding_name and
default_encoding.encoding_charset to Municode_full and
mcharset__unicode.  Use SAFE* macros for allocating filepath
buffer.
(mfont__fini): Free otf_script_list.
(mfont__id): New function.
(mfont__match_p): Check also capability member of MFont.
(mfont__merge): New funciton.
(mfont__set_spec_from_face): Set type and source members.
(mfont__set_spec_from_plist): Set capability and type members.
(mfont__select): Argument changed.
(mfont__available): New function.
(compare_font_score): New function.
(mfont__list): New function.
(mfont__open): Return a realized font.
(mfont__resize): Adjusted for the change of MFont.
(mfont__has_char): New function.
(mfont__encode_char): Argument changed.
(mfont__set_spec): Argument changed.
(free_font_capability): New function.
(mfont__get_capability): New function.
(MFontfile): New variable.
(mfont_get_prop): Adjusted for the change of MFont.
(mfont_put_prop): Likewise.
(mfont_set_selection_priority): Fix the way of setting
font_score_priority[].
(mfont_find): Use mfont__list instead of mfont__select.
(mfont_resize_ratio): Adjusted for the change of MFont.
(mfont_list): Use mfont__list.
(mfont_check): New function.

src/font.c

index 0a59172..ae30530 100644 (file)
@@ -30,7 +30,7 @@
     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 Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype.
 
     When the key of a font property is @c Msize or @c Mresolution, its
     value is an integer.  Otherwise the value is a symbol.  
     size in the unit of 1/10 point.
 
     The value of a resolution property is an integer representing
-    assumed device resolution in the unit of dots per inch (dpi)
+    assumed device resolution in the unit of dots per inch (dpi).
+
+    The value of a type property is a symbol indicating a font driver;
+    currently Mx or Mfreetype.
 
     The m17n library uses font objects for two purposes: to receive
     font specification from an application program, and to present
     variable @c M17NDIR.  See the documentation of the variable for
     details.
 
-    If the m17n library is configured to use the fontconfig librray,
+    If the m17n library is configured to use the fontconfig library,
     in addition to #mfont_freetype_path, all fonts available via
     fontconfig are supported.
 
     @addtogroup m17nFont
     @brief ¥Õ¥©¥ó¥È¥ª¥Ö¥¸¥§¥¯¥È.
 
-    m17n GUI API ¤Ï¥Õ¥©¥ó¥È¤ò @c MFont ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤È¤·¤Æɽ¸½¤¹¤ë¡£¥Õ¥©¥ó¥È¤Ï @e 
-    ¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£ ¤ò»ý¤Ä¤³¤È¤¬¤Ç¤­¤ë¡£Â¾¤Î¥¿¥¤¥×¤Î¥×¥í¥Ñ¥Æ¥£Æ±ÍÍ¡¢¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Ï¥­¡¼¤ÈÃͤ«¤é¤Ê¤ê¡¢¥­¡¼¤Ï°Ê²¼¤Î¥·¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
+    m17n GUI API ¤Ï¥Õ¥©¥ó¥È¤ò @c MFont ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤È¤·¤Æɽ¸½¤¹¤ë¡£
+    ¥Õ¥©¥ó¥È¤Ï @e ¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£ ¤ò»ý¤Ä¤³¤È¤¬¤Ç¤­¤ë¡£Â¾¤Î¥¿¥¤¥×¤Î¥×
+    ¥í¥Ñ¥Æ¥£Æ±ÍÍ¡¢¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Ï¥­¡¼¤ÈÃͤ«¤é¤Ê¤ê¡¢¥­¡¼¤Ï°Ê²¼¤Î¥·
+    ¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
 
     @c Mfoundry, @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
-    @c Madstyle, @c Mregistry, @c Msize, @c Mresolution
+    @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype
 
     ¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤¬ @c Msize ¤¢¤ë¤¤¤Ï @c Mresolution 
     ¤Î¾ì¹ç¡¢ÃͤÏÀ°¿ôÃͤǤ¢¤ê¡¢¥­¡¼¤¬¤½¤ì°Ê³°¤Î¾ì¹ç¡¢Ãͤϥ·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
     registry ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢iso10646, iso8895-1
     Åù¤Î¥ì¥¸¥¹¥È¥ê¾ðÊó¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
 
-    size ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢¥Õ¥©¥ó¥È¤Î¥Ç¥¶¥¤¥ó¥µ¥¤¥º¤òɽ¤ï¤¹À°¿ôÃͤǤ¢¤ê¡¢Ã±°Ì¤Ï
-    1/10 ¥Ý¥¤¥ó¥È¤Ç¤¢¤ë¡£
+    size ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢¥Õ¥©¥ó¥È¤Î¥Ç¥¶¥¤¥ó¥µ¥¤¥º¤òɽ¤ï¤¹À°¿ôÃͤǤ¢¤ê¡¢
+    Ã±°Ì¤Ï1/10 ¥Ý¥¤¥ó¥È¤Ç¤¢¤ë¡£
+
+    resolution ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢ÁÛÄꤵ¤ì¤Æ¤¤¤ë¥Ç¥Ð¥¤¥¹¤Î²òÁüÅÙ¤òɽ¤ï¤¹
+    À°¿ôÃͤǤ¢¤ê¡¢Ã±°Ì¤Ïdots per inch (dpi) ¤Ç¤¢¤ë¡£
 
-    resolution ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢ÁÛÄꤵ¤ì¤Æ¤¤¤ë¥Ç¥Ð¥¤¥¹¤Î²òÁüÅÙ¤òɽ¤ï¤¹À°¿ôÃͤǤ¢¤ê¡¢Ã±°Ì¤Ï
-    dots per inch (dpi) ¤Ç¤¢¤ë¡£  
+    type ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢¥Õ¥©¥ó¥È¥É¥é¥¤¥Ð¤ò»Ø¼¨¤·¡¢¸½ºß Mx ¤â¤·¤¯¤Ï
+    Mfreetype ¤Ç¤¢¤ë¡£
 
-    m17n ¥é¥¤¥Ö¥é¥ê¤Ï¥Õ¥©¥ó¥È¥ª¥Ö¥¸¥§¥¯¥È¤ò£²¤Ä¤ÎÌÜŪ¤ÇÍѤ¤¤Æ¤¤¤ë¡£
-    ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¥Õ¥©¥ó¥È¤Î»ØÄê¤ò¼õ¤±¼è¤ëÌÜŪ¤È¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤ËÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤òÄ󼨤¹¤ëÌÜŪ¤Ç¤¢¤ë¡£
-    ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤ËÂФ·¤ÆÄ󼨤ò¹Ô¤¦ºÝ¤Ë¤Ï¡¢¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù¤Æ¶ñÂÎŪ¤ÊÃͤò»ý¤Ä¡£
+    m17n ¥é¥¤¥Ö¥é¥ê¤Ï¥Õ¥©¥ó¥È¥ª¥Ö¥¸¥§¥¯¥È¤ò£²¤Ä¤ÎÌÜŪ¤ÇÍѤ¤¤Æ¤¤¤ë¡£¥¢¥×
+    ¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¥Õ¥©¥ó¥È¤Î»ØÄê¤ò¼õ¤±¼è¤ëÌÜŪ¤È¡¢¥¢¥×¥ê¥±¡¼
+    ¥·¥ç¥ó¥×¥í¥°¥é¥à¤ËÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤òÄ󼨤¹¤ëÌÜŪ¤Ç¤¢¤ë¡£¥¢¥×¥ê¥±¡¼
+    ¥·¥ç¥ó¥×¥í¥°¥é¥à¤ËÂФ·¤ÆÄ󼨤ò¹Ô¤¦ºÝ¤Ë¤Ï¡¢¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Ï¤¹¤Ù
+    ¤Æ¶ñÂÎŪ¤ÊÃͤò»ý¤Ä¡£
 
     m17n ¥é¥¤¥Ö¥é¥ê¤Ï Window ¥·¥¹¥Æ¥à¥Õ¥©¥ó¥È¡¢FreeType¥Õ¥©¥ó¥È¡¢
     OpenType¥Õ¥©¥ó¥È¤Î£³¼ïÎà¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë¡£
 #include "internal-gui.h"
 #include "font.h"
 #include "face.h"
+#include "fontset.h"
 
 MPlist *mfont__driver_list;
 
+static MSymbol M_font_capability, M_font_list, M_font_list_len;
+
 /** Indices to font properties sorted by their priority.  */
 static int font_score_priority[] =
   { MFONT_SIZE,
-    MFONT_ADSTYLE,
-    MFONT_FAMILY,
     MFONT_WEIGHT,
     MFONT_STYLE,
     MFONT_STRETCH,
+    MFONT_FAMILY,
+    MFONT_ADSTYLE,
     MFONT_FOUNDRY
   };
 
@@ -348,10 +361,10 @@ static int font_score_priority[] =
 
 /* Indexed by a font property MFONT_XXX, and the value is how many
    bits to shift the difference of property values.  */
-static int font_score_shift_bits[MFONT_PROPERTY_MAX];
+static int font_score_shift_bits[MFONT_SIZE + 1];
 
 /** Predefined symbols for each font property.  The order is important
-    because the function score_font () decides how well a font matches
+    because the function font_score () decides how well a font matches
     with a spec by checking how close the index is.  */
 
 static char *common_foundry[] =
@@ -363,7 +376,8 @@ static char *common_family[] =
     "helvetica",
     "times" };
 static char *common_weight[] =
-  { "ultralight",
+  { "thin"
+    "ultralight",
     "extralight",
     "light",
     "demilight",
@@ -372,10 +386,12 @@ static char *common_weight[] =
     "normal",
     "medium",
     "demibold",
+    "semibold",
     "bold",
     "extrabold",
     "ultrabold",
-    "black" };
+    "black",
+    "heavy" };
 static char *common_style[] =
   { "o",
     "i",
@@ -385,12 +401,16 @@ static char *common_style[] =
     "ri",
     "ro" };
 static char *common_stretch[] =
-  { "condensed",
+  { "ultracondensed",
+    "extracondensed",
+    "condensed",
     "narrow",
     "semicondensed",
     "normal",
     "semiexpanded",
-    "expanded" };
+    "expanded",
+    "extraexpanded",
+    "ultraexpanded" };
 static char *common_adstyle[] =
   { "serif",
     "",
@@ -398,6 +418,10 @@ static char *common_adstyle[] =
 static char *common_registry[] =
   { "iso8859-1" };
 
+static unsigned short font_weight_regular;
+static unsigned short font_weight_normal;
+static unsigned short font_weight_medium;
+
 /* Table containing all the data above.  */
 
 struct MFontCommonNames
@@ -437,31 +461,6 @@ MFontPropertyTable mfont__property_table[MFONT_REGISTRY + 1];
   msymbol_put((symbol), mfont__property_table[(n)].property,   \
              (void *) (numeric))
 
-static char *
-gen_font_name (char *buf, MFont *font)
-{
-  char size[16];
-  int i;
-
-  buf[0] = '\0';
-  for (i = 0; i <= MFONT_REGISTRY; i++)
-    if (FONT_PROPERTY (font, i) != Mnil)
-      {
-       char *name = msymbol_name (FONT_PROPERTY (font, i));
-
-       if (name[0])
-         {
-           if (i > 0)
-             strcat (buf, ",");
-           strcat (buf, name);
-         }
-      }
-  sprintf (size, ",%d", font->property[MFONT_SIZE] / 10);
-  strcat (buf, size);
-  return buf;
-}
-
-
 \f
 /* Font selector.  */
 
@@ -633,6 +632,7 @@ find_encoding (MFont *font)
                  continue;
                }
            }
+         font->encoding = encoding;
          return encoding;
        }
 
@@ -645,9 +645,74 @@ find_encoding (MFont *font)
       else
        plist = MPLIST_NEXT (plist);
     }
+  font->encoding = &default_encoding;
   return &default_encoding;
 }
 
+#ifndef HAVE_OTF
+static OTF_Tag
+OTF_tag (char *name)
+{
+  unsigned char *p = (unsigned char *) name;
+
+  if (! name)
+    return (OTF_Tag) 0;
+  return (OTF_Tag) ((p[0] << 24)
+                   | (! p[1] ? 0
+                      : ((p[1] << 16)
+                         | (! 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)
+{
+  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);
+}
+
+
 /* XLFD parser/generator */
 
 /** Indices to each field of split font name.  */
@@ -675,7 +740,8 @@ static int
 xlfd_parse_name (char *name, MFont *font)
 {
   char *field[XLFD_FIELD_MAX];
-  unsigned short size, resy, avgwidth;
+  unsigned short resy, avgwidth;
+  unsigned size;
   MSymbol attrs[MFONT_PROPERTY_MAX];
   char copy[513];
   int i;
@@ -743,6 +809,8 @@ xlfd_parse_name (char *name, MFont *font)
   attrs[MFONT_REGISTRY]
     = field[XLFD_REGISTRY] ? msymbol (field[XLFD_REGISTRY]) : Mnil;
   mfont__set_spec (font, attrs, size, resy);
+  font->type = MFONT_TYPE_SPEC;
+  font->source = MFONT_SOURCE_X;
   return 0;
 }
 
@@ -783,12 +851,12 @@ xlfd_unparse_name (MFont *font)
       > 513)
     return NULL;
 
-  size = (int) mfont_get_prop (font, Msize);
+  resy = (int) mfont_get_prop (font, Mresolution);
+  size = font->size;
   if ((size % 10) < 5)
     size /= 10;
   else
     size = size / 10 + 1;
-  resy = (int) mfont_get_prop (font, Mresolution);
 
   sprintf (name, "-%s-%s-%s-%s-%s-%s-%d-*-%d-%d-*-*-%s",
           str[0], str[1], str[2], str[3], str[4], str[5],
@@ -796,13 +864,97 @@ xlfd_unparse_name (MFont *font)
   return strdup (name);
 }
 
+void
+mfont__free_realized (MRealizedFont *rfont)
+{
+  MRealizedFont *next;
+
+  for (; rfont; rfont = next)
+    {
+      next = rfont->next;
+      M17N_OBJECT_UNREF (rfont->info);
+      free (rfont);
+      rfont = next;
+    }
+}
+
+
+/* Compare FONT with REQUEST and return how much they differs.  */
+
+int
+font_score (MFont *font, MFont *request)
+{
+  int score = 0;
+  int i = FONT_SCORE_PRIORITY_SIZE;
+
+  while (--i >= 0)
+    {
+      enum MFontProperty prop = font_score_priority[i];
+      int val;
+
+      if (prop == MFONT_SIZE)
+       {
+         if (font->size && request->size)
+           {
+             val = font->size - request->size;
+             if (val)
+               {
+                 if (val < 0)
+                   val = - val;
+                 if (val >= 0x10000)
+                   val = 0xFFFF;
+                 score |= (val << font_score_shift_bits[MFONT_SIZE]);
+               }
+           }
+       }
+      else if (font->property[prop] && request->property[prop]
+              && font->property[prop] != request->property[prop])
+       {
+         if (prop <= MFONT_FAMILY)
+           val = 1;
+         else if (prop == MFONT_WEIGHT)
+           {
+             unsigned short v1 = font->property[prop];
+             unsigned short v2 = request->property[prop];
+
+             if (v1 == font_weight_regular || v1 == font_weight_normal)
+               v1 = font_weight_medium;
+             if (v2 == font_weight_regular || v2 == font_weight_normal)
+               v2 = font_weight_medium;
+             val = v1 > v2 ? v1 - v2 : v2 - v1;
+           }
+         else
+           {
+             val = font->property[prop] - request->property[prop];
+             if (val < 0)
+               val = - val;
+             if (val > 3)
+               val = 3;
+           }
+         score |= val << font_score_shift_bits[prop];
+       }
+    }
+  if (request->file != Mnil && request->file != font->file)
+    score |= 40000000;
+  return score;
+}
+
 \f
 /* Internal API */
 
+MSymbol Miso8859_1, Miso10646_1, Municode_bmp, Municode_full, Mapple_roman;
+
 int
 mfont__init ()
 {
   int i, shift;
+  MSymbol regular = msymbol ("regular");
+  MSymbol normal = msymbol ("normal");
+  MSymbol medium = msymbol ("medium");
+
+  M_font_capability = msymbol_as_managing_key ("  font-capability");
+  M_font_list = msymbol_as_managing_key ("  font-list");
+  M_font_list_len = msymbol ("  font-list-len");
 
   Mfoundry = msymbol ("foundry");
   mfont__property_table[MFONT_FOUNDRY].property = Mfoundry;
@@ -821,6 +973,7 @@ mfont__init ()
 
   Msize = msymbol ("size");
   Mresolution = msymbol ("resolution");
+  Mfontfile = msymbol ("fontfile");
 
   Mfontconfig = msymbol ("fontconfig");
 
@@ -828,6 +981,12 @@ mfont__init ()
   Mfreetype = msymbol ("freetype");
   Mxft = msymbol ("xft");
 
+  Miso8859_1 = msymbol ("iso8859-1");
+  Miso10646_1 = msymbol ("iso10646-1");
+  Municode_bmp = msymbol ("unicode-bmp");
+  Municode_full = msymbol ("unicode-full");
+  Mapple_roman = msymbol ("apple-roman");
+
   /* 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++)
@@ -850,46 +1009,59 @@ mfont__init ()
          if (msymbol_put (sym, mfont__property_table[i].property,
                           (void *) (j + 1)) < 0)
            return -1;
-         MLIST_APPEND1 (&mfont__property_table[i], names, sym, MERROR_FONT);
+         MLIST_APPEND1 (&mfont__property_table[i], names, sym,
+                        MERROR_FONT);
+         if (i == MFONT_WEIGHT)
+           {
+             if (sym == regular)
+               font_weight_regular = j + 1;
+             else if (sym == normal)
+               font_weight_normal = j + 1;
+             else if (sym == medium)
+               font_weight_medium = j + 1;
+           }
        }
     }
 
   /* Here, SHIFT starts from 1, not 0.  This is because the lowest bit
      of a score is a flag for a scalable font (see the documentation
-     of mfont_score).  */
+     of font_score).  */
   i = FONT_SCORE_PRIORITY_SIZE - 1;
   for (shift = 1; i >= 0; i--)
     {
       font_score_shift_bits[font_score_priority[i]] = shift;
       if (font_score_priority[i] == MFONT_SIZE)
        shift += 16;
+      else if (font_score_priority[i] <= MFONT_FAMILY)
+       shift++;
       else
        shift += 2;
     }
 
   MFONT_INIT (&default_encoding.spec);
-  default_encoding.encoding_name = Mnil;
-  default_encoding.encoding_charset = NULL;
+  default_encoding.encoding_name = Municode_full;
+  default_encoding.encoding_charset = mcharset__unicode;
   default_encoding.repertory_name = Mnil;
   default_encoding.repertory_charset = NULL;
   {
     char *path, *buf;
     int bufsize;
+    USE_SAFE_ALLOCA;
 
     mfont_freetype_path = mplist ();
     bufsize = strlen (M17NDIR) + 7;
-    buf = alloca (bufsize);
+    SAFE_ALLOCA (buf, bufsize);
     sprintf (buf, "%s/fonts", M17NDIR);
     mplist_add (mfont_freetype_path, Mstring, strdup (buf));
     path = getenv ("M17NDIR");
     if (path)
       {
-       i = strlen (path) + 7;
-       if (i > bufsize)
-         buf = alloca (i);
+       bufsize = strlen (path) + 7;
+       SAFE_ALLOCA (buf, bufsize);
        sprintf (buf, "%s/fonts", path);
        mplist_push (mfont_freetype_path, Mstring, strdup (buf));
       }
+    SAFE_FREE (buf);
   }
 
 #ifdef HAVE_FREETYPE
@@ -931,65 +1103,70 @@ 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);
 }
 
-void
-mfont__free_realized (MRealizedFont *rfont)
-{
-  M17N_OBJECT_UNREF (rfont->info);
-  free (rfont);
-}
 
-
-/* Compare FONT with REQUEST and return how much they differs.  If
-   FONT does not match with SPEC, return -1.  */
-
-int
-mfont__score (MFont *font, MFont *spec, MFont *request, int limited_size)
+MSymbol
+mfont__id (MFont *font)
 {
-  int score = 0;
-  int i = FONT_SCORE_PRIORITY_SIZE;
-
-  while (--i >= 0)
+  char *buf, *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;
+  MSymbol id;
+  USE_SAFE_ALLOCA;
+
+  SAFE_ALLOCA (buf, total_len);
+  p = buf;
+  if (font->property[0])
+    p += sprintf (p, "%X", font->property[0]);
+  for (i = 1; i < MFONT_PROPERTY_MAX; i++)
     {
-      enum MFontProperty prop = font_score_priority[i];
-
-      if (request->property[prop] != 0)
-       {
-         int val = 0;
-
-         if (spec->property[prop] && font->property[prop]
-             && font->property[prop] != spec->property[prop])
-           return -1;
-         if (font->property[prop])
-           val = abs (font->property[prop] - request->property[prop]);
-         if (val && prop <= MFONT_FAMILY)
-           val = 1;
-         if (prop == MFONT_SIZE)
-           {
-             if (font->property[MFONT_RESY] == 0)
-               /* This is a scalable font.  We prefer a bitmap font
-                  if the size matches exactly.  */
-               score |= 1;
-             else
-               score |= (val << font_score_shift_bits[MFONT_SIZE]
-                         | ((limited_size && val > 0) ? 0x400000 : 0));
-           }
-         else
-           score |= (val > 3 ? 3 : val) << font_score_shift_bits[prop];
-       }
+      if (font->property[i])
+       p += sprintf (p, "-%X", font->property[i]);
+      else
+       *p++ = '-';
     }
-  return score;
+  if (font->size)
+    p += sprintf (p, "-%X", font->size);
+  if (capability_len > 0)
+    {
+      *p++ = '-';
+      memcpy (p, MSYMBOL_NAME (font->capability), capability_len);
+      p += capability_len;
+    }
+  if (file_len > 0)
+    {
+      *p++ = '-';
+      memcpy (p, MSYMBOL_NAME (font->file), file_len);
+      p += file_len;
+    }      
+  id = msymbol__with_len (buf, p - buf);
+  SAFE_FREE (buf);
+  return id;
 }
 
-
 /** Return 1 iff FONT matches SPEC.  */
 
 int
 mfont__match_p (MFont *font, MFont *spec, int prop)
 {
+  if (spec->capability != font->capability
+      && spec->capability != Mnil && font->capability != Mnil)
+    return 0;
+  if (spec->file != font->file
+      && spec->file != Mnil && font->file != Mnil)
+    return 0;
   for (; prop >= 0; prop--)
     if (spec->property[prop] && font->property[prop]
        && font->property[prop] != spec->property[prop])
@@ -997,6 +1174,43 @@ mfont__match_p (MFont *font, MFont *spec, int prop)
   return 1;
 }
 
+/* Merge SRC into DST.  If error_on_conflict is nonzero and a font
+   property differs in SRC and DST, return -1.  */
+
+int
+mfont__merge (MFont *dst, MFont *src, int error_on_conflict)
+{
+  int i;
+
+  for (i = 0; i < MFONT_PROPERTY_MAX; i++)
+    {
+      if (! dst->property[i])
+       dst->property[i] = src->property[i];
+      else if (error_on_conflict
+              && src->property[i]
+              && dst->property[i] != src->property[i])
+       return -1;
+    }
+  if (! dst->size)
+    dst->size = src->size;
+  else if (error_on_conflict
+          && src->size
+          && dst->size != src->size)
+    return -1;
+  if (dst->capability == Mnil)
+    dst->capability = src->capability;
+  else if (error_on_conflict
+          && src->capability
+          && dst->capability != src->capability)
+    return -1;
+  if (dst->file == Mnil)
+    dst->file = src->file;
+  else if (error_on_conflict
+          && src->file
+          && dst->file != src->file)
+    return -1;
+  return 0;
+}
 
 void
 mfont__set_spec_from_face (MFont *spec, MFace *face)
@@ -1005,10 +1219,13 @@ mfont__set_spec_from_face (MFont *spec, MFace *face)
 
   for (i = 0; i <= MFONT_ADSTYLE; i++)
     mfont__set_property (spec, i, face->property[i]);
-  /* The value 1 is "iso8859-1".  */
-  spec->property[MFONT_REGISTRY] = 1;
-  spec->property[MFONT_SIZE] = (int) (face->property[MFACE_SIZE]);
+  spec->property[MFONT_REGISTRY] = 0;
   spec->property[MFONT_RESY] = 0;
+  spec->size = (int) (face->property[MFACE_SIZE]);
+  spec->type = MFONT_TYPE_SPEC;
+  spec->source = MFONT_SOURCE_UNDECIDED;
+  spec->file = spec->capability = Mnil;
+  spec->encoding = NULL;
 }
 
 
@@ -1018,6 +1235,7 @@ mfont__set_spec_from_plist (MFont *spec, MPlist *plist)
   int i;
   MSymbol spec_list[MFONT_REGISTRY + 1];
   MSymbol registry;
+  char *reg;
 
   MFONT_INIT (spec);
   memset (spec_list, 0, sizeof spec_list);
@@ -1028,109 +1246,181 @@ mfont__set_spec_from_plist (MFont *spec, MPlist *plist)
       spec_list[i] = MPLIST_SYMBOL (plist);
     }
   registry = spec_list[i - 1];
+  if (i > 1 && registry != Mnil)
+    {
+      reg = MSYMBOL_NAME (registry);
+      if (reg[0] == ':')
+       {
+         mfont__get_capability (registry);
+         spec->capability = registry;
+         registry = spec_list[i - 2];
+         i--;
+       }
+    }
   mfont__set_property (spec, MFONT_REGISTRY, registry);
   for (i -= 2; i >= 0; i--)
     mfont__set_property (spec, i, spec_list[i]);
+  spec->type = MFONT_TYPE_SPEC;
+
   return registry;
 }
 
-MRealizedFont *
-mfont__select (MFrame *frame, MFont *spec, MFont *request, int limited_size,
-              MSymbol layouter)
+
+MFont *
+mfont__select (MFrame *frame, MFont *font, int max_size)
+{
+  MFontDriver *driver;
+
+  if (font->type == MFONT_TYPE_FAILURE)
+    return NULL;
+  if (font->type != MFONT_TYPE_SPEC)
+    return font;
+  if (font->source == MFONT_SOURCE_UNDECIDED)
+    {
+      if (font->file != Mnil || font->capability != Mnil)
+       font->source = MFONT_SOURCE_FT;
+      else if (font->property[MFONT_REGISTRY])
+       {
+         MSymbol registry = FONT_PROPERTY (font, MFONT_REGISTRY);
+         char *reg = MSYMBOL_NAME (registry);
+
+         if (strncmp (reg, "unicode-", 8) == 0
+             || strncmp (reg, "apple-roman", 11) == 0
+             || (reg[0] >= '0' && reg[0] <= '9' && reg[1] == '-'))
+           font->source = MFONT_SOURCE_FT;
+       }
+    }
+  if (font->source != MFONT_SOURCE_FT)
+    {
+      driver = mplist_get (frame->font_driver_list, Mx);
+      if (driver)
+       return (driver->select) (frame, font, max_size);
+    }
+  driver = mplist_get (frame->font_driver_list, Mfreetype);
+  if (! driver)
+    return NULL;
+  return (driver->select) (frame, font, max_size);
+}
+
+
+int
+mfont__available (MFrame *frame, MFont *font)
+{
+  return -1;
+}
+
+static int
+compare_font_score (const void *e1, const void *e2)
+{
+  return (((MFontScore *) e1)->score > ((MFontScore *) e2)->score);
+}
+
+void
+mdebug_dump_font_list (MFontList *font_list)
 {
-  MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
-  MPlist *plist;
-  MRealizedFont *best;
   int i;
-  int mdebug_mask = MDEBUG_FONT;
 
-  if (registry == Mnil)
-    registry = Mt;
+  for (i = 0; i < font_list->nfonts; i++)
+    {
+      fprintf (stderr, "%04X - ", font_list->fonts[i].score);
+      mdebug_dump_font (font_list->fonts[i].font);
+      fprintf (stderr, "\n");
+    }
+}
 
-  MPLIST_DO (plist, frame->realized_font_list)
+MFontList *
+mfont__list (MFrame *frame, MFont *spec, MFont *request, int max_size)
+{
+  MFontList *list;
+  MSymbol id = mfont__id (spec);
+  MPlist *pl, *p;
+  int num, i;
+
+  pl = msymbol_get (id, M_font_list);
+  if (pl)
+    num = (int) msymbol_get (id, M_font_list_len);
+  else
     {
-      best = MPLIST_VAL (plist);
-      if (MPLIST_KEY (plist) == registry
-         && ! memcmp (&best->spec, spec, sizeof (MFont))
-         && ! memcmp (&best->request, request, sizeof (MFont)))
+      pl = mplist ();
+      num = 0;
+      MPLIST_DO (p, frame->font_driver_list)
        {
-         if (best->layouter != layouter)
+         if (spec->source == MFONT_SOURCE_X ? MPLIST_KEY (p) == Mx
+             : spec->source == MFONT_SOURCE_FT ? MPLIST_KEY (p) == Mfreetype
+             : 1)
            {
-             MRealizedFont *copy;
-
-             MSTRUCT_MALLOC (copy, MERROR_FONT);
-             *copy = *best;
-             copy->layouter = layouter;
-             mplist_add (frame->realized_font_list, registry, copy);
-             if (copy->info)
-               M17N_OBJECT_REF (copy->info);
-             best = copy;
+             MFontDriver *driver = MPLIST_VAL (p);
+             num += (driver->list) (frame, pl, spec, 0);
            }
-         return best;
        }
+      msymbol_put (id, M_font_list, pl);
+      M17N_OBJECT_UNREF (pl);
+      msymbol_put (id, M_font_list_len, (void *) num);
     }
+  
+  if (num == 0)
+    return NULL;
 
-  MDEBUG_PUSH_TIME ();
-  best = NULL;
-  MPLIST_DO (plist, frame->font_driver_list)
+  MSTRUCT_MALLOC (list, MERROR_FONT);
+  MTABLE_MALLOC (list->fonts, num, MERROR_FONT);
+  for (i = 0; num > 0; num--, pl = MPLIST_NEXT (pl))
     {
-      MFontDriver *driver = MPLIST_VAL (plist);
-      MRealizedFont *this
-       = (driver->select) (frame, spec, request, limited_size);
+      MFont *font = MPLIST_VAL (pl);
 
-      if (this)
+      if (max_size == 0
+         || font->size == 0
+         || font->size < max_size)
        {
-         this->driver = driver;
-         if (! best
-             || this->score < best->score)
-           {
-             if (best)
-               mfont__free_realized (best);
-             best = this;
-             if (this->score == 0)
-               break;
-           }
-         else
-           mfont__free_realized (this);
+         list->fonts[i].font = font;
+         list->fonts[i].score
+           = spec == request ? 0 : font_score (font, request);
+         i++;
        }
     }
-
-  if (mdebug__flag & mdebug_mask)
+  if (i == 0)
     {
-      char buf1[256], buf2[256];
-      MFont font = *spec;
-
-      for (i = 0; i < MFONT_PROPERTY_MAX; i++)
-       if (! font.property[i])
-         font.property[i] = request->property[i];
-      gen_font_name (buf2, &font);
-
-      if (best)
-       MDEBUG_PRINT_TIME ("FONT", 
-                          (stderr, " to select <%s> (%x)from <%s>.",
-                           gen_font_name (buf1, &best->font),
-                           best->score,
-                           buf2));
-      else
-       MDEBUG_PRINT_TIME ("FONT", (stderr, " to fail to find <%s>.", buf2));
-      MDEBUG_POP_TIME ();
+      free (list->fonts);
+      free (list);
+      return NULL;
     }
-
-  if (! best)
-    return NULL;
-  best->layouter = layouter;
-  mplist_add (frame->realized_font_list, registry, best);
-  return best;
+  list->nfonts = i;
+  if (spec != request)
+    qsort (list->fonts, i, sizeof (MFontScore), compare_font_score);
+  list->object = *spec;
+  mfont__merge (&list->object, request, 0);
+  list->object.type = MFONT_TYPE_OBJECT;
+  return list;
 }
 
+/** Open a font specified in FONT.  */
 
-/** Open a font specified in RFONT.  Return 0 if successfully
-    opened, otherwise return -1.  */
-
-int
-mfont__open (MRealizedFont *rfont)
+MRealizedFont *
+mfont__open (MFrame *frame, MFont *font, MFont *spec)
 {
-  return (rfont->driver->open) (rfont);
+  MFontDriver *driver;
+  MRealizedFont *rfont;
+
+  if (font->source == MFONT_SOURCE_UNDECIDED)
+    MFATAL (MERROR_FONT);
+  if (font->type != MFONT_TYPE_OBJECT)
+    MFATAL (MERROR_FONT);
+  for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
+       rfont = rfont->next)
+    {
+      driver = rfont->driver;
+      if (rfont->font == font
+         && mplist_find_by_value (frame->font_driver_list, driver))
+       break;
+    }
+
+  if (! rfont)
+    {
+      driver = mplist_get (frame->font_driver_list,
+                          font->source == MFONT_SOURCE_X ? Mx : Mfreetype);
+      if (! driver)
+       MFATAL (MERROR_FONT);
+    }
+  return (driver->open) (frame, font, spec, rfont);
 }
 
 void
@@ -1152,8 +1442,7 @@ mfont__resize (MFont *spec, MFont *request)
            resize = (MFontResize *) MPLIST_VAL (plist);
            if (mfont__match_p (spec, &resize->spec, MFONT_ADSTYLE))
              {
-               request->property[MFONT_SIZE]
-                 = request->property[MFONT_SIZE] * resize->resize / 100;
+               request->size = request->size * resize->resize / 100;
                return;
              }
            plist = MPLIST_NEXT (plist);
@@ -1165,26 +1454,65 @@ mfont__resize (MFont *spec, MFont *request)
 }
 
 
+int
+mfont__has_char (MFrame *frame, MFont *font, MFont *spec, int c)
+{
+  MFontEncoding *encoding;
+  unsigned code;
+  MFontDriver *driver;
+
+  if (font->source == MFONT_SOURCE_UNDECIDED)
+    MFATAL (MERROR_FONT);
+  encoding = (font->encoding ? font->encoding : find_encoding (font));
+  if (! encoding->encoding_charset)
+    return 0;
+  if (encoding->repertory_charset)
+    {
+      code = ENCODE_CHAR (encoding->repertory_charset, c);
+      return (code != MCHAR_INVALID_CODE);
+    }
+  code = ENCODE_CHAR (encoding->encoding_charset, c);
+  if (code == MCHAR_INVALID_CODE)
+    return 0;
+  if (font->type == MFONT_TYPE_REALIZED)
+    driver = ((MRealizedFont *) font)->driver;
+  else
+    {
+      driver = mplist_get (frame->font_driver_list,
+                          font->source == MFONT_SOURCE_X ? Mx : Mfreetype);
+      if (! driver)
+       MFATAL (MERROR_FONT);
+    }
+  return (driver->has_char) (frame, font, spec, c, code);
+}
+
 unsigned
-mfont__encode_char (MRealizedFont *rfont, int c)
+mfont__encode_char (MFrame *frame, MFont *font, MFont *spec, int c)
 {
   MFontEncoding *encoding;
   unsigned code;
+  MFontDriver *driver;
 
-  if (rfont->layouter != Mnil)
-    return mfont__flt_encode_char (rfont->layouter, c);
-  if (! rfont->encoding)
-    rfont->encoding = find_encoding (&rfont->font);
-  encoding = rfont->encoding;
+  if (font->source == MFONT_SOURCE_UNDECIDED)
+    MFATAL (MERROR_FONT);
+  encoding = (font->encoding ? font->encoding : find_encoding (font));
   if (! encoding->encoding_charset)
     return MCHAR_INVALID_CODE;
-  if (encoding->repertory_charset
-      && ENCODE_CHAR (encoding->repertory_charset, c) == MCHAR_INVALID_CODE)
-    return MCHAR_INVALID_CODE;
+  if (encoding->repertory_charset)
+    return (ENCODE_CHAR (encoding->repertory_charset, c));
   code = ENCODE_CHAR (encoding->encoding_charset, c);
   if (code == MCHAR_INVALID_CODE)
     return MCHAR_INVALID_CODE;
-  return (rfont->driver->encode_char) (rfont, code);
+  if (font->type == MFONT_TYPE_REALIZED)
+    driver = ((MRealizedFont *) font)->driver;
+  else
+    {
+      driver = mplist_get (frame->font_driver_list,
+                          font->source == MFONT_SOURCE_X ? Mx : Mfreetype);
+      if (! driver)
+       MFATAL (MERROR_FONT);
+    }
+  return (driver->encode_char) (frame, font, spec, code);
 }
 
 void
@@ -1207,6 +1535,8 @@ mfont__get_metric (MGlyphString *gstring, int from, int to)
 }
 
 
+/* KEY <= MFONT_REGISTRY */
+
 void
 mfont__set_property (MFont *font, enum MFontProperty key, MSymbol val)
 {
@@ -1229,14 +1559,14 @@ mfont__set_property (MFont *font, enum MFontProperty key, MSymbol val)
 
 void
 mfont__set_spec (MFont *font, MSymbol *attrs,
-                unsigned short size, unsigned short resy)
+                unsigned size, unsigned short resy)
 {
   int i;
 
   for (i = 0; i <= MFONT_REGISTRY; i++)
     mfont__set_property (font, i, attrs[i]);
-  font->property[MFONT_SIZE] = size;
   font->property[MFONT_RESY] = resy;
+  font->size = size;
 }
 
 int
@@ -1261,6 +1591,171 @@ mfont__encoding_list (void)
   return font_encoding_list;
 }
 
+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 */
+  free (cap);
+}
+
+MFontCapability *
+mfont__get_capability (MSymbol sym)
+{
+  MFontCapability *cap = msymbol_get (sym, M_font_capability);
+  char *str, *p, *endp;
+  int i;
+
+  if (cap)
+    return cap;
+  str = MSYMBOL_NAME (sym);
+  if (str[0] != ':')
+    return NULL;
+  M17N_OBJECT (cap, free_font_capability, MERROR_FONT);
+  msymbol_put (sym, M_font_capability, cap);
+  M17N_OBJECT_UNREF (cap);
+  endp = str + MSYMBOL_NAMELEN (sym);
+  while (str < endp)
+    {
+      if (*str++ != ':')
+       continue;
+#ifdef HAVE_OTF
+      if (str[0] == 'o' && str[1] == 't' && str[2] == 'f' && str[3] == '=')
+       {
+         str += 4;
+         for (i = 0, p = str; i < 4 && p < endp; i++, p++);
+         if (i < 4)
+           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;
+                 break;
+               }
+             cap->langsys_tag = OTF_tag (str);
+           }
+         else
+           cap->langsys_tag = 0;
+
+         for (i = 0; i < MFONT_OTT_MAX; i++)
+           cap->features[i].nfeatures = -1;
+
+         while (*p == '=' || *p == '+')
+           {
+             int idx = *p == '=' ? MFONT_OTT_GSUB : MFONT_OTT_GPOS;
+
+             str = ++p;
+             while (p < endp && *p != '+') p++;
+             if (str < p)
+               {
+                 int n;
+                 /* We never have more than (p - str) tags.  */
+                 OTF_Tag *tags = alloca (sizeof (OTF_Tag) * (p - str));
+                 char *p0;
+
+                 cap->features[idx].str = malloc (p - str + 1);
+                 for (i = n = 0, p0 = str; str + i < p; i++)
+                   {
+                     cap->features[idx].str[i] = str[i];
+                     if (str[i] == ',' || str + i + 1 == p)
+                       {
+                         if (*p0 == '*')
+                           tags[n] = 0;
+                         else if (*p0 == '~')
+                           tags[n] = OTF_tag (p0 + 1) | 0x80000000;
+                         else
+                           tags[n] = OTF_tag (p0);
+                         n++;
+                         p0 = str + i + 1;
+                       }
+                   }
+                 cap->features[idx].str[i] = '\0';
+                 cap->features[idx].nfeatures = n;
+                 if (n > 0)
+                   {
+                     int size = sizeof (OTF_Tag) * n;
+
+                     cap->features[idx].tags = malloc (size);
+                     memcpy (cap->features[idx].tags, tags, size);
+                   }
+               }
+             else
+               {
+                 cap->features[idx].str = NULL;
+                 cap->features[idx].nfeatures = 0;
+               }
+           }
+
+         for (i = 0; i < MFONT_OTT_MAX; i++)
+           if (cap->features[i].nfeatures < 0)
+             {
+               cap->features[i].str = strdup ("*");
+               cap->features[i].nfeatures = 1;
+               cap->features[i].tags = malloc (sizeof (OTF_Tag));
+               cap->features[i].tags[0] = 0;
+             }
+         str = p;
+         continue;
+       }
+#endif /* HAVE_OTF */
+      if (str[0] == 'l' && str[1] == 'a' && str[2] == 'n' && str[3] == 'g'
+         && str[4] == '=')
+       {
+         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;
+             }
+         if (str < p)
+           cap->lang[count++] = msymbol__with_len (str, p - str);
+         cap->lang[count] = Mnil;
+         str = p;
+       }
+      else if (str[0] == 's' && str[1] == 'c' && str[2] == 'r' && str[3] == 'i'
+              && str[4] == 'p' && str[5] == 't' && str[6] == '=')
+       {
+         str += 7;
+         for (p = str; p < endp && *p != ':'; p++);
+         if (str < p)
+           cap->script = msymbol__with_len (str, p - str);
+         str = p;
+       }
+    }
+  return cap;
+}
+
 /*** @} */
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
@@ -1407,6 +1902,21 @@ MSymbol Mregistry;
 MSymbol Msize;
 
 /***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 ¥Õ¥©¥ó¥È¥Õ¥¡¥¤¥ë¤ò»ØÄꤹ¤ë¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼.
+    
+    ÊÑ¿ô #Mfontfile ¤Ï <tt>"fontfile"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤Ç¤¢
+    ¤ê¡¢¥Õ¥©¥ó¥È¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£Ãͤϡ¢¥Õ¥©¥ó¥È¥Õ¥¡¥¤
+    ¥ë̾¤ò̾Á°¤È¤·¤Æ»ý¤Ä¤È¤¹¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£ */
+
+MSymbol Mfontfile;
+
+/***en
     @brief Key of font property specifying resolution.
 
     The variable #Mresolution is a symbol of name <tt>"resolution"</tt> and
@@ -1633,7 +2143,8 @@ mfont_unparse_name (MFont *font, MSymbol format)
 #ifdef HAVE_FONTCONFIG
   else if (format == Mfontconfig)
     name = mfont__ft_unparse_name (font);
-#endif
+
+#endif /* HAVE_FONTCONFIG */
   else
     MERROR (MERROR_FONT, NULL);
   return name;
@@ -1669,11 +2180,11 @@ mfont_copy (MFont *font)
     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 Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype.
 
     @return
     If $KEY is @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch, @c
-    Madstyle, or @c Mregistry, this function returns the
+    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
@@ -1685,20 +2196,21 @@ mfont_copy (MFont *font)
 /***ja
     @brief ¥Õ¥©¥ó¥È¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÆÀ¤ë.
 
-    ´Ø¿ô mfont_get_prop () ¤Ï¥Õ¥©¥ó¥È $FONT ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬ 
-    $KEY ¤Ç¤¢¤ë¤â¤Î¤ÎÃͤòÊÖ¤¹¡£$KEY ¤Ï°Ê²¼¤Î¥·¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
+    ´Ø¿ô mfont_get_prop () ¤Ï¥Õ¥©¥ó¥È $FONT ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¤¦¤Á¡¢¥­¡¼¤¬
+    $KEY ¤Ç¤¢¤ë¤â¤Î¤ÎÃͤòÊÖ¤¹¡£$KEY ¤Ï°Ê²¼¤Î¥·¥ó¥Ü¥ë¤Î¤¤¤º¤ì¤«¤Ç¤Ê¤±¤ì
+    ¤Ð¤Ê¤é¤Ê¤¤¡£
 
        @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch,
-       @c Madstyle, @c Mregistry, @c Msize, @c Mresolution.
+       @c Madstyle, @c Mregistry, @c Msize, @c Mresolution, @c Mtype.
 
     @return 
     $KEY ¤¬ @c Mfamily, @c Mweight, @c Mstyle, @c Mstretch, @c
-    Madstyle, @c Mregistry ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ì¤Ð¡¢ÁêÅö¤¹¤ëÃͤò¥·¥ó¥Ü¥ë¤È¤·¤ÆÊÖ¤¹¡£
-    ¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¾ì¹ç¤Ë¤Ï @c Mnil ¤òÊÖ¤¹¡£
-    $KEY ¤¬ @c Msize ¤¢¤ë¤¤¤Ï @c Mresolution 
-    ¤Î¾ì¹ç¤Ë¤Ï¡¢ÁêÅö¤¹¤ëÃͤò¤ÏÀ°¿ôÃͤȤ·¤ÆÊÖ¤¹¡£¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¾ì¹ç¤Ë¤Ï 0 
-    ¤òÊÖ¤¹¡£$KEY ¤¬¤½¤ì°Ê³°¤Î¤â¤Î¤Ç¤¢¤ì¤Ð¡¢@c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô 
-    #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
+    Madstyle, @c Mregistry, @c Mtype ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ì¤Ð¡¢ÁêÅö¤¹¤ëÃͤò¥·
+    ¥ó¥Ü¥ë¤È¤·¤ÆÊÖ¤¹¡£¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤¾ì¹ç¤Ë¤Ï @c
+    Mnil ¤òÊÖ¤¹¡£$KEY ¤¬ @c Msize ¤¢¤ë¤¤¤Ï @c Mresolution ¤Î¾ì¹ç¤Ë¤Ï¡¢
+    ÁêÅö¤¹¤ëÃͤò¤ÏÀ°¿ôÃͤȤ·¤ÆÊÖ¤¹¡£¥Õ¥©¥ó¥È¤¬¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ò»ý¤¿¤Ê¤¤
+    ¾ì¹ç¤Ë¤Ï 0 ¤òÊÖ¤¹¡£$KEY ¤¬¤½¤ì°Ê³°¤Î¤â¤Î¤Ç¤¢¤ì¤Ð¡¢@c NULL ¤òÊÖ¤·¡¢
+    ³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
 
 void *
 mfont_get_prop (MFont *font, MSymbol key)
@@ -1719,7 +2231,7 @@ mfont_get_prop (MFont *font, MSymbol key)
     return (void *) FONT_PROPERTY (font, MFONT_REGISTRY);
   if (key == Msize)
     {
-      int size = font->property[MFONT_SIZE];
+      int size = font->size;
       return (void *) size;
     }
   if (key == Mresolution)
@@ -1727,7 +2239,8 @@ mfont_get_prop (MFont *font, MSymbol key)
       int resy = font->property[MFONT_RESY];
       return (void *) resy;
     }
-
+  if (key == Mfontfile)
+    return (void *) font->file;
   MERROR (MERROR_FONT, NULL);
 }
 
@@ -1777,12 +2290,16 @@ mfont_put_prop (MFont *font, MSymbol key, void *val)
   else if (key == Msize)
     {
       unsigned size = (unsigned) val;
-      font->property[MFONT_SIZE] = size;
+      font->size = size;
     }
   else if (key == Mresolution)
     {
       unsigned resy = (unsigned) val;
-      font->property[MFONT_RESY] =  resy;
+      font->property[MFONT_RESY] = resy;
+    }
+  else if (key == Mfontfile)
+    {
+      font->file = (MSymbol) val;
     }
   else
     MERROR (MERROR_FONT, -1);
@@ -1880,7 +2397,7 @@ int
 mfont_set_selection_priority (MSymbol *keys)
 {
   int priority[FONT_SCORE_PRIORITY_SIZE];
-  int i, j;
+  int i, j, shift;
 
   for (i = 0; i < FONT_SCORE_PRIORITY_SIZE; i++, keys++)
     {
@@ -1911,6 +2428,20 @@ mfont_set_selection_priority (MSymbol *keys)
     }
   for (i = 0; i < FONT_SCORE_PRIORITY_SIZE; i++)
     font_score_priority[i] = priority[i];
+  /* Here, SHIFT starts from 1, not 0.  This is because the lowest bit
+     of a score is a flag for a scalable font (see the documentation
+     of font_score).  */
+  i = FONT_SCORE_PRIORITY_SIZE - 1;
+  for (shift = 1; i >= 0; i--)
+    {
+      font_score_shift_bits[font_score_priority[i]] = shift;
+      if (font_score_priority[i] == MFONT_SIZE)
+       shift += 16;
+      else if (font_score_priority[i] <= MFONT_FAMILY)
+       shift++;
+      else
+       shift += 2;
+    }
   return 0;
 }
 
@@ -1937,20 +2468,28 @@ mfont_set_selection_priority (MSymbol *keys)
     */
 
 MFont *
-mfont_find (MFrame *frame, MFont *spec, int *score, int limited_size)
+mfont_find (MFrame *frame, MFont *spec, int *score, int max_size)
 {
   MFont spec_copy;
-  MRealizedFont *rfont;
+  MFont *best;
+  MFontList *list;
 
   MFONT_INIT (&spec_copy);
+  spec_copy.property[MFONT_FAMILY] = spec->property[MFONT_FAMILY];
   spec_copy.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
+  spec_copy.capability = spec->capability;
+  spec_copy.file = spec->file;
 
-  rfont = mfont__select (frame, &spec_copy, spec, limited_size, Mnil);
-  if (!rfont)
+  list = mfont__list (frame, &spec_copy, spec, max_size);
+  if (! list)
     return NULL;
+
+  best = list->fonts[0].font;
   if (score)
-    *score = rfont->score;
-  return &rfont->font;
+    *score = list->fonts[0].score;
+  free (list->fonts);
+  free (list);
+  return best;
 }
 
 /*=*/
@@ -2089,7 +2628,7 @@ mfont_resize_ratio (MFont *font)
   MFont request = *font;
 
   mfont__resize (font, &request);
-  return (font->property[MFONT_SIZE] * 100 / request.property[MFONT_SIZE]);
+  return (font->size * 100 / request.size);
 }
 
 /*=*/
@@ -2098,7 +2637,7 @@ mfont_resize_ratio (MFont *font)
     @brief Get a list of fonts.
 
     The mfont_list () functions returns a list of fonts available on
-    frame $FRAME.  $FONT, if not @c Mnil, limits fonts to ones
+    frame $FRAME.  $FONT, if not NULL, limits fonts to ones
     that match with $FONT.  $LANGUAGE, if not @c Mnil, limits fonts to
     ones that support $LANGUAGE.  $MAXNUM, if greater than 0, limits
     the number of fonts.
@@ -2113,7 +2652,7 @@ mfont_resize_ratio (MFont *font)
     @brief ¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÆÀ¤ë
 
     ´Ø¿ô mfont_list () ¤Ï¥Õ¥ì¡¼¥à $FRAME ¤ÇÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£
-    $FONT ¤¬ @c Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$FONT ¤È¹çÃפ¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£
+    $FONT ¤¬ NULL ¤Ç¤Ê¤±¤ì¤Ð¡¢$FONT ¤È¹çÃפ¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£
     $LANGUAGE ¤¬ @c Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤ò¥µ¥Ý¡¼¥È¤¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£
     $MAXNUM ¤Ï¡¢0 ¤è¤êÂ礭¤¤¾ì¹ç¤Ë¤Ï¡¢ÊÖ¤¹¥Õ¥©¥ó¥È¤Î¿ô¤Î¾å¸Â¤Ç¤¢¤ë¡£
 
@@ -2125,26 +2664,94 @@ mfont_resize_ratio (MFont *font)
 MPlist *
 mfont_list (MFrame *frame, MFont *font, MSymbol language, int maxnum)
 {
-  MPlist *plist = mplist (), *p;
-  int num = 0;
+  MPlist *plist, *pl;
+  MFontList *font_list;
+  int i;
   
-  MPLIST_DO (p, frame->font_driver_list)
+  if (language != Mnil)
     {
-      MFontDriver *driver = MPLIST_VAL (p);
+      /* ":lang=XXX" */
+      char *buf = alloca (MSYMBOL_NAMELEN (language) + 7);
 
-      num += (driver->list) (frame, plist, font, language,
-                            maxnum > 0 ? maxnum - num : 0);
-      if (maxnum > 0 && num >= maxnum)
-       break;
+      sprintf (buf, ":lang=%s", MSYMBOL_NAME (language));
+      font->capability = msymbol (buf);
+    }
+
+  font_list = mfont__list (frame, font, font, 0);
+  if (! font_list)
+    return NULL;
+  if (font_list->nfonts == 0)
+    {
+      free (font_list);
+      return NULL;
     }
-  if (MPLIST_TAIL_P (plist))
+
+  plist = pl = mplist ();
+  for (i = 0; i < font_list->nfonts; i++)
     {
-      M17N_OBJECT_UNREF (plist);
-      plist = NULL;
+      MSymbol family = FONT_PROPERTY (font_list->fonts[i].font, MFONT_FAMILY);
+
+      if (family != Mnil)
+       pl = mplist_add (pl, family, font_list->fonts[i].font);
     }
+  free (font_list);
   return plist;
 }
 
+
+/*=*/
+
+/***en
+    @brief Check if FONT can be used for SCRIPT and LANGUAGE in FONTSET.
+ */
+
+int
+mfont_check (MFrame *frame, MFontset *fontset, MFont *font,
+            MSymbol script, MSymbol language)
+{
+  MFont spec;
+  MPlist *plist, *pl;
+  int result = 0;
+
+  if (! fontset)
+    fontset = frame->face->property[MFACE_FONTSET];
+
+  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)
+    {
+      spec = *(MFont *) MPLIST_VAL (pl);         
+      if (mfont__merge (&spec, font, 1) >= 0
+         && mfont__select (frame, &spec, 0))
+       {
+         result = 1;
+         break;
+       }
+    }
+  M17N_OBJECT_UNREF (plist);
+  return result;
+}
+
 /*** @} */
 
 /*** @addtogroup m17nDebug */
@@ -2182,29 +2789,6 @@ mdebug_dump_font (MFont *font)
   return font;
 }
 
-void
-mdebug_dump_font_list (MFrame *frame, MSymbol family, MSymbol lang)
-{
-  MPlist *plist, *p;
-
-  if (family == Mnil)
-    plist = mfont_list (frame, NULL, lang, 0);
-  else
-    {
-      MFont font;
-
-      MFONT_INIT (&font);
-      mfont__set_property (&font, MFONT_FAMILY, family);
-      plist = mfont_list (frame, &font, lang, 0);
-    }
-  MPLIST_DO (p, plist)
-    {
-      mdebug_dump_font (MPLIST_VAL (p));
-      fprintf (stderr, "\n");
-    }
-  M17N_OBJECT_UNREF (plist);
-}
-
 /*** @} */
 
 /*