*** empty log message ***
[m17n/m17n-lib.git] / src / font.c
index 194af7e..e4de266 100644 (file)
 
     The m17n library, if configured to use the FreeType library,
     supports all fonts that can be handled by the FreeType library.
-    The variable #mfont_freetype_path is initialized properly accoding
+    The variable #mfont_freetype_path is initialized properly according
     to the configuration of the m17n library and the environment
     variable @c M17NDIR.  See the documentation of the variable for
     details.
 
+    If the m17n library is configured to use the fontconfig librray,
+    in addition to #mfont_freetype_path, all fonts available via
+    fontconfig are supported.
+
     The family name of a FreeType font corresponds to the family
     property.  Style names of FreeType fonts correspond to the weight,
     style, and stretch properties as below.
     Narrow Bold Italic  bold    i       condensed
     Black               black   r       normal
     Black Italic        black   i       normal
-    Oblique            medium  o       normal
-    BoldOblique                bold    o       normal
+    Oblique             medium  o       normal
+    BoldOblique         bold    o       normal
 @endverbatim
 
     Style names not listed in the above table are treated as
     adstyle ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢serif, sans-serif Åù¤ÎÃê¾ÝŪ¤Ê¥Õ¥©¥ó¥È¥Õ¥¡
     ¥ß¥ê¡¼¤Ë´Ø¤¹¤ë¾ðÊó¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
 
-    registry ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢iso10646, iso8895-1 ¤Î¥ì¥¸¥¹¥È¥ê¾ðÊó¤ò
+    registry ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢iso10646, iso8895-1 Åù¤Î¥ì¥¸¥¹¥È¥ê¾ðÊó¤ò
     ¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
 
     size ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϡ¢¥Õ¥©¥ó¥È¤Î¥Ç¥¶¥¤¥ó¥µ¥¤¥º¤òɽ¤ï¤¹À°¿ôÃͤǤ¢
     #mfont_freetype_path ¤Ï m17n ¥é¥¤¥Ö¥é¥ê¤ÎÀßÄê¤È´Ä¶­ÊÑ¿ô @c M17NDIR 
     ¤Ë±þ¤¸¤Æ½é´ü²½¤µ¤ì¤ë¡£¾ÜºÙ¤ÏÊÑ¿ô¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£
 
+    ¤â¤· m17n ¥é¥¤¥Ö¥é¥ê¤¬ fontconfig ¥é¥¤¥Ö¥é¥ê¤ò»È¤¦¤è¤¦¤ËÀßÄꤵ¤ì¤¿
+    ¾ì¹ç¤Ë¤Ï¡¢#mfont_freetype_path ¤Ë²Ã¤¨¤Æ¡¢ fontconfig ¤Ç»ÈÍѲÄǽ¤Ê¥Õ¥©
+    ¥ó¥È¤â¤¹¤Ù¤Æ¥µ¥Ý¡¼¥È¤µ¤ì¤ë¡£
+
     FreeType ¥Õ¥©¥ó¥È¤Î¥Õ¥¡¥ß¥ê̾¤Ï family ¥×¥í¥Ñ¥Æ¥£¤ËÂбþ¤¹¤ë¡£
     FreeType ¥Õ¥©¥ó¥È¤Î¥¹¥¿¥¤¥ë̾¤Ï¡¢²¼¤Îɽ¤Î¤è¤¦¤Ë weight, style,
     stretch ¥×¥í¥Ñ¥Æ¥£¤ËÂбþ¤¹¤ë¡£
     Narrow Bold Italic  bold    i       condensed
     Black               black   r       normal
     Black Italic        black   i       normal
-    Oblique            medium  o       normal
-    BoldOblique                bold    o       normal
+    Oblique             medium  o       normal
+    BoldOblique         bold    o       normal
 @endverbatim
 
     ¾å¤Îɽ¤Ë¸½¤ï¤ì¤Ê¤¤¥¹¥¿¥¤¥ë̾¤Ï "Regular" ¤È¤·¤Æ°·¤ï¤ì¤ë¡£
     3                   1               unicode-full
 @endverbatim
 
-    ¤·¤¿¤¬¤Ã¤Æ¡¢Æó¤Ä¤ÎÁȹ礻 (1 0) ¡¢(3 1) ¤ò»ý¤Ä¥Õ¥©¥ó¥È¤Ï¡¢¤½¤ì¤¾¤ì 
-    registry ¥×¥í¥Ñ¥Æ¥£¤¬1-0, apple-roman, 3-1, unicode-bmp ¤Ç¤¢¤ë£´¤Ä
+    ¤·¤¿¤¬¤Ã¤Æ¡¢Æó¤Ä¤ÎÁȹ礻 (1 0) ¡¢(3 1) ¤ò»ý¤Ä¥Õ¥©¥ó¥È¤Ï¡¢¤½¤ì¤¾¤ì
+    registry ¥×¥í¥Ñ¥Æ¥£¤¬ 1-0, apple-roman, 3-1, unicode-bmp ¤Ç¤¢¤ë£´¤Ä
     ¤Î¥Õ¥©¥ó¥È¥ª¥Ö¥¸¥§¥¯¥È¤ËÂбþ¤¹¤ë¡£
 
     <li> OpenType ¥Õ¥©¥ó¥È
 
-    m17n ¥é¥¤¥Ö¥é¥ê¤Ï¡¢FreeType ¥é¥¤¥Ö¥é¥ê¤È OTF ¥é¥¤¥Ö¥é¥ê¤ò»ÈÍѤ¹¤ë
-    ¤è¤¦¤ËÀßÄꤹ¤ì¤Ð¡¢¤¹¤Ù¤Æ¤Î OpenType ¥Õ¥©¥ó¥È¤ò¥µ¥Ý¡¼¥È¤¹¤ë¡£¼ÂºÝ¤Ë
-    ÍøÍѤǤ­¤ë¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤ÏFreeType ¥Õ¥©¥ó¥È¤Î¾ì¹ç¤ÈƱÍͤ˺î¤é¤ì
-    ¤ë¡£OpenType ¥Õ¥©¥ó¥È¤ò FLT (Font Layout Table) ·Ðͳ¤Ç»ÈÍѤ¹¤ë¤è¤¦
-    ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ë»ØÄꤵ¤ì¤Æ¤ª¤ê¡¢FLT ¤Ë OTF ´ØÏ¢¤Î¥³¥Þ¥ó¥É (¤¿¤È¤¨
-    ¤Ð otf:deva) ¤¬¤¢¤ì¤Ð¡¢OTF ¥é¥¤¥Ö¥é¥ê¤¬¥Õ¥©¥ó¥È¤Î OpenType ¥ì¥¤¥¢
-    ¥¦¥È¥Æ¡¼¥Ö¥ë¤Ë½¾¤Ã¤Æʸ»úÎó¤ò¥°¥ê¥Õ¥³¡¼¥ÉÎó¤ËÊÑ´¹¤·¡¢FreeType ¥é¥¤
-    ¥Ö¥é¥ê¤¬³Æ¥°¥ê¥Õ¤Î¥Ó¥Ã¥È¥Þ¥Ã¥×¥¤¥á¡¼¥¸¤òÄ󶡤¹¤ë¡£
+    m17n ¥é¥¤¥Ö¥é¥ê¤Ï¡¢FreeType ¥é¥¤¥Ö¥é¥ê¤È OTF ¥é¥¤¥Ö¥é¥ê¤ò»ÈÍѤ¹¤ë¤è
+    ¤¦¤ËÀßÄꤹ¤ì¤Ð¡¢¤¹¤Ù¤Æ¤Î OpenType ¥Õ¥©¥ó¥È¤ò¥µ¥Ý¡¼¥È¤¹¤ë¡£¼ÂºÝ¤ËÍø
+    ÍѤǤ­¤ë¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤Ï FreeType ¥Õ¥©¥ó¥È¤Î¾ì¹ç¤ÈƱÍͤ˺î¤é¤ì¤ë¡£
+    OpenType ¥Õ¥©¥ó¥È¤ò FLT (Font Layout Table) ·Ðͳ¤Ç»ÈÍѤ¹¤ë¤è¤¦¥Õ¥©
+    ¥ó¥È¥»¥Ã¥È¤Ë»ØÄꤵ¤ì¤Æ¤ª¤ê¡¢FLT ¤Ë OTF ´ØÏ¢¤Î¥³¥Þ¥ó¥É (¤¿¤È¤¨¤Ð
+    otf:deva) ¤¬¤¢¤ì¤Ð¡¢OTF ¥é¥¤¥Ö¥é¥ê¤¬¥Õ¥©¥ó¥È¤Î OpenType ¥ì¥¤¥¢¥¦¥È
+    ¥Æ¡¼¥Ö¥ë¤Ë½¾¤Ã¤Æʸ»úÎó¤ò¥°¥ê¥Õ¥³¡¼¥ÉÎó¤ËÊÑ´¹¤·¡¢FreeType ¥é¥¤¥Ö¥é¥ê
+    ¤¬³Æ¥°¥ê¥Õ¤Î¥Ó¥Ã¥È¥Þ¥Ã¥×¥¤¥á¡¼¥¸¤òÄ󶡤¹¤ë¡£
 
     </ul>
 
 #include "font.h"
 #include "face.h"
 
-MFontDriver *mfont__driver_list[MFONT_TYPE_MAX];
+MPlist *mfont__driver_list;
 
 /** Indices to font properties sorted by their priority.  */
 static int font_score_priority[] =
@@ -365,9 +373,9 @@ static char *common_weight[] =
     "light",
     "demilight",
     "book",
+    "regular",
     "normal",
     "medium",
-    "regular",
     "demibold",
     "bold",
     "extrabold",
@@ -376,7 +384,9 @@ static char *common_weight[] =
 static char *common_style[] =
   { "o",
     "i",
+    "slanted",
     "r",
+    "rslanted",
     "ri",
     "ro" };
 static char *common_stretch[] =
@@ -517,8 +527,9 @@ load_font_encoding_table ()
        encoding->repertory_name = MPLIST_SYMBOL (elt);
 
       if (registry == Mnil)
-       registry = Mt;
-      pl = mplist_add (pl, registry, encoding);
+       mplist_push (font_encoding_list, Mt, encoding);
+      else
+       pl = mplist_add (pl, registry, encoding);
       continue;
 
     warning:
@@ -599,48 +610,196 @@ find_encoding (MFont *font)
 
   if (! font_encoding_list)
     load_font_encoding_table ();
-  if (! MPLIST_TAIL_P (font_encoding_list))
-    while (1)
-      {
-       plist = font_encoding_list;
-       while (registry ? (plist = mplist_find_by_key (plist, registry))
-              : plist)
-         {
-           encoding = (MFontEncoding *) MPLIST_VAL (plist);
-           if (mfont__match_p (font, &encoding->spec, MFONT_ADSTYLE))
-             {
-               if (! encoding->encoding_charset)
-                 encoding->encoding_charset
-                   = MCHARSET (encoding->encoding_name);
-               if (! encoding->encoding_charset)
-                 {
-                   mplist_pop (plist);
-                   continue;
-                 }
-               if (encoding->repertory_name == encoding->encoding_name)
-                 encoding->repertory_charset = encoding->encoding_charset;
-               else if (encoding->repertory_name != Mnil)
-                 {
-                   encoding->repertory_charset
-                     = MCHARSET (encoding->repertory_name);
-                   if (! encoding->repertory_charset)
-                     {
-                       mplist_pop (plist);
-                       continue;
-                     }
-                 }
-               return encoding;
-             }
-           else
-             plist = MPLIST_NEXT (plist);
-         }
-       if (registry == Mnil || registry == Mt)
-         break;
-       registry = Mt;
-      }
+  plist = font_encoding_list;
+  while (! MPLIST_TAIL_P (plist))
+    {
+      encoding = (MFontEncoding *) MPLIST_VAL (plist);
+      if (mfont__match_p (font, &encoding->spec, MFONT_REGISTRY))
+       {
+         if (encoding->encoding_name != Mnil
+             && ! encoding->encoding_charset)
+           {
+             encoding->encoding_charset = MCHARSET (encoding->encoding_name);
+             if (! encoding->encoding_charset)
+               {
+                 mplist_pop (plist);
+                 continue;
+               }
+           }
+         if (encoding->repertory_name == encoding->encoding_name)
+           encoding->repertory_charset = encoding->encoding_charset;
+         else if (encoding->repertory_name != Mnil)
+           {
+             encoding->repertory_charset
+               = MCHARSET (encoding->repertory_name);
+             if (! encoding->repertory_charset)
+               {
+                 mplist_pop (plist);
+                 continue;
+               }
+           }
+         return encoding;
+       }
+
+      if (registry && MPLIST_KEY (plist) != Mt)
+       {
+         plist = mplist_find_by_key (plist, registry);
+         if (! plist)
+           break;
+       }
+      else
+       plist = MPLIST_NEXT (plist);
+    }
   return &default_encoding;
 }
 
+/* XLFD parser/generator */
+
+/** Indices to each field of split font name.  */
+
+enum xlfd_field_idx
+  {
+    XLFD_FOUNDRY,
+    XLFD_FAMILY,
+    XLFD_WEIGHT,
+    XLFD_SLANT,
+    XLFD_SWIDTH,
+    XLFD_ADSTYLE,
+    XLFD_PIXEL,
+    XLFD_POINT,
+    XLFD_RESX,
+    XLFD_RESY,
+    XLFD_SPACING,
+    XLFD_AVGWIDTH,
+    XLFD_REGISTRY,             /* This contains ENCODING.  */
+    /* anchor */
+    XLFD_FIELD_MAX
+  };
+
+static int
+xlfd_parse_name (char *name, MFont *font)
+{
+  char *field[XLFD_FIELD_MAX];
+  unsigned short size, resy, avgwidth;
+  MSymbol attrs[MFONT_PROPERTY_MAX];
+  char copy[513];
+  int i;
+  char *p;
+
+  if (name[0] != '-')
+    return -1;
+
+  field[0] = copy;
+  for (i = 1, p = copy, name++; *name; p++, name++)
+    {
+      if (p - copy > 512)
+       return -1;
+      if (*name == '-'
+         && i < XLFD_FIELD_MAX)
+       {
+         *p = '\0';
+         if (field[i - 1][0] == '*')
+           field[i - 1] = NULL;
+         field[i++] = p + 1;
+       }
+      else
+       *p = tolower (*name);
+    }
+  *p = '\0';
+  if (field[i - 1][0] == '*')
+    field[i - 1] = NULL;
+  while (i < XLFD_FIELD_MAX)
+    field[i++] = NULL;
+
+  resy = field[XLFD_RESY] ? atoi (field[XLFD_RESY]) : 0;
+  avgwidth = ((field[XLFD_AVGWIDTH] && isdigit (field[XLFD_AVGWIDTH][0]))
+             ? atoi (field[XLFD_AVGWIDTH]) : 1);
+  if (! avgwidth)
+    size = 0;
+  else if (! field[XLFD_PIXEL])
+    size = field[XLFD_POINT] ? atoi (field[XLFD_POINT]) * resy / 72 : 0;
+  else if (field[XLFD_PIXEL][0] == '[')
+    {
+      /* The pixel size field specifies a transformation matrix of the
+        form "[A B C D]".  The XLFD spec says that the scalar value N
+        for the pixel size is equivalent to D.  */
+      char *p0 = field[XLFD_PIXEL] + 1, *p1;
+      double d;
+
+      for (i = 0; i < 4; i++, p0 = p1)
+       d = strtod (p0, &p1);
+      size = d * 10;
+    }
+  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);
+  return 0;
+}
+
+static char *
+xlfd_unparse_name (MFont *font)
+{
+  MSymbol prop[7];
+  char name[513];
+  char *str[7];
+  int len, i;
+  unsigned short size, resy;
+
+  prop[0] = (MSymbol) mfont_get_prop (font, Mfoundry);
+  prop[1] = (MSymbol) mfont_get_prop (font, Mfamily);
+  prop[2] = (MSymbol) mfont_get_prop (font, Mweight);
+  prop[3] = (MSymbol) mfont_get_prop (font, Mstyle);
+  prop[4] = (MSymbol) mfont_get_prop (font, Mstretch);
+  prop[5] = (MSymbol) mfont_get_prop (font, Madstyle);
+  prop[6] = (MSymbol) mfont_get_prop (font, Mregistry);
+  for (len = 0, i = 0; i < 7; i++)
+    {
+      if (prop[i] != Mnil)
+       {
+         str[i] = msymbol_name (prop[i]);
+         len += strlen (str[i]);
+       }
+      else
+       {
+         str[i] = "*";
+         len++;
+       }
+    }
+  if ((len
+       + 12                    /* 12 dashes */
+       + 3                     /* 3 asterisks */
+       + 30                    /* 3 integers (each 10 digits) */
+       + 1)                    /* '\0' terminal */
+      > 513)
+    return NULL;
+
+  size = (int) mfont_get_prop (font, Msize);
+  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],
+          size, resy, resy,  str[6]);
+  return strdup (name);
+}
 
 \f
 /* Internal API */
@@ -668,6 +827,12 @@ mfont__init ()
   Msize = msymbol ("size");
   Mresolution = msymbol ("resolution");
 
+  Mfontconfig = msymbol ("fontconfig");
+
+  Mx = msymbol ("x");
+  Mfreetype = msymbol ("freetype");
+  Mxft = msymbol ("xft");
+
   /* 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++)
@@ -687,15 +852,13 @@ mfont__init ()
 
          if (sym == Mnil)
            return -1;
-         if (msymbol_put(sym, mfont__property_table[i].property,
-                         (void *) (j + 1)) < 0)
+         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);
        }
     }
 
-  memset (mfont__driver_list, 0, sizeof mfont__driver_list);
-
   /* 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).  */
@@ -780,8 +943,7 @@ mfont__fini ()
 void
 mfont__free_realized (MRealizedFont *rfont)
 {
-  if (rfont->info)
-    M17N_OBJECT_UNREF (rfont->info);
+  M17N_OBJECT_UNREF (rfont->info);
   free (rfont);
 }
 
@@ -808,6 +970,8 @@ mfont__score (MFont *font, MFont *spec, MFont *request, int limited_size)
            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)
@@ -850,7 +1014,6 @@ mfont__set_spec_from_face (MFont *spec, MFace *face)
   spec->property[MFONT_REGISTRY] = 1;
   spec->property[MFONT_SIZE] = (int) (face->property[MFACE_SIZE]);
   spec->property[MFONT_RESY] = 0;
-  spec->property[MFONT_TYPE] = 0;
 }
 
 
@@ -881,19 +1044,18 @@ mfont__select (MFrame *frame, MFont *spec, MFont *request, int limited_size,
               MSymbol layouter)
 {
   MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
-  MPlist *realized_font_list;
-  MRealizedFont *best_font[MFONT_TYPE_MAX], *best;
-  int best_index;
+  MPlist *plist;
+  MRealizedFont *best;
   int i;
   int mdebug_mask = MDEBUG_FONT;
 
   if (registry == Mnil)
     registry = Mt;
 
-  MPLIST_DO (realized_font_list, frame->realized_font_list)
+  MPLIST_DO (plist, frame->realized_font_list)
     {
-      best = MPLIST_VAL (realized_font_list);
-      if (MPLIST_KEY (realized_font_list) == registry
+      best = MPLIST_VAL (plist);
+      if (MPLIST_KEY (plist) == registry
          && ! memcmp (&best->spec, spec, sizeof (MFont))
          && ! memcmp (&best->request, request, sizeof (MFont)))
        {
@@ -904,9 +1066,9 @@ mfont__select (MFrame *frame, MFont *spec, MFont *request, int limited_size,
              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);
-             mplist_add (frame->realized_font_list, registry, copy);
              best = copy;
            }
          return best;
@@ -915,25 +1077,27 @@ mfont__select (MFrame *frame, MFont *spec, MFont *request, int limited_size,
 
   MDEBUG_PUSH_TIME ();
   best = NULL;
-  best_index = -1;
-  for (i = 0; i < MFONT_TYPE_MAX; i++)
-    {
-      MFontDriver *driver = mfont__driver_list[i];
-
-      best_font[i] = (driver
-                     ? (driver->select) (frame, spec, request, limited_size)
-                     : NULL);
-      if (best_font[i]
-         && (best_index < 0
-             || best_font[best_index]->score < best_font[i]->score))
-       best_index = i;
-    }
-  for (i = 0; i < MFONT_TYPE_MAX; i++)
+  MPLIST_DO (plist, frame->font_driver_list)
     {
-      if (i == best_index)
-       best = best_font[i];
-      else if (best_font[i])
-       free (best_font[i]);
+      MFontDriver *driver = MPLIST_VAL (plist);
+      MRealizedFont *this
+       = (driver->select) (frame, spec, request, limited_size);
+
+      if (this)
+       {
+         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);
+       }
     }
 
   if (mdebug__flag & mdebug_mask)
@@ -948,8 +1112,9 @@ mfont__select (MFrame *frame, MFont *spec, MFont *request, int limited_size,
 
       if (best)
        MDEBUG_PRINT_TIME ("FONT", 
-                          (stderr, " to select <%s> from <%s>.",
+                          (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));
@@ -970,39 +1135,10 @@ mfont__select (MFrame *frame, MFont *spec, MFont *request, int limited_size,
 int
 mfont__open (MRealizedFont *rfont)
 {
-  MPlist *realized_font_list;
-  MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
-
-  if (rfont->status)
-    mdebug_hook ();
-
-  MPLIST_DO (realized_font_list, rfont->frame->realized_font_list)
-    {
-      MRealizedFont *this_rfont = MPLIST_VAL (realized_font_list);
-
-      if (this_rfont->status != 0
-         && MPLIST_KEY (realized_font_list) == registry
-         && ! memcmp (&this_rfont->font, &rfont->font, sizeof (MFont)))
-       {
-         if (rfont->info)
-           M17N_OBJECT_UNREF (rfont->info);
-         rfont->info = this_rfont->info;
-         M17N_OBJECT_REF (this_rfont->info);
-         rfont->status = this_rfont->status;
-         return (this_rfont->status > 0 ? 0 : -1);
-       }
-    }
-
   return (rfont->driver->open) (rfont);
 }
 
 void
-mfont__close (MRealizedFont *rfont)
-{
-  (rfont->driver->close) (rfont);
-}
-
-void
 mfont__resize (MFont *spec, MFont *request)
 {
   MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
@@ -1033,24 +1169,6 @@ mfont__resize (MFont *spec, MFont *request)
       }
 }
 
-/* Return 1 if C is encodable, 0, if C is not encodable, -1 if it
-   can't be decided now.  */
-
-int
-mfont__encodable_p (MRealizedFont *rfont, MSymbol layouter_name, int c)
-{
-  MFontEncoding *encoding;
-
-  if (layouter_name != Mnil)
-    return (mfont__flt_encode_char (layouter_name, c)
-           != MCHAR_INVALID_CODE);
-  if (! rfont->encoding)
-    rfont->encoding = find_encoding (&rfont->spec);
-  encoding = rfont->encoding;
-  if (! encoding->repertory_charset)
-    return -1;
-  return (ENCODE_CHAR (encoding->repertory_charset, c) != MCHAR_INVALID_CODE);
-}
 
 unsigned
 mfont__encode_char (MRealizedFont *rfont, int c)
@@ -1065,14 +1183,13 @@ mfont__encode_char (MRealizedFont *rfont, int c)
   encoding = rfont->encoding;
   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;
   code = ENCODE_CHAR (encoding->encoding_charset, c);
   if (code == MCHAR_INVALID_CODE)
     return MCHAR_INVALID_CODE;
-  if (! encoding->repertory_charset)
-    return (rfont->driver->encode_char) (rfont, c, code);
-  if (ENCODE_CHAR (encoding->repertory_charset, c) == MCHAR_INVALID_CODE)
-    return MCHAR_INVALID_CODE;
-  return code;
+  return (rfont->driver->encode_char) (rfont, code);
 }
 
 void
@@ -1127,6 +1244,28 @@ mfont__set_spec (MFont *font, MSymbol *attrs,
   font->property[MFONT_RESY] = resy;
 }
 
+int
+mfont__parse_name_into_font (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))
+    result = mfont__ft_parse_name (name, font);
+#endif
+  return result;
+}
+
+MPlist *
+mfont__encoding_list (void)
+{
+  if (! font_encoding_list)
+    load_font_encoding_table ();
+  return font_encoding_list;
+}
+
 /*** @} */
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
@@ -1301,6 +1440,41 @@ MSymbol Msize;
 
 MSymbol Mresolution;
 
+/***en
+    @brief Symobl of name "fontconfig".
+
+    The variable #Mfontconfig is to be used as an argument of the
+    functions mfont_parse_name () and mfont_unparse_name ().  */
+
+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
+    actually (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
+    is actually 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
+    is actually (XftFont *).  */
+
+MSymbol Mxft;
+
 /*=*/
 /*** @} */
 /*=*/
@@ -1374,13 +1548,17 @@ mfont ()
 /*=*/
 
 /***en
-    @brief Create a new font from fontname.
+    @brief Create a font by parsing a fontname.
 
-    The mfont_from_name () function creates a new font object.  The
+    The mfont_parse_name () function creates a new font object.  The
     properties are extracted fontname $NAME.
 
-    How to extract properties is window system dependent.  The m17n-X
-    library parses $NAME as XLFD (X Logical Font Description).
+    $FORMAT specifies the format of $NAME.  If $FORMAT is #Mx, $NAME
+    is parsed as XLFD (X Logical Font Description).  If $FORMAT is
+    #Mfontconfig, $NAME is parsed as Fontconfig's textual
+    representation of font.  If $FORMAT is #Mnil, $NAME is at first
+    parsed as XLFD, and it it fails, parsed as Fontconfig's
+    representation.
 
     @return
     If the operation was successful, this function returns a pointer
@@ -1389,24 +1567,27 @@ mfont ()
 /***ja
     @brief ¥Õ¥©¥ó¥È̾¤«¤é¥Õ¥©¥ó¥È¤òºî¤ë.
 
-    ´Ø¿ô mfont_from_name () ¤Ï¡¢¥Õ¥©¥ó¥È̾ $NAME ¤«¤é¼è¤ê½Ð¤µ¤ì¤¿¥×¥í¥Ñ
+    ´Ø¿ô mfont_parse_name () ¤Ï¡¢¥Õ¥©¥ó¥È̾ $NAME ¤«¤é¼è¤ê½Ð¤µ¤ì¤¿¥×¥í¥Ñ
     ¥Æ¥£¤ò»ý¤Ä¡¢¿·¤·¤¤¥Õ¥©¥ó¥È¥ª¥Ö¥¸¥§¥¯¥È¤òºî¤ë¡£
 
-    ¤É¤Î¤è¤¦¤Ë¥×¥í¥Ñ¥Æ¥£¤ò¼è¤ê½Ð¤¹¤«¤Ï¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤Ë°Í¸¤¹¤ë¡£
-    m17n-X ¥é¥¤¥Ö¥é¥ê¤Î¾ì¹ç¤Ï XLFD (X Logical Font Description) ¤Ë½¾¤Ã¤Æ
-    $NAME ¤ò²òÀϤ¹¤ë¡£
+    $FORMAT ¤Ï $NAME ¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤ò»ØÄꤹ¤ë¡£$FORMAT ¤¬ #Mx ¤Ç¤¢¤ì¤Ð¡¢
+    $NAME ¤Ï XLFD (X Logical Font Description) ¤Ë½¾¤Ã¤Æ²òÀϤµ¤ì¤ë¡£
+    $FORMAT ¤¬ #Mfontconfig ¤Ç¤¢¤ì¤Ð $NAME ¤Ï Fontfonfig ¤Î¥Õ¥©¥ó¥È¥Æ¥­
+    ¥¹¥Èɽ¸½¤Ë½¾¤Ã¤Æ²òÀϤµ¤ì¤ë¡£$FORMAT ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¤Þ¤º XLFD ¤Ë
+    ½¾¤Ã¤Æ²òÀϤµ¤ì¡¢¤½¤ì¤Ë¼ºÇÔ¤·¤¿¤é Fontconfig ¤Ë½¾¤Ã¤Æ²òÀϤµ¤ì¤ë¡£
 
     @return
-    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mfont_from_name () ¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ø¤Î
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mfont_parse_name () ¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ø¤Î
     ¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
 
 MFont *
-mfont_from_name (char *name)
+mfont_parse_name (char *name, MSymbol format)
 {
   MFont template, *font;
-
-  if (mwin__parse_font_name (name, &template) < 0)
-    return NULL;
+  
+  MFONT_INIT (&template);
+  if (mfont__parse_name_into_font (name, format, &template) < 0)
+    MERROR (MERROR_FONT, NULL);
   MSTRUCT_CALLOC (font, MERROR_FONT);
   *font = template;
   return font;
@@ -1415,6 +1596,53 @@ mfont_from_name (char *name)
 /*=*/
 
 /***en
+    @brief Create a fontname from a font.
+
+    The mfont_unparse_name () function creates a fontname string
+    from font $FONT according to $FORMAT.
+
+    $FORMAT must be #Mx or #Mfontconfig.  If it is #Mx, the fontname
+    is in XLFD (X Logical Font Description) format.  If it is
+    #Mfontconfig, the fontname is in the style of Fontconfig's text
+    representation.
+
+    @return
+    This function returns a newly allocated fontname string, which is
+    not freed unless the user explicitly does so by free ().  */
+
+/***ja
+    @brief ¥Õ¥©¥ó¥È̾¤«¤é¥Õ¥©¥ó¥È¤òºî¤ë.
+
+    ´Ø¿ô mfont_unparse_name () ¤Ï $FORMAT ¤Ë¤·¤¿¤¬¤Ã¤¿¥Õ¥©¥ó¥È̾¤Îʸ»ú
+    Îó¤ò¥Õ¥©¥ó¥È$FONT ¤ò¸µ¤Ëºî¤ë¡£
+
+    $FORMAT ¤Ï #Mx ¤Þ¤¿¤Ï #Mfontconfig ¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£#Mx ¤Ê¤é¤Ð¥Õ¥©
+    ¥ó¥È̾¤Ï XLFD (X Logical Font Description) ¤Ë½¾¤¦¡£#Mfontconfig ¤Ê
+    ¤é¤Ð¥Õ¥©¥ó¥È̾¤Ï Fontconfig ¤Î¥Õ¥©¥ó¥È¥Æ¥­¥¹¥Èɽ¸½¤Ë½¾¤¦¡£
+
+    @return 
+    ¤³¤Î´Ø¿ô¤Ï¿·¤¿¤Ë¥¢¥í¥±¡¼¥È¤·¤¿¥Õ¥©¥ó¥È̾¤Îʸ»úÎó¤òÊÖ¤¹¡£Ê¸»úÎó¤Ï¡¢
+    ¥æ¡¼¥¶¤¬ free () ¤Ë¤è¤Ã¤ÆÌÀ¼¨Åª¤Ë²òÊü¤·¤Ê¤¤¸Â¤ê²òÊü¤µ¤ì¤Ê¤¤¡£  */
+
+char *
+mfont_unparse_name (MFont *font, MSymbol format)
+{
+  char *name;
+
+  if (format == Mx)
+    name = xlfd_unparse_name (font);
+#ifdef HAVE_FONTCONFIG
+  else if (format == Mfontconfig)
+    name = mfont__ft_unparse_name (font);
+#endif
+  else
+    MERROR (MERROR_FONT, NULL);
+  return name;
+}
+
+/*=*/
+
+/***en
     @brief Make a copy of a font.
 
     The mfont_copy () function returns a new copy of font $FONT.  */
@@ -1436,40 +1664,6 @@ mfont_copy (MFont *font)
 /*=*/
 
 /***en
-    @brief Create a fontname from a font.
-
-    The mfont_name () function creates a fontname string created from
-    font $FONT.
-
-    The syntax of fontname is window system dependent.  The m17n-X
-    library returns a fontname conforming to XLFD (X Logical Font
-    Description).
-
-    @return
-    This function returns the created fontname string, which is not freed
-    unless the user explicitly does so by free ().  */
-/***ja
-    @brief ¥Õ¥©¥ó¥È̾¤«¤é¥Õ¥©¥ó¥È¤òºî¤ë.
-
-    ´Ø¿ô mfont_name () ¤Ï¥Õ¥©¥ó¥È̾¤Îʸ»úÎó¤ò¥Õ¥©¥ó¥È
-    $FONT ¤ò¸µ¤Ëºî¤ë¡£
-
-    ¥Õ¥©¥ó¥È̾¤Îʸˡ¤Ï¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤Ë°Í¸¤¹¤ë¡£m17n-X ¥é¥¤¥Ö¥é¥ê
-    ¤Ï XLFD (X Logical Font Description) ¤Ë½¾¤¦¥Õ¥©¥ó¥È̾¤òÊÖ¤¹¡£
-
-    @return 
-    ¤³¤Î´Ø¿ô¤Ïºî¤Ã¤¿¥Õ¥©¥ó¥È̾¤Îʸ»úÎó¤òÊÖ¤¹¡£Ê¸»úÎó¤Ï¡¢¥æ¡¼¥¶
-    ¤¬ free () ¤Ë¤è¤Ã¤ÆÌÀ¼¨Åª¤Ë²òÊü¤·¤Ê¤¤¸Â¤ê²òÊü¤µ¤ì¤Ê¤¤¡£  */
-
-char *
-mfont_name (MFont *font)
-{
-  return mwin__build_font_name (font);
-}
-
-/*=*/
-
-/***en
     @brief Get a property value of a font.
 
     The mfont_get_prop () function gets the value of $KEY property of
@@ -1844,6 +2038,124 @@ mfont_set_encoding (MFont *font, MSymbol encoding_name, MSymbol repertory_name)
   return 0;
 }
 
+/*=*/
+
+/***en
+    @brief Create a fontname from a font.
+
+    This function is obsolete.   Use mfont_unparse_name instead. */
+/***ja
+    @brief ¥Õ¥©¥ó¥È̾¤«¤é¥Õ¥©¥ó¥È¤òºî¤ë.
+
+    ¤³¤Î´Ø¿ô¤ÏÇÑ»ßͽÄê¤Ç¤¢¤ë¡£ mfont_unparse_name () ¤ò»ÈÍѤΤ³¤È¡£ */
+
+char *
+mfont_name (MFont *font)
+{
+  return mfont_unparse_name (font, Mx);
+}
+
+/*=*/
+
+/***en
+    @brief Create a new font from fontname.
+
+    This function is obsolete.  Use mfont_parse_name () instead.  */
+
+/***ja
+    @brief ¥Õ¥©¥ó¥È̾¤«¤é¥Õ¥©¥ó¥È¤òºî¤ë.
+
+    ¤³¤ì¤Ï´Ø¿ô¤ÏÇÑ»ßͽÄê¤Ç¤¢¤ë¡£ mfont_parse_name () ¤ò»ÈÍѤΤ³¤È¡£  */
+
+MFont *
+mfont_from_name (char *name)
+{
+  return mfont_parse_name (name, Mx);
+}
+
+/*=*/
+
+/***en
+    @brief Get resize information of a font.
+
+    The mfont_resize_ratio () function lookups the m17n database
+    \<font, reisize\> and returns a resizing ratio (in percentage) of
+    FONT.  For instance, if the return value is 150, that means that
+    the m17n library uses an 1.5 time bigger font than a specified
+    size.  */
+
+/***ja
+    @brief ¥Õ¥©¥ó¥È¤Î¥ê¥µ¥¤¥º¾ðÊó¤òÆÀ¤ë
+
+    ´Ø¿ô mfont_resize_ratio ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹ \<font, reisize\> ¤ò¸¡
+    º÷¤·¡¢¥Õ¥©¥ó¥È FONT ¤Î¥ê¥µ¥¤¥º¤ÎÈæΨ¡Ê¥Ñ¡¼¥»¥ó¥Æ¡¼¥¸¡Ë¤òÊÖ¤¹¡£¤¿¤È¤¨
+    ¤ÐÊÖÃͤ¬ 150 ¤Ç¤¢¤ì¤Ð¡¢m17n ¥é¥¤¥Ö¥é¥ê¤Ï»ØÄꤵ¤ì¤¿¥µ¥¤¥º¤Î 1.5 ÇܤÎ
+    ¥Õ¥©¥ó¥È¤ò»ÈÍѤ¹¤ë¤³¤È¤ò°ÕÌ£¤¹¤ë¡£ */
+
+int
+mfont_resize_ratio (MFont *font)
+{
+  MFont request = *font;
+
+  mfont__resize (font, &request);
+  return (font->property[MFONT_SIZE] * 100 / request.property[MFONT_SIZE]);
+}
+
+/*=*/
+
+/***en
+    @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
+    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.
+
+    @return
+    This function returns a plist whose keys are family names and
+    values are pointers to the object MFont.  The plist must be freed
+    by m17n_object_unref ().  If no font is found, it returns
+    NULL.  */
+
+/***ja
+    @brief ¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÆÀ¤ë
+
+    ´Ø¿ô mfont_list () ¤Ï¥Õ¥ì¡¼¥à $FRAME ¤ÇÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È
+    ¤òÊÖ¤¹¡£ $FONT ¤¬ @c Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$FONT ¤È¹çÃפ¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©
+    ¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£$LANGUAGE ¤¬ @c Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤ò
+    ¥µ¥Ý¡¼¥È¤¹¤ëÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤Î¥ê¥¹¥È¤òÊÖ¤¹¡£ $MAXNUM ¤Ï¡¢0 ¤è¤êÂç
+    ¤¤¾ì¹ç¤Ë¤Ï¡¢ÊÖ¤¹¥Õ¥©¥ó¥È¤Î¿ô¤Î¾å¸Â¤Ç¤¢¤ë¡£
+
+    @return 
+    ¤³¤Î´Ø¿ô¤Ï¥­¡¼¤¬¥Õ¥©¥ó¥È¥Õ¥¡¥ß¥ê̾¤Ç¤¢¤êÃͤ¬ MFont ¥ª¥Ö¥¸¥§
+    ¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤è¤¦¤Ê plist ¤òÊÖ¤¹¡£plist ¤Ï
+    m17n_object_unref () ¤Ç²òÊü¤¹¤ëɬÍפ¬¤¢¤ë¡£¥Õ¥©¥ó¥È¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð
+    NULL ¤òÊÖ¤¹¡£  */
+
+MPlist *
+mfont_list (MFrame *frame, MFont *font, MSymbol language, int maxnum)
+{
+  MPlist *plist = mplist (), *p;
+  int num = 0;
+  
+  MPLIST_DO (p, frame->font_driver_list)
+    {
+      MFontDriver *driver = MPLIST_VAL (p);
+
+      num += (driver->list) (frame, plist, font, language,
+                            maxnum > 0 ? maxnum - num : 0);
+      if (maxnum > 0 && num >= maxnum)
+       break;
+    }
+  if (MPLIST_TAIL_P (plist))
+    {
+      M17N_OBJECT_UNREF (plist);
+      plist = NULL;
+    }
+  return plist;
+}
+
 /*** @} */
 
 /*** @addtogroup m17nDebug */
@@ -1870,13 +2182,40 @@ mfont_set_encoding (MFont *font, MSymbol encoding_name, MSymbol repertory_name)
 MFont *
 mdebug_dump_font (MFont *font)
 {
-  char *name = mwin__build_font_name (font);
-
-  fprintf (stderr, "%s", name);
-  free (name);
+  char *name;
+  
+  name = mfont_unparse_name (font, Mx);
+  if (name)
+    {
+      fprintf (stderr, "%s", name);
+      free (name);
+    }
   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);
+}
+
 /*** @} */
 
 /*