*** empty log message ***
[bpt/emacs.git] / src / font.c
index ce6d26e..b0838ce 100644 (file)
@@ -29,6 +29,7 @@ Boston, MA 02110-1301, USA.  */
 #include "lisp.h"
 #include "buffer.h"
 #include "frame.h"
+#include "window.h"
 #include "dispextern.h"
 #include "charset.h"
 #include "character.h"
@@ -36,7 +37,9 @@ Boston, MA 02110-1301, USA.  */
 #include "fontset.h"
 #include "font.h"
 
+#ifndef FONT_DEBUG
 #define FONT_DEBUG
+#endif
 
 #ifdef FONT_DEBUG
 #undef xassert
@@ -49,6 +52,11 @@ int enable_font_backend;
 
 Lisp_Object Qfontp;
 
+Lisp_Object Qopentype;
+
+/* Important character set symbols.  */
+Lisp_Object Qiso8859_1, Qiso10646_1, Qunicode_bmp, Qunicode_sip;
+
 /* Like CHECK_FONT_SPEC but also validate properties of the font-spec,
    and set X to the validated result.  */
 
@@ -61,11 +69,13 @@ Lisp_Object Qfontp;
 /* Number of pt per inch (from the TeXbook).  */
 #define PT_PER_INCH 72.27
 
-/* Return a pixel size corresponding to POINT size (1/10 pt unit) on
-   resolution RESY.  */
-#define POINT_TO_PIXEL(POINT, RESY) ((POINT) * (RESY) / PT_PER_INCH / 10 + 0.5)
+/* Return a pixel size (integer) corresponding to POINT size (double)
+   on resolution DPI.  */
+#define POINT_TO_PIXEL(POINT, DPI) ((POINT) * (DPI) / PT_PER_INCH + 0.5)
 
-#define PIXEL_TO_POINT(PIXEL, RESY) ((PIXEL) * PT_PER_INCH * 10 / (RESY) + 0.5)
+/* Return a point size (double) corresponding to POINT size (integer)
+   on resolution DPI.  */
+#define PIXEL_TO_POINT(PIXEL, DPI) ((PIXEL) * PT_PER_INCH * 10 / (DPI) + 0.5)
 
 /* Special string of zero length.  It is used to specify a NULL name
    in a font properties (e.g. adstyle).  We don't use the symbol of
@@ -96,21 +106,57 @@ static Lisp_Object font_family_alist;
 extern Lisp_Object QCtype, QCfamily, QCweight, QCslant, QCwidth, QCsize, QCname;
 Lisp_Object QCfoundry, QCadstyle, QCregistry, QCextra;
 /* Symbols representing keys of font extra info.  */
-Lisp_Object QCotf, QClanguage, QCscript;
+Lisp_Object QCspacing, QCdpi, QCscalable, QCotf, QClanguage, QCscript;
+/* Symbols representing values of font spacing property.  */
+Lisp_Object Qc, Qm, Qp, Qd;
 
 /* List of all font drivers.  All font-backends (XXXfont.c) call
    add_font_driver in syms_of_XXXfont to register the font-driver
    here.  */
 static struct font_driver_list *font_driver_list;
 
+static int font_pixel_size P_ ((FRAME_PTR f, Lisp_Object));
 static Lisp_Object prop_name_to_numeric P_ ((enum font_property_index,
                                             Lisp_Object));
 static Lisp_Object prop_numeric_to_name P_ ((enum font_property_index, int));
 static Lisp_Object font_open_entity P_ ((FRAME_PTR, Lisp_Object, int));
+static void build_font_family_alist P_ ((void));
 
 /* Number of registered font drivers.  */
 static int num_font_drivers;
 
+/* Return a pixel size of font-spec SPEC on frame F.  */
+
+static int
+font_pixel_size (f, spec)
+     FRAME_PTR f;
+     Lisp_Object spec;
+{
+  Lisp_Object size = AREF (spec, FONT_SIZE_INDEX);
+  double point_size;
+  int pixel_size, dpi;
+  Lisp_Object extra, val;
+      
+  if (INTEGERP (size))
+    return XINT (size);
+  if (NILP (size))
+    return 0;
+  point_size = XFLOAT_DATA (size);
+  extra = AREF (spec, FONT_EXTRA_INDEX);
+  val = assq_no_quit (extra, QCdpi);
+  if (CONSP (val))
+    {
+      if (INTEGERP (XCDR (val)))
+       dpi = XINT (XCDR (val));
+      else
+       dpi = XFLOAT_DATA (XCDR (val)) + 0.5;
+    }
+  else
+    dpi = f->resy;
+  pixel_size = POINT_TO_PIXEL (point_size, dpi);
+  return pixel_size;
+}
+
 /* Return a numeric value corresponding to PROP's NAME (symbol).  If
    NAME is not registered in font_style_table, return Qnil.  PROP must
    be one of FONT_{WEIGHT|SLANT|SWIDTH}_INDEX.  */
@@ -204,19 +250,25 @@ build_font_family_alist ()
 \f
 /* Font property validater.  */
 
-static Lisp_Object
-font_prop_validate_type (prop, val)
-     enum font_property_index prop;
-     Lisp_Object val;
-{
-  return (SYMBOLP (val) ? val : Qerror);
-}
+static Lisp_Object font_prop_validate_symbol P_ ((enum font_property_index,
+                                                 Lisp_Object, Lisp_Object));
+static Lisp_Object font_prop_validate_style P_ ((enum font_property_index,
+                                                Lisp_Object, Lisp_Object));
+static Lisp_Object font_prop_validate_non_neg P_ ((enum font_property_index,
+                                                  Lisp_Object, Lisp_Object));
+static Lisp_Object font_prop_validate_spacing P_ ((enum font_property_index,
+                                                  Lisp_Object, Lisp_Object));
+static int get_font_prop_index P_ ((Lisp_Object, int));
+static Lisp_Object font_prop_validate P_ ((Lisp_Object));
+static Lisp_Object font_put_extra P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
 
 static Lisp_Object
-font_prop_validate_symbol (prop, val)
-     enum font_property_index prop;
-     Lisp_Object val;
+font_prop_validate_symbol (prop_index, prop, val)
+     enum font_property_index prop_index;
+     Lisp_Object prop, val;
 {
+  if (EQ (prop, QCotf))
+    return (SYMBOLP (val) ? val : Qerror);
   if (STRINGP (val))
     val = (SCHARS (val) == 0 ? null_string
           : intern_downcase ((char *) SDATA (val), SBYTES (val)));
@@ -231,9 +283,9 @@ font_prop_validate_symbol (prop, val)
 }
 
 static Lisp_Object
-font_prop_validate_style (prop, val)
-     enum font_property_index prop;
-     Lisp_Object val;
+font_prop_validate_style (prop_index, prop, val)
+     enum font_property_index prop_index;
+     Lisp_Object prop, val;
 {
   if (! INTEGERP (val))
     {
@@ -243,7 +295,7 @@ font_prop_validate_style (prop, val)
        val = Qerror;
       else
        {
-         val = prop_name_to_numeric (prop, val);
+         val = prop_name_to_numeric (prop_index, val);
          if (NILP (val))
            val = Qerror;
        }
@@ -252,51 +304,41 @@ font_prop_validate_style (prop, val)
 }
 
 static Lisp_Object
-font_prop_validate_size (prop, val)
-     enum font_property_index prop;
-     Lisp_Object val;
+font_prop_validate_non_neg (prop_index, prop, val)
+     enum font_property_index prop_index;
+     Lisp_Object prop, val;
 {
   return (NATNUMP (val) || (FLOATP (val) && XFLOAT_DATA (val) >= 0)
          ? val : Qerror);
 }
 
 static Lisp_Object
-font_prop_validate_extra (prop, val)
-     enum font_property_index prop;
-     Lisp_Object val;
-{
-  Lisp_Object tail;
-
-  for (tail = val; CONSP (tail); tail = XCDR (tail))
-    {
-      Lisp_Object key = Fcar (XCAR (tail)), this_val = Fcdr (XCAR (tail));
-      
-      if (NILP (this_val))
-       return Qnil;
-      if (EQ (key, QClanguage))
-       if (! SYMBOLP (this_val))
-         {
-           for (; CONSP (this_val); this_val = XCDR (this_val))
-             if (! SYMBOLP (XCAR (this_val)))
-               return Qerror;
-           if (! NILP (this_val))
-             return Qerror;
-         }
-      if (EQ (key, QCotf))
-       if (! STRINGP (this_val))
-         return Qerror;
-    }
-  return (NILP (tail) ? val : Qerror);
-}
-
-
+font_prop_validate_spacing (prop_index, prop, val)
+     enum font_property_index prop_index;
+     Lisp_Object prop, val;
+{
+  if (NILP (val) || (NATNUMP (val) && XINT (val) <= FONT_SPACING_CHARCELL))
+    return val;
+  if (EQ (val, Qc))
+    return make_number (FONT_SPACING_CHARCELL);
+  if (EQ (val, Qm))
+    return make_number (FONT_SPACING_MONO);
+  if (EQ (val, Qp))
+    return make_number (FONT_SPACING_PROPORTIONAL);
+  return Qerror;
+}
+
+/* Structure of known font property keys and validater of the
+   values.  */
 struct
 {
+  /* Pointer to the key symbol.  */
   Lisp_Object *key;
-  Lisp_Object (*validater) P_ ((enum font_property_index prop,
-                               Lisp_Object val));
-} font_property_table[FONT_SPEC_MAX] =
-  { { &QCtype, font_prop_validate_type },
+  /* Function to validate the value VAL, or NULL if any value is ok.  */
+  Lisp_Object (*validater) P_ ((enum font_property_index prop_index,
+                               Lisp_Object prop, Lisp_Object val));
+} font_property_table[] =
+  { { &QCtype, font_prop_validate_symbol },
     { &QCfoundry, font_prop_validate_symbol },
     { &QCfamily, font_prop_validate_symbol },
     { &QCadstyle, font_prop_validate_symbol },
@@ -304,49 +346,94 @@ struct
     { &QCweight, font_prop_validate_style },
     { &QCslant, font_prop_validate_style },
     { &QCwidth, font_prop_validate_style },
-    { &QCsize, font_prop_validate_size },
-    { &QCextra, font_prop_validate_extra }
+    { &QCsize, font_prop_validate_non_neg },
+    { &QClanguage, font_prop_validate_symbol },
+    { &QCscript, font_prop_validate_symbol },
+    { &QCdpi, font_prop_validate_non_neg },
+    { &QCspacing, font_prop_validate_spacing },
+    { &QCscalable, NULL },
+    { &QCotf, font_prop_validate_symbol }
   };
 
-static enum font_property_index
-check_font_prop_name (key)
+#define FONT_PROPERTY_TABLE_SIZE \
+  ((sizeof font_property_table) / (sizeof *font_property_table))
+
+static int
+get_font_prop_index (key, from)
      Lisp_Object key;
+     int from;
 {
-  enum font_property_index i;
-  
-  for (i = FONT_TYPE_INDEX; i < FONT_SPEC_MAX; i++)
-    if (EQ (key, *font_property_table[i].key))
-      break;
-  return i;
+  for (; from < FONT_PROPERTY_TABLE_SIZE; from++)
+    if (EQ (key, *font_property_table[from].key))
+      return from;
+  return -1;
 }
 
 static Lisp_Object
 font_prop_validate (spec)
      Lisp_Object spec;
 {
-  enum font_property_index i;
-  Lisp_Object val;
+  int i;
+  Lisp_Object prop, val, extra;
 
-  for (i = FONT_TYPE_INDEX; i <= FONT_EXTRA_INDEX; i++)
+  for (i = FONT_TYPE_INDEX; i < FONT_EXTRA_INDEX; i++)
     {
       if (! NILP (AREF (spec, i)))
        {
-         val = (font_property_table[i].validater) (i, AREF (spec, i));
+         prop = *font_property_table[i].key;
+         val = (font_property_table[i].validater) (i, prop, AREF (spec, i));
          if (EQ (val, Qerror))
-           Fsignal (Qerror, list3 (build_string ("invalid font property"),
-                                   *font_property_table[i].key,
-                                   AREF (spec, i)));
+           Fsignal (Qfont, list2 (build_string ("invalid font property"),
+                                  Fcons (prop, AREF (spec, i))));
          ASET (spec, i, val);
        }
     }
+  for (extra = AREF (spec, FONT_EXTRA_INDEX);
+       CONSP (extra); extra = XCDR (extra))
+    {
+      Lisp_Object elt = XCAR (extra);
+
+      prop = XCAR (elt);
+      i = get_font_prop_index (prop, FONT_EXTRA_INDEX);
+      if (i >= 0
+         && font_property_table[i].validater)
+       {
+         val = (font_property_table[i].validater) (i, prop, XCDR (elt));
+         if (EQ (val, Qerror))
+           Fsignal (Qfont, list2 (build_string ("invalid font property"),
+                                  elt));
+         XSETCDR (elt, val);
+       }
+    }
   return spec;
 }
       
+static Lisp_Object
+font_put_extra (font, prop, val)
+     Lisp_Object font, prop, val;
+{
+  Lisp_Object extra = AREF (font, FONT_EXTRA_INDEX);
+  Lisp_Object slot = (NILP (extra) ? Qnil : assq_no_quit (prop, extra));
+
+  if (NILP (slot))
+    {
+      extra = Fcons (Fcons (prop, val), extra);
+      ASET (font, FONT_EXTRA_INDEX, extra);
+      return val;
+    }
+  XSETCDR (slot, val);
+  return val;
+}
+
 \f
 /* Font name parser and unparser */
 
-/* An enumerator for each field of an XLFD font name.  */
+static Lisp_Object intern_font_field P_ ((char *, int));
+static int parse_matrix P_ ((char *));
+static int font_expand_wildcards P_ ((Lisp_Object *, int));
+static int font_parse_name P_ ((char *, Lisp_Object));
 
+/* An enumerator for each field of an XLFD font name.  */
 enum xlfd_field_index
 {
   XLFD_FOUNDRY_INDEX,
@@ -355,8 +442,8 @@ enum xlfd_field_index
   XLFD_SLANT_INDEX,
   XLFD_SWIDTH_INDEX,
   XLFD_ADSTYLE_INDEX,
-  XLFD_PIXEL_SIZE_INDEX,
-  XLFD_POINT_SIZE_INDEX,
+  XLFD_PIXEL_INDEX,
+  XLFD_POINT_INDEX,
   XLFD_RESX_INDEX,
   XLFD_RESY_INDEX,
   XLFD_SPACING_INDEX,
@@ -366,28 +453,51 @@ enum xlfd_field_index
   XLFD_LAST_INDEX
 };
 
-/* Return a symbol interned by string at STR and bytes LEN.
-   If LEN == 0, return a null string.
-   If the string is "*", return Qnil.
-   It is assured that LEN < 256.   */
+/* An enumerator for mask bit corresponding to each XLFD field.  */
+enum xlfd_field_mask
+{
+  XLFD_FOUNDRY_MASK = 0x0001,
+  XLFD_FAMILY_MASK = 0x0002,
+  XLFD_WEIGHT_MASK = 0x0004,
+  XLFD_SLANT_MASK = 0x0008,
+  XLFD_SWIDTH_MASK = 0x0010,
+  XLFD_ADSTYLE_MASK = 0x0020,
+  XLFD_PIXEL_MASK = 0x0040,
+  XLFD_POINT_MASK = 0x0080,
+  XLFD_RESX_MASK = 0x0100,
+  XLFD_RESY_MASK = 0x0200,
+  XLFD_SPACING_MASK = 0x0400,
+  XLFD_AVGWIDTH_MASK = 0x0800,
+  XLFD_REGISTRY_MASK = 0x1000,
+  XLFD_ENCODING_MASK = 0x2000
+};
+
+
+/* Return a Lispy value of a XLFD font field at STR and LEN bytes.
+   If LEN is zero, it returns `null_string'.
+   If STR is "*", it returns nil.
+   If all characters in STR are digits, it returns an integer.
+   Otherwise, it returns a symbol interned from downcased STR.  */
 
 static Lisp_Object
-intern_font_field (f, xlfd)
-     char *f[XLFD_LAST_INDEX + 1];
-     int xlfd;
+intern_font_field (str, len)
+     char *str;
+     int len;
 {
-  char *str = f[xlfd] + 1;
-  int len;
-  
-  if (xlfd != XLFD_RESY_INDEX)
-    len = f[xlfd + 1] - f[xlfd] - 1;
-  else
-    len = f[XLFD_REGISTRY_INDEX] - f[xlfd] - 1;
+  int i;
 
   if (len == 0)
     return null_string;
   if (*str == '*' && len == 1)
     return Qnil;
+  if (isdigit (*str))
+    {
+      for (i = 1; i < len; i++)
+       if (! isdigit (str[i]))
+         break;
+      if (i == len)
+       return make_number (atoi (str));
+    }
   return intern_downcase (str, len);
 }
 
@@ -424,155 +534,407 @@ parse_matrix (p)
   return (i == 4 ? (int) matrix[3] : -1);
 }
 
-/* Parse NAME (null terminated) as XLFD format, and store information
-   in FONT (font-spec or font-entity).  If NAME is successfully
-   parsed, return 2 (non-scalable font), 1 (scalable vector font), or
-   0 (auto-scaled font).  Otherwise return -1.
+/* Expand a wildcard field in FIELD (the first N fields are filled) to
+   multiple fields to fill in all 14 XLFD fields while restring a
+   field position by its contents.  */
+
+static int
+font_expand_wildcards (field, n)
+     Lisp_Object field[XLFD_LAST_INDEX];
+     int n;
+{
+  /* Copy of FIELD.  */
+  Lisp_Object tmp[XLFD_LAST_INDEX];
+  /* Array of information about where this element can go.  Nth
+     element is for Nth element of FIELD. */
+  struct {
+    /* Minimum possible field.  */
+    int from;
+    /* Maxinum possible field.  */
+    int to;
+    /* Bit mask of possible field.  Nth bit corresponds to Nth field.  */
+    int mask;
+  } range[XLFD_LAST_INDEX];
+  int i, j;
+  int range_from, range_to;
+  unsigned range_mask;
+
+#define XLFD_SYMBOL_MASK (XLFD_FOUNDRY_MASK | XLFD_FAMILY_MASK \
+                         | XLFD_ADSTYLE_MASK  | XLFD_REGISTRY_MASK)
+#define XLFD_NULL_MASK (XLFD_FOUNDRY_MASK | XLFD_ADSTYLE_MASK)
+#define XLFD_LARGENUM_MASK (XLFD_POINT_MASK | XLFD_RESX_MASK | XLFD_RESY_MASK \
+                           | XLFD_AVGWIDTH_MASK)
+#define XLFD_REGENC_MASK (XLFD_REGISTRY_MASK | XLFD_ENCODING_MASK)
+
+  /* Initialize RANGE_MASK for FIELD[0] which can be 0th to (14 - N)th
+     field.  The value is shifted to left one bit by one in the
+     following loop.  */
+  for (i = 0, range_mask = 0; i <= 14 - n; i++)
+    range_mask = (range_mask << 1) | 1;
+
+  /* The triplet RANGE_FROM, RANGE_TO, and RANGE_MASK is a
+     position-based retriction for FIELD[I].  */
+  for (i = 0, range_from = 0, range_to = 14 - n; i < n;
+       i++, range_from++, range_to++, range_mask <<= 1)
+    {
+      Lisp_Object val = field[i];
+
+      tmp[i] = val;
+      if (NILP (val))
+       {
+         /* Wildcard.  */
+         range[i].from = range_from;
+         range[i].to = range_to;
+         range[i].mask = range_mask;
+       }
+      else
+       {
+         /* The triplet FROM, TO, and MASK is a value-based
+            retriction for FIELD[I].  */
+         int from, to;
+         unsigned mask;
+
+         if (INTEGERP (val))
+           {
+             int numeric = XINT (val);
+
+             if (i + 1 == n)
+               from = to = XLFD_ENCODING_INDEX,
+                 mask = XLFD_ENCODING_MASK;
+             else if (numeric == 0)
+               from = XLFD_PIXEL_INDEX, to = XLFD_AVGWIDTH_INDEX,
+                 mask = XLFD_PIXEL_MASK | XLFD_LARGENUM_MASK;
+             else if (numeric <= 48)
+               from = to = XLFD_PIXEL_INDEX,
+                 mask = XLFD_PIXEL_MASK;
+             else 
+               from = XLFD_POINT_INDEX, to = XLFD_AVGWIDTH_INDEX,
+                 mask = XLFD_LARGENUM_MASK;
+           }
+         else if (EQ (val, null_string))
+           from = XLFD_FOUNDRY_INDEX, to = XLFD_ADSTYLE_INDEX,
+             mask = XLFD_NULL_MASK;
+         else if (i == 0)
+           from = to = XLFD_FOUNDRY_INDEX, mask = XLFD_FOUNDRY_MASK;
+         else if (i + 1 == n)
+           {
+             Lisp_Object name = SYMBOL_NAME (val);
+
+             if (SDATA (name)[SBYTES (name) - 1] == '*')
+               from = XLFD_REGISTRY_INDEX, to = XLFD_ENCODING_INDEX,
+                 mask = XLFD_REGENC_MASK;
+             else
+               from = to = XLFD_ENCODING_INDEX,
+                 mask = XLFD_ENCODING_MASK;
+           }
+         else if (range_from <= XLFD_WEIGHT_INDEX
+                  && range_to >= XLFD_WEIGHT_INDEX
+                  && !NILP (prop_name_to_numeric (FONT_WEIGHT_INDEX, val)))
+           from = to = XLFD_WEIGHT_INDEX, mask = XLFD_WEIGHT_MASK;
+         else if (range_from <= XLFD_SLANT_INDEX
+                  && range_to >= XLFD_SLANT_INDEX
+                  && !NILP (prop_name_to_numeric (FONT_SLANT_INDEX, val)))
+           from = to = XLFD_SLANT_INDEX, mask = XLFD_SLANT_MASK;
+         else if (range_from <= XLFD_SWIDTH_INDEX
+                  && range_to >= XLFD_SWIDTH_INDEX
+                  && !NILP (prop_name_to_numeric (FONT_WIDTH_INDEX, val)))
+           from = to = XLFD_SWIDTH_INDEX, mask = XLFD_SWIDTH_MASK;
+         else
+           {
+             if (EQ (val, Qc) || EQ (val, Qm) || EQ (val, Qp) || EQ (val, Qd))
+               from = to = XLFD_SPACING_INDEX, mask = XLFD_SPACING_MASK;
+             else
+               from = XLFD_FOUNDRY_INDEX, to = XLFD_ENCODING_INDEX,
+                 mask = XLFD_SYMBOL_MASK;
+           }
+
+         /* Merge position-based and value-based restrictions.  */
+         mask &= range_mask;
+         while (from < range_from)
+           mask &= ~(1 << from++);
+         while (from < 14 && ! (mask & (1 << from)))
+           from++;
+         while (to > range_to)
+           mask &= ~(1 << to--);
+         while (to >= 0 && ! (mask & (1 << to)))
+           to--;
+         if (from > to)
+           return -1;
+         range[i].from = from;
+         range[i].to = to;
+         range[i].mask = mask;
+
+         if (from > range_from || to < range_to)
+           {
+             /* The range is narrowed by value-based restrictions.
+                Reflect it to the other fields.  */
+
+             /* Following fields should be after FROM.  */
+             range_from = from;
+             /* Preceding fields should be before TO.  */
+             for (j = i - 1, from--, to--; j >= 0; j--, from--, to--)
+               {
+                 /* Check FROM for non-wildcard field.  */
+                 if (! NILP (tmp[j]) && range[j].from < from)
+                   {
+                     while (range[j].from < from)
+                       range[j].mask &= ~(1 << range[j].from++);
+                     while (from < 14 && ! (range[j].mask & (1 << from)))
+                       from++;
+                     range[j].from = from;
+                   }
+                 else
+                   from = range[j].from;
+                 if (range[j].to > to)
+                   {
+                     while (range[j].to > to)
+                       range[j].mask &= ~(1 << range[j].to--);
+                     while (to >= 0 && ! (range[j].mask & (1 << to)))
+                       to--;
+                     range[j].to = to;
+                   }
+                 else
+                   to = range[j].to;
+                 if (from > to)
+                   return -1;
+               }
+           }
+       }
+    }
+
+  /* Decide all fileds from restrictions in RANGE.  */
+  for (i = j = 0; i < n ; i++)
+    {
+      if (j < range[i].from)
+       {
+         if (i == 0 || ! NILP (tmp[i - 1]))
+           /* None of TMP[X] corresponds to Jth field.  */
+           return -1;
+         for (; j < range[i].from; j++)
+           field[j] = Qnil;
+       }
+      field[j++] = tmp[i];
+    }
+  if (! NILP (tmp[n - 1]) && j < XLFD_REGISTRY_INDEX)
+    return -1;
+  for (; j < XLFD_LAST_INDEX; j++)
+    field[j] = Qnil;
+  if (INTEGERP (field[XLFD_ENCODING_INDEX]))
+    field[XLFD_ENCODING_INDEX]
+      = Fintern (Fnumber_to_string (field[XLFD_ENCODING_INDEX]), Qnil);
+  return 0;
+}
+
+/* Parse NAME (null terminated) as XLFD and store information in FONT
+   (font-spec or font-entity).  Size property of FONT is set as
+   follows:
+       specified XLFD fields           FONT property
+       ---------------------           -------------
+       PIXEL_SIZE                      PIXEL_SIZE (Lisp integer)
+       POINT_SIZE and RESY             calculated pixel size (Lisp integer)
+       POINT_SIZE                      POINT_SIZE/10 (Lisp float)
 
-   If FONT is a font-entity, store RESY-SPACING-AVWIDTH information as
-   a symbol in FONT_EXTRA_INDEX.
+   If NAME is successfully parsed, return 0.  Otherwise return -1.
 
-   If MERGE is nonzero, set a property of FONT only when it's nil.  */
+   FONT is usually a font-spec, but when this function is called from
+   X font backend driver, it is a font-entity.  In that case, NAME is
+   a fully specified XLFD, and we set FONT_EXTRA_INDEX of FONT to a
+   symbol RESX-RESY-SPACING-AVGWIDTH.
+*/
 
 int
-font_parse_xlfd (name, font, merge)
+font_parse_xlfd (name, font)
      char *name;
      Lisp_Object font;
-     int merge;
 {
   int len = strlen (name);
   int i, j;
-  int pixel_size, resy, avwidth;
-  double point_size;
+  Lisp_Object dpi, spacing;
+  int avgwidth;
   char *f[XLFD_LAST_INDEX + 1];
   Lisp_Object val;
-  int first_wildcard_field = -1, last_wildcard_field = XLFD_LAST_INDEX;
+  char *p;
 
   if (len > 255)
     /* Maximum XLFD name length is 255. */
     return -1;
-  for (i = 0; *name; name++)
-    if (*name == '-'
-       && i < XLFD_LAST_INDEX)
-      {
-       f[i] = name;
-       if (name[1] == '*' && (! name[2] || name[2] == '-'))
-         {
-           if (first_wildcard_field < 0)
-             first_wildcard_field = i;
-           last_wildcard_field = i;
-         }
-       i++;
-      }
+  /* Accept "*-.." as a fully specified XLFD. */
+  if (name[0] == '*' && name[1] == '-')
+    i = 1, f[XLFD_FOUNDRY_INDEX] = name;
+  else
+    i = 0;
+  for (p = name + i; *p; p++)
+    if (*p == '-' && i < XLFD_LAST_INDEX)
+      f[i++] = p + 1;
+  f[i] = p;
 
-  f[XLFD_LAST_INDEX] = name;
-  if (i < XLFD_LAST_INDEX)
+  dpi = spacing = Qnil;
+  avgwidth = -1;
+
+  if (i == XLFD_LAST_INDEX)
     {
-      /* Not a fully specified XLFD.  */
-      if (first_wildcard_field < 0 )
-       /* No wild card.  */
-       return -1;
-      i--;
-      if (last_wildcard_field < i)
+      int pixel_size;
+
+      /* Fully specified XLFD.  */
+      for (i = 0, j = FONT_FOUNDRY_INDEX; i < XLFD_WEIGHT_INDEX; i++, j++)
        {
-         /* Shift fields after the last wildcard field.   */
-         for (j = XLFD_LAST_INDEX - 1; j > last_wildcard_field; j--, i--)
-           f[j] = f[i];
-         /* Make all fields between the first and last wildcard fieled
-            also wildcard fields.  */
-         for (j--; j > first_wildcard_field; j--)
-           f[j] = "-*";
+         val = intern_font_field (f[i], f[i + 1] - 1 - f[i]);
+         if (! NILP (val))
+           ASET (font, j, val);
        }
-    }
-  f[XLFD_ENCODING_INDEX] = f[XLFD_LAST_INDEX];
-
-  if (! merge || NILP (AREF (font, FONT_FOUNDRY_INDEX)))
-    ASET (font, FONT_FOUNDRY_INDEX, intern_font_field (f, XLFD_FOUNDRY_INDEX));
-  if (! merge || NILP (AREF (font, FONT_FAMILY_INDEX)))
-    ASET (font, FONT_FAMILY_INDEX, intern_font_field (f, XLFD_FAMILY_INDEX));
-  if (! merge || NILP (AREF (font, FONT_ADSTYLE_INDEX)))
-    ASET (font, FONT_ADSTYLE_INDEX, intern_font_field (f, XLFD_ADSTYLE_INDEX));
-  if (! merge || NILP (AREF (font, FONT_REGISTRY_INDEX)))
-    ASET (font, FONT_REGISTRY_INDEX, intern_font_field (f, XLFD_REGISTRY_INDEX));
-
-  for (i = FONT_WEIGHT_INDEX, j = XLFD_WEIGHT_INDEX;
-       j <= XLFD_SWIDTH_INDEX; i++, j++)
-    if (! merge || NILP (AREF (font, i)))
-      {
-       if (isdigit(f[j][1]))
-         val = make_number (atoi (f[j] + 1));
-       else
-         {
-           Lisp_Object sym = intern_font_field (f, j);
-
-           val = prop_name_to_numeric (i, sym);
-           if (NILP (val))
-             val = sym;
-         }
-       ASET (font, i, val);
-      }
-
-  if (f[XLFD_PIXEL_SIZE_INDEX][1] == '*')
-    pixel_size = -1;           /* indicates "unspecified" */
-  else if (f[XLFD_PIXEL_SIZE_INDEX][1] == '[')
-    pixel_size = parse_matrix (f[XLFD_PIXEL_SIZE_INDEX] + 1);
-  else if (isdigit (f[XLFD_PIXEL_SIZE_INDEX][1]))
-    pixel_size = strtod (f[XLFD_PIXEL_SIZE_INDEX] + 1, NULL);
-  else
-    pixel_size = -1;
-
-  if (pixel_size < 0 && FONT_ENTITY_P (font))
-    return -1;
+      for (j = FONT_WEIGHT_INDEX; i < XLFD_ADSTYLE_INDEX; i++, j++)
+       {
+         val = intern_font_field (f[i], f[i + 1] - 1 - f[i]);
+         if (! NILP (val))
+           {
+             Lisp_Object numeric = prop_name_to_numeric (j, val);
 
-  if (f[XLFD_POINT_SIZE_INDEX][1] == '*')
-    point_size = -1;           /* indicates "unspecified" */
-  else if (f[XLFD_POINT_SIZE_INDEX][1] == '[')
-    point_size = parse_matrix (f[XLFD_POINT_SIZE_INDEX] + 1);
-  else if (isdigit (f[XLFD_POINT_SIZE_INDEX][1]))
-    point_size = strtod (f[XLFD_POINT_SIZE_INDEX] + 1, NULL);
-  else
-    point_size = -1;
+             if (INTEGERP (numeric))
+               val = numeric;
+             ASET (font, j, val);
+           }
+       }
+      val = intern_font_field (f[i], f[i + 1] - 1 - f[i]);
+      if (! NILP (val))
+       ASET (font, FONT_ADSTYLE_INDEX, val);
+      i = XLFD_REGISTRY_INDEX;
+      val = intern_font_field (f[i], f[i + 2] - f[i]);
+      if (! NILP (val))
+       ASET (font, FONT_REGISTRY_INDEX, val);
+
+      p = f[XLFD_PIXEL_INDEX];
+      if (*p == '[' && (pixel_size = parse_matrix (p)) >= 0)
+       ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));       
+      else
+       {
+         i = XLFD_PIXEL_INDEX;
+         val = intern_font_field (f[i], f[i + 1] - 1 - f[i]);
+         if (! NILP (val))
+           ASET (font, FONT_SIZE_INDEX, val);
+         else
+           {
+             double point_size = -1;
+
+             xassert (FONT_SPEC_P (font));
+             p = f[XLFD_POINT_INDEX];
+             if (*p == '[')
+               point_size = parse_matrix (p);
+             else if (isdigit (*p))
+               point_size = atoi (p), point_size /= 10;
+             if (point_size >= 0)
+               ASET (font, FONT_SIZE_INDEX, make_float (point_size));
+             else
+               {
+                 i = XLFD_PIXEL_INDEX;
+                 val = intern_font_field (f[i], f[i + 1] - 1 - f[i]);
+                 if (! NILP (val))
+                   ASET (font, FONT_SIZE_INDEX, val);
+               }
+           }
+       }
 
-  if (f[XLFD_RESY_INDEX][1] == '*')
-    resy = -1;                 /* indicates "unspecified" */
-  else
-    resy = strtod (f[XLFD_RESY_INDEX] + 1, NULL);
+      /* Parse RESX, RESY, SPACING, and AVGWIDTH.  */
+      if (FONT_ENTITY_P (font))
+       {
+         i = XLFD_RESX_INDEX;
+         ASET (font, FONT_EXTRA_INDEX,
+               intern_font_field (f[i], f[XLFD_REGISTRY_INDEX] - 1 - f[i]));
+         return 0;
+       }
 
-  if (f[XLFD_AVGWIDTH_INDEX][1] == '*')
-    avwidth = -1;              /* indicates "unspecified" */
-  else if (f[XLFD_AVGWIDTH_INDEX][1] == '~')
-    avwidth = - strtod (f[XLFD_AVGWIDTH_INDEX] + 2, NULL);
+      /* Here we just setup DPI, SPACING, and AVGWIDTH.  They are set
+        in FONT_EXTRA_INDEX later.  */
+      i = XLFD_RESX_INDEX;
+      dpi = intern_font_field (f[i], f[i + 1] - 1 - f[i]);
+      i = XLFD_SPACING_INDEX;
+      spacing = intern_font_field (f[i], f[i + 1] - 1 - f[i]);
+      p = f[XLFD_AVGWIDTH_INDEX];
+      if (*p == '~')
+       p++;
+      if (isdigit (*p))
+       avgwidth = atoi (p);
+    }
   else
-    avwidth = strtod (f[XLFD_AVGWIDTH_INDEX] + 1, NULL);
-
-  if (! merge || NILP (AREF (font, FONT_SIZE_INDEX)))
     {
-      if (pixel_size >= 0)
-       ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
-      else
+      int wild_card_found = 0;
+      Lisp_Object prop[XLFD_LAST_INDEX];
+
+      for (j = 0; j < i; j++)
        {
-         if (point_size >= 0)
+         if (*f[j] == '*')
            {
-             if (resy > 0)
-               {
-                 pixel_size = POINT_TO_PIXEL (point_size, resy);
-                 ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
-               }
+             if (f[j][1] && f[j][1] != '-')
+               return -1;
+             prop[j] = Qnil;
+             wild_card_found = 1;
+           }
+         else if (isdigit (*f[j]))
+           {
+             for (p = f[j] + 1; isdigit (*p); p++);
+             if (*p && *p != '-')
+               prop[j] = intern_downcase (f[j], p - f[j]);
              else
-               {
-                 ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
-               }
+               prop[j] = make_number (atoi (f[j]));
            }
+         else if (j + 1 < i)
+           prop[j] = intern_font_field (f[j], f[j + 1] - 1 - f[j]);
          else
-           ASET (font, FONT_SIZE_INDEX, Qnil);
+           prop[j] = intern_font_field (f[j], f[i] - f[j]);
+       }
+      if (! wild_card_found)
+       return -1;
+      if (font_expand_wildcards (prop, i) < 0)
+       return -1;
+
+      for (i = 0, j = FONT_FOUNDRY_INDEX; i < XLFD_WEIGHT_INDEX; i++, j++)
+       if (! NILP (prop[i]))
+         ASET (font, j, prop[i]);
+      for (j = FONT_WEIGHT_INDEX; i < XLFD_ADSTYLE_INDEX; i++, j++)
+       if (! NILP (prop[i]))
+         ASET (font, j, prop[i]);
+      if (! NILP (prop[XLFD_ADSTYLE_INDEX]))
+       ASET (font, FONT_ADSTYLE_INDEX, prop[XLFD_ADSTYLE_INDEX]);
+      val = prop[XLFD_REGISTRY_INDEX];
+      if (NILP (val))
+       {
+         val = prop[XLFD_ENCODING_INDEX];
+         if (! NILP (val))
+           val = Fintern (concat2 (build_string ("*-"), SYMBOL_NAME (val)),
+                          Qnil);
+       }
+      else if (NILP (prop[XLFD_ENCODING_INDEX]))
+       val = Fintern (concat2 (SYMBOL_NAME (val), build_string ("-*")),
+                      Qnil);
+      else
+       val = Fintern (concat3 (SYMBOL_NAME (val), build_string ("-"),
+                               SYMBOL_NAME (prop[XLFD_ENCODING_INDEX])),
+                      Qnil);
+      if (! NILP (val))
+       ASET (font, FONT_REGISTRY_INDEX, val);
+
+      if (INTEGERP (prop[XLFD_PIXEL_INDEX]))
+       ASET (font, FONT_SIZE_INDEX, prop[XLFD_PIXEL_INDEX]);
+      else if (INTEGERP (prop[XLFD_POINT_INDEX]))
+       {
+         double point_size = XINT (prop[XLFD_POINT_INDEX]);
+
+         ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
        }
+
+      dpi = prop[XLFD_RESX_INDEX];
+      spacing = prop[XLFD_SPACING_INDEX];
+      if (INTEGERP (prop[XLFD_AVGWIDTH_INDEX]))
+       avgwidth = XINT (prop[XLFD_AVGWIDTH_INDEX]);
     }
 
-  if (FONT_ENTITY_P (font)
-      && EQ (AREF (font, FONT_TYPE_INDEX), Qx))
-    ASET (font, FONT_EXTRA_INDEX, intern_font_field (f, XLFD_RESY_INDEX));
+  if (! NILP (dpi))
+    font_put_extra (font, QCdpi, dpi);
+  if (! NILP (spacing))
+    font_put_extra (font, QCspacing, spacing);
+  if (avgwidth >= 0)
+    font_put_extra (font, QCscalable, avgwidth == 0 ? Qt : Qnil);
 
-  return (avwidth > 0 ? 2 : resy == 0);
+  return 0;
 }
 
 /* Store XLFD name of FONT (font-spec or font-entity) in NAME (NBYTES
@@ -582,11 +944,11 @@ font_parse_xlfd (name, font, merge)
 int
 font_unparse_xlfd (font, pixel_size, name, nbytes)
      Lisp_Object font;
+     int pixel_size;
      char *name;
      int nbytes;
 {
-  char *f[XLFD_REGISTRY_INDEX + 1], *pixel_point;
-  char work[256];
+  char *f[XLFD_REGISTRY_INDEX + 1];
   Lisp_Object val;
   int i, j, len = 0;
 
@@ -601,12 +963,35 @@ font_unparse_xlfd (font, pixel_size, name, nbytes)
        j = XLFD_REGISTRY_INDEX;
       val = AREF (font, i);
       if (NILP (val))
-       f[j] = "*", len += 2;
+       {
+         if (j == XLFD_REGISTRY_INDEX)
+           f[j] = "*-*", len += 4;
+         else
+           f[j] = "*", len += 2;
+       }
       else
        {
          if (SYMBOLP (val))
            val = SYMBOL_NAME (val);
-         f[j] = (char *) SDATA (val), len += SBYTES (val) + 1;
+         if (j == XLFD_REGISTRY_INDEX
+             && ! strchr ((char *) SDATA (val), '-'))
+           {
+             /* Change "jisx0208*" and "jisx0208" to "jisx0208*-*".  */
+             if (SDATA (val)[SBYTES (val) - 1] == '*')
+               {
+                 f[j] = alloca (SBYTES (val) + 3);
+                 sprintf (f[j], "%s-*", SDATA (val));
+                 len += SBYTES (val) + 3;
+               }
+             else
+               {
+                 f[j] = alloca (SBYTES (val) + 4);
+                 sprintf (f[j], "%s*-*", SDATA (val));
+                 len += SBYTES (val) + 4;
+               }
+           }
+         else
+           f[j] = (char *) SDATA (val), len += SBYTES (val) + 1;
        }
     }
 
@@ -631,47 +1016,346 @@ font_unparse_xlfd (font, pixel_size, name, nbytes)
   xassert (NUMBERP (val) || NILP (val));
   if (INTEGERP (val))
     {
+      f[XLFD_PIXEL_INDEX] = alloca (22);
       i = XINT (val);
       if (i > 0)
-       len += sprintf (work, "%d", i) + 1;
+       len += sprintf (f[XLFD_PIXEL_INDEX], "%d-*", i) + 1;
       else                     /* i == 0 */
-       len += sprintf (work, "%d-*", pixel_size) + 1;
-      pixel_point = work;
+       len += sprintf (f[XLFD_PIXEL_INDEX], "%d-*", pixel_size) + 1;
     }
   else if (FLOATP (val))
     {
+      f[XLFD_PIXEL_INDEX] = alloca (12);
       i = XFLOAT_DATA (val) * 10;
-      len += sprintf (work, "*-%d", i) + 1;
-      pixel_point = work;
+      len += sprintf (f[XLFD_PIXEL_INDEX], "*-%d", i) + 1;
     }
   else
-    pixel_point = "*-*", len += 4;
+    f[XLFD_PIXEL_INDEX] = "*-*", len += 4;
+
+  val = AREF (font, FONT_EXTRA_INDEX);
 
   if (FONT_ENTITY_P (font)
       && EQ (AREF (font, FONT_TYPE_INDEX), Qx))
     {
-      /* Setup names for RESY-SPACING-AVWIDTH.  */
-      val = AREF (font, FONT_EXTRA_INDEX);
+      /* Setup names for RESX-RESY-SPACING-AVWIDTH.  */
       if (SYMBOLP (val) && ! NILP (val))
        {
          val = SYMBOL_NAME (val);
-         f[XLFD_RESY_INDEX] = (char *) SDATA (val), len += SBYTES (val) + 1;
+         f[XLFD_RESX_INDEX] = (char *) SDATA (val), len += SBYTES (val) + 1;
        }
       else
-       f[XLFD_RESY_INDEX] = "*-*-*", len += 6;
+       f[XLFD_RESX_INDEX] = "*-*-*-*", len += 6;
     }
   else
-    f[XLFD_RESY_INDEX] = "*-*-*", len += 6;
+    {
+      Lisp_Object dpi = assq_no_quit (QCdpi, val);
+      Lisp_Object spacing = assq_no_quit (QCspacing, val);
+      Lisp_Object scalable = assq_no_quit (QCscalable, val);
+
+      if (CONSP (dpi) || CONSP (spacing) || CONSP (scalable))
+       {
+         char *str = alloca (24);
+         int this_len;
+
+         if (CONSP (dpi) && INTEGERP (XCDR (dpi)))
+           this_len = sprintf (str, "%d-%d",
+                               XINT (XCDR (dpi)), XINT (XCDR (dpi)));
+         else
+           this_len = sprintf (str, "*-*");
+         if (CONSP (spacing) && ! NILP (XCDR (spacing)))
+           {
+             val = XCDR (spacing);
+             if (INTEGERP (val))
+               {
+                 if (XINT (val) < FONT_SPACING_MONO)
+                   val = Qp;
+                 else if (XINT (val) < FONT_SPACING_CHARCELL)
+                   val = Qm;
+                 else
+                   val = Qc;
+               }
+             xassert (SYMBOLP (val));
+             this_len += sprintf (str + this_len, "-%c",
+                                  SDATA (SYMBOL_NAME (val))[0]);
+           }
+         else
+           this_len += sprintf (str + this_len, "-*");
+         if (CONSP (scalable) && ! NILP (XCDR (spacing)))
+           this_len += sprintf (str + this_len, "-0");
+         else
+           this_len += sprintf (str + this_len, "-*");
+         f[XLFD_RESX_INDEX] = str;
+         len += this_len;
+       }
+      else
+       f[XLFD_RESX_INDEX] = "*-*-*-*", len += 8;
+    }
 
-  len += 3;    /* for "-*" of resx, and terminating '\0'.  */
+  len++;       /* for terminating '\0'.  */
   if (len >= nbytes)
     return -1;
-  return sprintf (name, "-%s-%s-%s-%s-%s-%s-%s-*-%s-%s",
+  return sprintf (name, "-%s-%s-%s-%s-%s-%s-%s-%s-%s",
                  f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX],
                  f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX],
                  f[XLFD_SWIDTH_INDEX],
-                 f[XLFD_ADSTYLE_INDEX], pixel_point,
-                 f[XLFD_RESY_INDEX], f[XLFD_REGISTRY_INDEX]);
+                 f[XLFD_ADSTYLE_INDEX], f[XLFD_PIXEL_INDEX],
+                 f[XLFD_RESX_INDEX], f[XLFD_REGISTRY_INDEX]);
+}
+
+/* Parse NAME (null terminated) as Fonconfig's name format and store
+   information in FONT (font-spec or font-entity).  If NAME is
+   successfully parsed, return 0.  Otherwise return -1.  */
+
+int
+font_parse_fcname (name, font)
+     char *name;
+     Lisp_Object font;
+{
+  char *p0, *p1;
+  int len = strlen (name);
+  char *copy;
+
+  if (len == 0)
+    return -1;
+  /* It is assured that (name[0] && name[0] != '-').  */
+  if (name[0] == ':')
+    p0 = name;
+  else
+    {
+      Lisp_Object family;
+      double point_size;
+
+      for (p0 = name + 1; *p0 && (*p0 != '-' && *p0 != ':'); p0++)
+       if (*p0 == '\\' && p0[1])
+         p0++;
+      family = intern_font_field (name, p0 - name);
+      if (*p0 == '-')
+       {
+         if (! isdigit (p0[1]))
+           return -1;
+         point_size = strtod (p0 + 1, &p1);
+         if (*p1 && *p1 != ':')
+           return -1;
+         ASET (font, FONT_SIZE_INDEX, make_float (point_size));
+         p0 = p1;
+       }
+      ASET (font, FONT_FAMILY_INDEX, family);
+    }
+
+  len -= p0 - name;
+  copy = alloca (len + 1);
+  if (! copy)
+    return -1;
+  name = copy;
+  
+  /* Now parse ":KEY=VAL" patterns.  Store known keys and values in
+     extra, copy unknown ones to COPY.  */
+  while (*p0)
+    {
+      Lisp_Object key, val;
+      int prop;
+
+      for (p1 = p0 + 1; *p1 && *p1 != '=' && *p1 != ':'; p1++);
+      if (*p1 != '=')
+       {
+         /* Must be an enumerated value.  */
+         val = intern_font_field (p0 + 1, p1 - p0 - 1);
+         if (memcmp (p0 + 1, "light", 5) == 0
+             || memcmp (p0 + 1, "medium", 6) == 0
+             || memcmp (p0 + 1, "demibold", 8) == 0
+             || memcmp (p0 + 1, "bold", 4) == 0
+             || memcmp (p0 + 1, "black", 5) == 0)
+           {
+             ASET (font, FONT_WEIGHT_INDEX, val);
+           }
+         else if (memcmp (p0 + 1, "roman", 5) == 0
+                  || memcmp (p0 + 1, "italic", 6) == 0
+                  || memcmp (p0 + 1, "oblique", 7) == 0)
+           {
+             ASET (font, FONT_SLANT_INDEX, val);
+           }
+         else if (memcmp (p0 + 1, "charcell", 8) == 0
+                  || memcmp (p0 + 1, "mono", 4) == 0
+                  || memcmp (p0 + 1, "proportional", 12) == 0)
+           {
+             font_put_extra (font, QCspacing,
+                             (p0[1] == 'c' ? Qc : p0[1] == 'm' ? Qm : Qp));
+           }
+         else
+           {
+             /* unknown key */
+             bcopy (p0, copy, p1 - p0);
+             copy += p1 - p0;
+           }
+       }
+      else
+       {
+         if (memcmp (p0 + 1, "pixelsize=", 10) == 0)
+           prop = FONT_SIZE_INDEX;
+         else
+           {
+             key = intern_font_field (p0, p1 - p0);
+             prop = get_font_prop_index (key, 0);
+           }
+         p0 = p1 + 1;
+         for (p1 = p0; *p1 && *p1 != ':'; p1++);
+         val = intern_font_field (p0, p1 - p0);
+         if (! NILP (val))
+           {
+             if (prop >= 0 && prop < FONT_EXTRA_INDEX)
+               {
+                 ASET (font, prop, val);
+               }
+             else
+               font_put_extra (font, key, val);
+           }
+       }
+      p0 = p1;
+    }
+
+  return 0;
+}
+
+/* Store fontconfig's font name of FONT (font-spec or font-entity) in
+   NAME (NBYTES length), and return the name length.  If
+   FONT_SIZE_INDEX of FONT is 0, use PIXEL_SIZE instead.  */
+
+int
+font_unparse_fcname (font, pixel_size, name, nbytes)
+     Lisp_Object font;
+     int pixel_size;
+     char *name;
+     int nbytes;
+{
+  Lisp_Object val;
+  int point_size;
+  int dpi, spacing, scalable;
+  int i, len = 1;
+  char *p;
+  Lisp_Object styles[3];
+  char *style_names[3] = { "weight", "slant", "width" };
+
+  val = AREF (font, FONT_FAMILY_INDEX);
+  if (SYMBOLP (val) && ! NILP (val))
+    len += SBYTES (SYMBOL_NAME (val));
+
+  val = AREF (font, FONT_SIZE_INDEX);
+  if (INTEGERP (val))
+    {
+      if (XINT (val) != 0)
+       pixel_size = XINT (val);
+      point_size = -1;
+      len += 21;               /* for ":pixelsize=NUM" */
+    }
+  else if (FLOATP (val))
+    {
+      pixel_size = -1;
+      point_size = (int) XFLOAT_DATA (val);
+      len += 11;               /* for "-NUM" */
+    }
+
+  val = AREF (font, FONT_FOUNDRY_INDEX);
+  if (SYMBOLP (val) && ! NILP (val))
+    /* ":foundry=NAME" */
+    len += 9 + SBYTES (SYMBOL_NAME (val));
+
+  for (i = FONT_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; i++)
+    {
+      val = AREF (font, i);
+      if (INTEGERP (val))
+       {
+         val = prop_numeric_to_name (i, XINT (val));
+         len += (strlen (style_names[i - FONT_WEIGHT_INDEX])
+                 + 2 + SBYTES (SYMBOL_NAME (val))); /* :xxx=NAME */
+       }
+      styles[i - FONT_WEIGHT_INDEX] = val;
+    }
+
+  val = AREF (font, FONT_EXTRA_INDEX);
+  if (FONT_ENTITY_P (font)
+      && EQ (AREF (font, FONT_TYPE_INDEX), Qx))
+    {
+      char *p;
+
+      /* VAL is a symbol of name `RESX-RESY-SPACING-AVWIDTH'.  */
+      p = (char *) SDATA (SYMBOL_NAME (val));
+      dpi = atoi (p);
+      for (p++; *p != '-'; p++);       /* skip RESX */
+      for (p++; *p != '-'; p++);       /* skip RESY */
+      spacing = (*p == 'c' ? FONT_SPACING_CHARCELL
+                : *p == 'm' ? FONT_SPACING_MONO
+                : FONT_SPACING_PROPORTIONAL);
+      for (p++; *p != '-'; p++);       /* skip SPACING */
+      scalable = (atoi (p) == 0);
+      /* The longest pattern is ":dpi=NUM:scalable=False:spacing=100" */
+      len += 42;
+    }
+  else
+    {
+      Lisp_Object elt;
+
+      dpi = spacing = scalable = -1;
+      elt = assq_no_quit (QCdpi, val);
+      if (CONSP (elt))
+       dpi = XINT (XCDR (elt)), len += 15; /* for ":dpi=NUM" */
+      elt = assq_no_quit (QCspacing, val);
+      if (CONSP (elt))
+       spacing = XINT (XCDR (elt)), len += 12; /* for ":spacing=100" */
+      elt = assq_no_quit (QCscalable, val);
+      if (CONSP (elt))
+       scalable = ! NILP (XCDR (elt)), len += 15; /* for ":scalable=False" */
+    }
+
+  if (len > nbytes)
+    return -1;
+  p = name;
+  if (! NILP (AREF (font, FONT_FAMILY_INDEX)))
+    p += sprintf(p, "%s",
+                SDATA (SYMBOL_NAME (AREF (font, FONT_FAMILY_INDEX))));
+  if (point_size > 0)
+    {
+      if (p == name)
+       p += sprintf (p, "%d", point_size);
+      else
+       p += sprintf (p, "-%d", point_size);
+    }
+  else if (pixel_size > 0)
+    p += sprintf (p, ":pixelsize=%d", pixel_size);
+  if (SYMBOLP (AREF (font, FONT_FOUNDRY_INDEX))
+      && ! NILP (AREF (font, FONT_FOUNDRY_INDEX)))
+    p += sprintf (p, ":foundry=%s",
+                 SDATA (SYMBOL_NAME (AREF (font, FONT_FOUNDRY_INDEX))));
+  for (i = 0; i < 3; i++)
+    if (SYMBOLP (styles[i]) && ! NILP (styles [i]))
+      p += sprintf (p, ":%s=%s", style_names[i],
+                   SDATA (SYMBOL_NAME (styles [i])));
+  if (dpi >= 0)
+    p += sprintf (p, ":dpi=%d", dpi);
+  if (spacing >= 0)
+    p += sprintf (p, ":spacing=%d", spacing);
+  if (scalable > 0)
+    p += sprintf (p, ":scalable=True");
+  else if (scalable == 0)
+    p += sprintf (p, ":scalable=False");
+  return (p - name);
+}
+
+/* Parse NAME (null terminated) and store information in FONT
+   (font-spec or font-entity).  If NAME is successfully parsed, return
+   0.  Otherwise return -1.
+
+   If NAME is XLFD and FONT is a font-entity, store
+   RESX-RESY-SPACING-AVWIDTH information as a symbol in
+   FONT_EXTRA_INDEX.  */
+
+static int
+font_parse_name (name, font)
+     char *name;
+     Lisp_Object font;
+{
+  if (name[0] == '-' || index (name, '*'))
+    return font_parse_xlfd (name, font);
+  return font_parse_fcname (name, font);
 }
 
 void
@@ -680,7 +1364,7 @@ font_merge_old_spec (name, family, registry, spec)
 {
   if (STRINGP (name))
     {
-      if (font_parse_xlfd ((char *) SDATA (name), spec, 1) < 0)
+      if (font_parse_xlfd ((char *) SDATA (name), spec) < 0)
        {
          Lisp_Object extra = Fcons (Fcons (QCname, name), Qnil);
 
@@ -700,7 +1384,8 @@ font_merge_old_spec (name, family, registry, spec)
          p1 = index (p0, '-');
          if (p1)
            {
-             if (NILP (AREF (spec, FONT_FOUNDRY_INDEX)))
+             if ((*p0 != '*' || p1 - p0 > 1)
+                 && NILP (AREF (spec, FONT_FOUNDRY_INDEX)))
                ASET (spec, FONT_FOUNDRY_INDEX,
                      intern_downcase (p0, p1 - p0));
              if (NILP (AREF (spec, FONT_FAMILY_INDEX)))
@@ -717,6 +1402,81 @@ font_merge_old_spec (name, family, registry, spec)
     }
 }
 
+static Lisp_Object
+font_lispy_object (font)
+     struct font *font;
+{
+  Lisp_Object objlist = AREF (font->entity, FONT_OBJLIST_INDEX);
+
+  for (; ! NILP (objlist); objlist = XCDR (objlist))
+    {
+      struct Lisp_Save_Value *p = XSAVE_VALUE (XCAR (objlist));
+
+      if (font == (struct font *) p->pointer)
+       break;
+    }
+  xassert (! NILP (objlist));
+  return XCAR (objlist);
+}
+
+#define LGSTRING_HEADER_SIZE 6
+#define LGSTRING_GLYPH_SIZE 8
+
+static int
+check_gstring (gstring)
+     Lisp_Object gstring;
+{
+  Lisp_Object val;
+  int i, j;
+
+  CHECK_VECTOR (gstring);
+  val = AREF (gstring, 0);
+  CHECK_VECTOR (val);
+  if (ASIZE (val) < LGSTRING_HEADER_SIZE)
+    goto err;
+  CHECK_FONT_OBJECT (LGSTRING_FONT (gstring));
+  if (! NILP (LGSTRING_LBEARING (gstring)))
+    CHECK_NUMBER (LGSTRING_LBEARING (gstring));
+  if (! NILP (LGSTRING_RBEARING (gstring)))
+    CHECK_NUMBER (LGSTRING_RBEARING (gstring));
+  if (! NILP (LGSTRING_WIDTH (gstring)))
+    CHECK_NATNUM (LGSTRING_WIDTH (gstring));
+  if (! NILP (LGSTRING_ASCENT (gstring)))
+    CHECK_NUMBER (LGSTRING_ASCENT (gstring));
+  if (! NILP (LGSTRING_DESCENT (gstring)))
+    CHECK_NUMBER (LGSTRING_DESCENT(gstring));
+
+  for (i = 0; i < LGSTRING_LENGTH (gstring); i++)
+    {
+      val = LGSTRING_GLYPH (gstring, i);
+      CHECK_VECTOR (val);
+      if (ASIZE (val) < LGSTRING_GLYPH_SIZE)
+       goto err;
+      if (NILP (LGLYPH_CHAR (val)))
+       break;
+      CHECK_NATNUM (LGLYPH_FROM (val));
+      CHECK_NATNUM (LGLYPH_TO (val));
+      CHECK_CHARACTER (LGLYPH_CHAR (val));
+      if (! NILP (LGLYPH_CODE (val)))
+       CHECK_NATNUM (LGLYPH_CODE (val));
+      if (! NILP (LGLYPH_WIDTH (val)))
+       CHECK_NATNUM (LGLYPH_WIDTH (val));
+      if (! NILP (LGLYPH_ADJUSTMENT (val)))
+       {
+         val = LGLYPH_ADJUSTMENT (val);
+         CHECK_VECTOR (val);
+         if (ASIZE (val) < 3)
+           goto err;
+         for (j = 0; j < 3; j++)
+           CHECK_NUMBER (AREF (val, j));
+       }
+    }
+  return i;
+ err:
+  error ("Invalid glyph-string format");
+  return -1;
+}
+
 \f
 /* OTF handler */
 
@@ -801,7 +1561,7 @@ font_otf_capability (font)
              Lisp_Object langsys_tag;
              int l;
 
-             if (j == script->LangSysCount)
+             if (k == script->LangSysCount)
                {
                  langsys = &script->DefaultLangSys;
                  langsys_tag = Qnil;
@@ -812,7 +1572,7 @@ font_otf_capability (font)
                  langsys_tag
                    = otf_tag_symbol (script->LangSysRecord[k].LangSysTag);
                }
-             for (l = langsys->FeatureCount -1; l >= 0; l--)
+             for (l = langsys->FeatureCount - 1; l >= 0; l--)
                {
                  OTF_Feature *feature
                    = gsub_gpos->FeatureList.Feature + langsys->FeatureIndex[l];
@@ -837,46 +1597,68 @@ font_otf_capability (font)
   return capability;
 }
 
-static int
-parse_gsub_gpos_spec (spec, script, langsys, features)
+static void
+parse_gsub_gpos_spec (spec, script, langsys, features, nbytes)
      Lisp_Object spec;
-     char **script, **langsys, **features;
+     char **script, **langsys, *features;
+     int nbytes;
 {
   Lisp_Object val;
-  int len;
-  char *p;
+  char *p, *pend;
   int asterisk;
 
+  CHECK_CONS (spec);
   val = XCAR (spec);
+  CHECK_SYMBOL (val);
   *script = (char *) SDATA (SYMBOL_NAME (val));
   spec = XCDR (spec);
+  CHECK_CONS (spec);
   val = XCAR (spec);
+  CHECK_SYMBOL (val);
   *langsys = NILP (val) ? NULL : (char *) SDATA (SYMBOL_NAME (val));
   spec = XCDR (spec);
-  len = XINT (Flength (spec));
-  *features = p = malloc (6 * len);
-  if (! p)
-    return -1;
 
+  p = features, pend = p + nbytes - 1;
+  *p = '\0';
   for (asterisk = 0; CONSP (spec); spec = XCDR (spec))
     {
       val = XCAR (spec);
+      CHECK_SYMBOL (val);
+      if (p > features)
+       {
+         if (p >= pend)
+           break;
+         *p++ = ',';
+       }
       if (SREF (SYMBOL_NAME (val), 0) == '*')
        {
          asterisk = 1;
-         p += sprintf (p, ",*");
+         if (p >= pend)
+           break;
+         *p++ = '*';
        }
       else if (! asterisk)
-       p += sprintf (p, ",%s", SDATA (SYMBOL_NAME (val)));
+       {
+         val = SYMBOL_NAME (val);
+         if (p + SBYTES (val) >= pend)
+           break;
+         p += sprintf (p, "%s", SDATA (val));
+       }
       else
-       p += sprintf (p, ",~%s", SDATA (SYMBOL_NAME (val)));
+       {
+         val = SYMBOL_NAME (val);
+         if (p + 1 + SBYTES (val)>= pend)
+           break;
+         p += sprintf (p, "~%s", SDATA (val));
+       }
     }
-  return 0;
+  if (CONSP (spec))
+    error ("OTF spec too long");
 }
 
 #define DEVICE_DELTA(table, size)                              \
   (((size) >= (table).StartSize && (size) <= (table).EndSize)  \
-   ? (table).DeltaValue[(size) >= (table).StartSize]           \
+   ? (table).DeltaValue[(size) - (table).StartSize]            \
    : 0)
 
 void
@@ -900,49 +1682,66 @@ adjust_anchor (struct font *font, OTF_Anchor *anchor,
     }
 }
 
+#define REPLACEMENT_CHARACTER 0xFFFD
 
 /* Drive FONT's OTF GSUB features according to GSUB_SPEC.  See the
    comment of (sturct font_driver).otf_gsub.  */
 
 int
-font_otf_gsub (font, gsub_spec, gstring_in, from, to, gstring_out, idx)
+font_otf_gsub (font, gsub_spec, gstring_in, from, to, gstring_out, idx,
+              alternate_subst)
      struct font *font;
      Lisp_Object gsub_spec;
      Lisp_Object gstring_in;
      int from, to;
      Lisp_Object gstring_out;
-     int idx;
+     int idx, alternate_subst;
 {
   int len;
   int i;
   OTF *otf;
   OTF_GlyphString otf_gstring;
   OTF_Glyph *g;
-  char *script, *langsys, *features;
+  char *script, *langsys, features[256];
+  int need_cmap;
+
+  parse_gsub_gpos_spec (gsub_spec, &script, &langsys, features, 256);
 
   otf = otf_open (font->entity, font->file_name);
   if (! otf)
     return 0;
   if (OTF_get_table (otf, "head") < 0)
     return 0;
+  if (OTF_get_table (otf, "cmap") < 0)
+    return 0;
   if (OTF_check_table (otf, "GSUB") < 0)
     return 0;    
-  if (parse_gsub_gpos_spec (gsub_spec, &script, &langsys, &features) < 0)
-    return 0;
   len = to - from;
   otf_gstring.size = otf_gstring.used = len;
   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
-  for (i = 0; i < len; i++)
+  for (i = 0, need_cmap = 0; i < len; i++)
     {
       Lisp_Object g = LGSTRING_GLYPH (gstring_in, from + i);
 
       otf_gstring.glyphs[i].c = XINT (LGLYPH_CHAR (g));
-      otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (g));
+      if (otf_gstring.glyphs[i].c == REPLACEMENT_CHARACTER)
+       otf_gstring.glyphs[i].c = 0;
+      if (NILP (LGLYPH_CODE (g)))
+       {
+         otf_gstring.glyphs[i].glyph_id = 0;
+         need_cmap = 1;
+       }
+      else
+       otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (g));
     }
 
+  if (need_cmap)
+    OTF_drive_cmap (otf, &otf_gstring);
   OTF_drive_gdef (otf, &otf_gstring);
-  if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, features) < 0)
+  if ((alternate_subst
+       ? OTF_drive_gsub_alternate (otf, &otf_gstring, script, langsys, features)
+       : OTF_drive_gsub (otf, &otf_gstring, script, langsys, features)) < 0)
     {
       free (otf_gstring.glyphs);
       return 0;
@@ -981,7 +1780,10 @@ font_otf_gsub (font, gsub_spec, gstring_in, from, to, gstring_out, idx)
          glyph = LGSTRING_GLYPH (gstring_out, idx + i);
          ASET (glyph, 0, min_idx);
          ASET (glyph, 1, max_idx);
-         LGLYPH_SET_CHAR (glyph, make_number (g->c));
+         if (g->c > 0)
+           LGLYPH_SET_CHAR (glyph, make_number (g->c));
+         else
+           LGLYPH_SET_CHAR (glyph, make_number (REPLACEMENT_CHARACTER));
          LGLYPH_SET_CODE (glyph, make_number (g->glyph_id));
        }
     }
@@ -1005,30 +1807,43 @@ font_otf_gpos (font, gpos_spec, gstring, from, to)
   OTF *otf;
   OTF_GlyphString otf_gstring;
   OTF_Glyph *g;
-  char *script, *langsys, *features;
+  char *script, *langsys, features[256];
+  int need_cmap;
   Lisp_Object glyph;
   int u, size;
   Lisp_Object base, mark;
 
+  parse_gsub_gpos_spec (gpos_spec, &script, &langsys, features, 256);
+
   otf = otf_open (font->entity, font->file_name);
   if (! otf)
     return 0;
   if (OTF_get_table (otf, "head") < 0)
     return 0;
+  if (OTF_get_table (otf, "cmap") < 0)
+    return 0;
   if (OTF_check_table (otf, "GPOS") < 0)
     return 0;    
-  if (parse_gsub_gpos_spec (gpos_spec, &script, &langsys, &features) < 0)
-    return 0;
   len = to - from;
   otf_gstring.size = otf_gstring.used = len;
   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
-  for (i = 0; i < len; i++)
+  for (i = 0, need_cmap = 0; i < len; i++)
     {
       glyph = LGSTRING_GLYPH (gstring, from + i);
-      otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (glyph));
+      otf_gstring.glyphs[i].c = XINT (LGLYPH_CHAR (glyph));
+      if (otf_gstring.glyphs[i].c == REPLACEMENT_CHARACTER)
+       otf_gstring.glyphs[i].c = 0;
+      if (NILP (LGLYPH_CODE (glyph)))
+       {
+         otf_gstring.glyphs[i].glyph_id = 0;
+         need_cmap = 1;
+       }
+      else
+       otf_gstring.glyphs[i].glyph_id = XINT (LGLYPH_CODE (glyph));
     }
-
+  if (need_cmap)
+    OTF_drive_cmap (otf, &otf_gstring);
   OTF_drive_gdef (otf, &otf_gstring);
 
   if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, features) < 0)
@@ -1043,7 +1858,7 @@ font_otf_gpos (font, gpos_spec, gstring, from, to)
   for (i = 0, g = otf_gstring.glyphs; i < otf_gstring.used; i++, g++)
     {
       Lisp_Object prev;
-      int xoff = 0, yoff = 0,  width_adjust = 0;
+      int xoff = 0, yoff = 0, width_adjust = 0;
 
       if (! g->glyph_id)
        continue;
@@ -1107,42 +1922,42 @@ font_otf_gpos (font, gpos_spec, gstring, from, to)
                width = font->driver->text_extents (font, &code, 1, NULL);
                LGLYPH_SET_WIDTH (prev, make_number (width));
              }
+           else
+             width = XINT (LGLYPH_WIDTH (prev));
            xoff = XINT (LGLYPH_XOFF (prev)) + (base_x - width) - mark_x;
            yoff = XINT (LGLYPH_YOFF (prev)) + mark_y - base_y;
          }
        }
+
+      if (xoff || yoff || width_adjust)
+       {
+         Lisp_Object adjustment = Fmake_vector (make_number (3), Qnil);
+
+         ASET (adjustment, 0, make_number (xoff));
+         ASET (adjustment, 1, make_number (yoff));
+         ASET (adjustment, 2, make_number (width_adjust));
+         LGLYPH_SET_ADJUSTMENT (glyph, adjustment);
+       }
+
       if (g->GlyphClass == OTF_GlyphClass0)
        base = mark = glyph;
       else if (g->GlyphClass == OTF_GlyphClassMark)
        mark = glyph;
       else
        base = glyph;
-
-      LGLYPH_SET_XOFF (glyph, make_number (xoff));
-      LGLYPH_SET_YOFF (glyph, make_number (yoff));
-      LGLYPH_SET_WADJUST (glyph, make_number (width_adjust));
     }
 
   free (otf_gstring.glyphs);  
-  return 0;
+  return i;
 }
 
 #endif /* HAVE_LIBOTF */
 
 \f
-/* glyph-string handler */
-
-/* GSTRING is a vector of this form:
-       [ [FONT-OBJECT LBEARING RBEARING WITH ASCENT DESCENT] GLYPH ... ]
-   and GLYPH is a vector of this form:
-       [ FROM-IDX TO-IDX C CODE X-OFF Y-OFF WIDTH WADJUST ]
-   where
-       FROM-IDX and TO-IDX are used internally and should not be touched.
-       C is a character of the glyph.
-       CODE is a glyph-code of C in FONT-OBJECT.
-       X-OFF and Y-OFF are offests to the base position for the glyph.
-       WIDTH is a normal width of the glyph.
-       WADJUST is an adjustment to the normal width of the glyph.  */
+/* G-string (glyph string) handler */
+
+/* G-string is a vector of the form [HEADER GLYPH ...].
+   See the docstring of `font-make-gstring' for more detail.  */
 
 struct font *
 font_prepare_composition (cmp)
@@ -1163,15 +1978,18 @@ font_prepare_composition (cmp)
   for (i = 0; i < len; i++)
     {
       Lisp_Object g = LGSTRING_GLYPH (gstring, i);
-      unsigned code = XINT (LGLYPH_CODE (g));
+      unsigned code;
       struct font_metrics metrics;
 
+      if (NILP (LGLYPH_FROM (g)))
+       break;
+      code = XINT (LGLYPH_CODE (g));
       font->driver->text_extents (font, &code, 1, &metrics);
       LGLYPH_SET_WIDTH (g, make_number (metrics.width));
-      metrics.lbearing += XINT (LGLYPH_XOFF (g));
-      metrics.rbearing += XINT (LGLYPH_XOFF (g));
-      metrics.ascent += XINT (LGLYPH_YOFF (g));
-      metrics.descent += XINT (LGLYPH_YOFF (g));
+      metrics.lbearing += LGLYPH_XOFF (g);
+      metrics.rbearing += LGLYPH_XOFF (g);
+      metrics.ascent += LGLYPH_YOFF (g);
+      metrics.descent += LGLYPH_YOFF (g);
 
       if (cmp->lbearing > cmp->pixel_width + metrics.lbearing)
        cmp->lbearing = cmp->pixel_width + metrics.lbearing;
@@ -1181,8 +1999,9 @@ font_prepare_composition (cmp)
        cmp->ascent = metrics.ascent;
       if (cmp->descent < metrics.descent)
        cmp->descent = metrics.descent;
-      cmp->pixel_width += metrics.width + XINT (LGLYPH_WADJUST (g));
+      cmp->pixel_width += metrics.width + LGLYPH_WADJUST (g);
     }
+  cmp->glyph_len = i;
   LGSTRING_SET_LBEARING (gstring, make_number (cmp->lbearing));
   LGSTRING_SET_RBEARING (gstring, make_number (cmp->rbearing));
   LGSTRING_SET_WIDTH (gstring, make_number (cmp->pixel_width));
@@ -1252,7 +2071,7 @@ font_gstring_produce (old, from, to, new, idx, code, n)
 \f
 /* Font sorting */
 
-static unsigned font_score P_ ((Lisp_Object, Lisp_Object));
+static unsigned font_score P_ ((Lisp_Object, Lisp_Object *));
 static int font_compare P_ ((const void *, const void *));
 static Lisp_Object font_sort_entites P_ ((Lisp_Object, Lisp_Object,
                                          Lisp_Object, Lisp_Object));
@@ -1271,43 +2090,45 @@ static Lisp_Object font_sort_entites P_ ((Lisp_Object, Lisp_Object,
    property in a score.  */
 static int sort_shift_bits[FONT_SIZE_INDEX + 1];
 
-/* Score font-entity ENTITY against font-spec SPEC.  The return value
-   indicates how different ENTITY is compared with SPEC.  */
+/* Score font-entity ENTITY against properties of font-spec SPEC_PROP.
+   The return value indicates how different ENTITY is compared with
+   SPEC_PROP.  */
 
 static unsigned
-font_score (entity, spec)
-     Lisp_Object entity, spec;
+font_score (entity, spec_prop)
+     Lisp_Object entity, *spec_prop;
 {
   unsigned score = 0;
   int i;
-  /* Score atomic fields.  Maximum difference is 1. */
+  /* Score four atomic fields.  Maximum difference is 1. */
   for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
-    {
-      Lisp_Object val = AREF (spec, i);
+    if (! NILP (spec_prop[i])
+       && ! EQ (spec_prop[i], AREF (entity, i)))
+      score |= 1 << sort_shift_bits[i];
 
-      if (! NILP (val)
-         && ! EQ (val, AREF (entity, i)))
-       score |= 1 << sort_shift_bits[i];
-    }
-
-  /* Score numeric fields.  Maximum difference is 127. */
+  /* Score four numeric fields.  Maximum difference is 127. */
   for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
     {
-      Lisp_Object spec_val = AREF (spec, i);
       Lisp_Object entity_val = AREF (entity, i);
 
-      if (! NILP (spec_val) && ! EQ (spec_val, entity_val))
+      if (! NILP (spec_prop[i]) && ! EQ (spec_prop[i], entity_val))
        {
          if (! INTEGERP (entity_val))
            score |= 127 << sort_shift_bits[i];
-         else if (i < FONT_SIZE_INDEX
-                  || XINT (entity_val) != 0)
+         else
            {
-             int diff = XINT (entity_val) - XINT (spec_val);
+             int diff = XINT (entity_val) - XINT (spec_prop[i]);
 
              if (diff < 0)
                diff = - diff;
-             score |= min (diff, 127) << sort_shift_bits[i];
+             if (i == FONT_SIZE_INDEX)
+               {
+                 if (XINT (entity_val) > 0
+                     && diff > FONT_PIXEL_SIZE_QUANTUM)
+                   score |= min (diff, 127) << sort_shift_bits[i];
+               }
+             else
+               score |= min (diff, 127) << sort_shift_bits[i];
            }
        }
     }
@@ -1337,58 +2158,46 @@ struct font_sort_data
 
 /* Sort font-entities in vector VEC by closeness to font-spec PREFER.
    If PREFER specifies a point-size, calculate the corresponding
-   pixel-size from the Y-resolution of FRAME before sorting.  If SPEC
-   is not nil, it is a font-spec to get the font-entities in VEC.  */
+   pixel-size from QCdpi property of PREFER or from the Y-resolution
+   of FRAME before sorting.  If SPEC is not nil, it is a font-spec to
+   get the font-entities in VEC.  */
 
 static Lisp_Object
 font_sort_entites (vec, prefer, frame, spec)
      Lisp_Object vec, prefer, frame, spec;
 {
-  Lisp_Object size;
+  Lisp_Object prefer_prop[FONT_SPEC_MAX];
   int len, i;
   struct font_sort_data *data;
-  int prefer_is_copy = 0;
   USE_SAFE_ALLOCA;
 
   len = ASIZE (vec);
   if (len <= 1)
     return vec;
 
-  size = AREF (spec, FONT_SIZE_INDEX);
-  if (FLOATP (size))
-    {
-      double point_size = XFLOAT_DATA (size) * 10;
-      int pixel_size =  POINT_TO_PIXEL (point_size, XFRAME (frame)->resy);
-
-      prefer = Fcopy_sequence (prefer);
-      ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
-      prefer_is_copy = 1;
-    }
+  for (i = FONT_FOUNDRY_INDEX; i <= FONT_SIZE_INDEX; i++)
+    prefer_prop[i] = AREF (prefer, i);
 
   if (! NILP (spec))
     {
       /* As it is assured that all fonts in VEC match with SPEC, we
         should ignore properties specified in SPEC.  So, set the
-        corresponding properties in PREFER nil. */
+        corresponding properties in PREFER_PROP to nil. */
       for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
-       if (! NILP (AREF (spec, i)) && ! NILP (AREF (prefer, i)))
-         break;
-      if (i <= FONT_SIZE_INDEX)
-       {
-         if (! prefer_is_copy)
-           prefer = Fcopy_sequence (prefer);
-         for (; i <= FONT_SIZE_INDEX; i++)
-           if (! NILP (AREF (spec, i)) && ! NILP (AREF (prefer, i)))
-             ASET (prefer, i, Qnil);
-       }
+       if (! NILP (AREF (spec, i)))
+         prefer_prop[i++] = Qnil;
     }
 
+  if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
+    prefer_prop[FONT_SIZE_INDEX]
+      = make_number (font_pixel_size (XFRAME (frame), prefer));
+
   /* Scoring and sorting.  */
   SAFE_ALLOCA (data, struct font_sort_data *, (sizeof *data) * len);
   for (i = 0; i < len; i++)
     {
       data[i].entity = AREF (vec, i);
-      data[i].score = font_score (data[i].entity, prefer);
+      data[i].score = font_score (data[i].entity, prefer_prop);
     }
   qsort (data, len, sizeof *data, font_compare);
   for (i = 0; i < len; i++)
@@ -1455,6 +2264,24 @@ font_symbolic_width (font)
   return width;
 }
 
+int
+font_match_p (spec, entity)
+     Lisp_Object spec, entity;
+{
+  int i;
+
+  for (i = FONT_FOUNDRY_INDEX; i < FONT_SIZE_INDEX; i++)
+    if (! NILP (AREF (spec, i))
+       && ! EQ (AREF (spec, i), AREF (entity, i)))
+      return 0;
+  if (INTEGERP (AREF (spec, FONT_SIZE_INDEX))
+      && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0
+      && (XINT (AREF (spec, FONT_SIZE_INDEX))
+         != XINT (AREF (entity, FONT_SIZE_INDEX))))
+    return 0;
+  return 1;
+}
+
 Lisp_Object
 font_find_object (font)
      struct font *font;
@@ -1483,7 +2310,7 @@ font_list_entities (frame, spec)
 {
   FRAME_PTR f = XFRAME (frame);
   struct font_driver_list *driver_list = f->font_driver_list;
-  Lisp_Object ftype, family, alternate_familes;
+  Lisp_Object ftype, family, size, alternate_familes;
   Lisp_Object *vec = alloca (sizeof (Lisp_Object) * num_font_drivers);
   int i;
 
@@ -1502,11 +2329,16 @@ font_list_entities (frame, spec)
       if (! NILP (alternate_familes))
        alternate_familes = XCDR (alternate_familes);
     }
+  size = AREF (spec, FONT_SIZE_INDEX);
+  if (FLOATP (size))
+    ASET (spec, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
+
   xassert (ASIZE (spec) == FONT_SPEC_MAX);
   ftype = AREF (spec, FONT_TYPE_INDEX);
   
   for (i = 0; driver_list; driver_list = driver_list->next)
-    if (NILP (ftype) || EQ (driver_list->driver->type, ftype))
+    if (driver_list->on
+       && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
       {
        Lisp_Object cache = driver_list->driver->get_cache (frame);
        Lisp_Object tail = alternate_familes;
@@ -1541,9 +2373,53 @@ font_list_entities (frame, spec)
       }
   ASET (spec, FONT_TYPE_INDEX, ftype);
   ASET (spec, FONT_FAMILY_INDEX, family);
+  ASET (spec, FONT_SIZE_INDEX, size);
   return (i > 0 ? Fvconcat (i, vec) : null_vector);
 }
 
+static Lisp_Object
+font_matching_entity (frame, spec)
+     Lisp_Object frame, spec;
+{
+  FRAME_PTR f = XFRAME (frame);
+  struct font_driver_list *driver_list = f->font_driver_list;
+  Lisp_Object ftype, size, entity;
+
+  ftype = AREF (spec, FONT_TYPE_INDEX);
+  size = AREF (spec, FONT_SIZE_INDEX);
+  if (FLOATP (size))
+    ASET (spec, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
+  entity = Qnil;
+  for (; driver_list; driver_list = driver_list->next)
+    if (driver_list->on
+       && (NILP (ftype) || EQ (driver_list->driver->type, ftype)))
+      {
+       Lisp_Object cache = driver_list->driver->get_cache (frame);
+       Lisp_Object key;
+
+       xassert (CONSP (cache));
+       ASET (spec, FONT_TYPE_INDEX, driver_list->driver->type);
+       key = Fcons (spec, Qnil);
+       entity = assoc_no_quit (key, XCDR (cache));
+       if (CONSP (entity))
+         entity = XCDR (entity);
+       else
+         {
+           entity = driver_list->driver->match (frame, spec);
+           if (! NILP (entity))
+             {
+               XSETCAR (key, Fcopy_sequence (spec));
+               XSETCDR (cache, Fcons (Fcons (key, entity), XCDR (cache)));
+             }
+         }
+       if (! NILP (entity))
+         break;
+      }
+  ASET (spec, FONT_TYPE_INDEX, ftype);
+  ASET (spec, FONT_SIZE_INDEX, size);
+  return entity;
+}
+
 static int num_fonts;
 
 static Lisp_Object
@@ -1583,6 +2459,8 @@ font_open_entity (f, entity, pixel_size)
   font = driver_list->driver->open (f, entity, pixel_size);
   if (! font)
     return Qnil;
+  font->scalable = XINT (size) == 0;
+
   val = make_save_value (font, 1);
   ASET (entity, FONT_OBJLIST_INDEX,
        Fcons (val, AREF (entity, FONT_OBJLIST_INDEX)));
@@ -1595,47 +2473,66 @@ font_close_object (f, font_object)
      FRAME_PTR f;
      Lisp_Object font_object;
 {
-  struct font *font;
-  Lisp_Object objlist = AREF (font->entity, FONT_OBJLIST_INDEX);
+  struct font *font = XSAVE_VALUE (font_object)->pointer;
+  Lisp_Object objlist;
   Lisp_Object tail, prev = Qnil;
 
+  XSAVE_VALUE (font_object)->integer--;
+  xassert (XSAVE_VALUE (font_object)->integer >= 0);
+  if (XSAVE_VALUE (font_object)->integer > 0)
+    return;
+
+  objlist = AREF (font->entity, FONT_OBJLIST_INDEX);
   for (prev = Qnil, tail = objlist; CONSP (tail);
        prev = tail, tail = XCDR (tail))
     if (EQ (font_object, XCAR (tail)))
       {
-       struct Lisp_Save_Value *p = XSAVE_VALUE (font_object);
-
-       xassert (p->integer > 0);
-       p->integer--;
-       if (p->integer == 0)
-         {
-           if (font->driver->close)
-             font->driver->close (f, p->pointer);
-           p->pointer = NULL;
-           if (NILP (prev))
-             ASET (font->entity, FONT_OBJLIST_INDEX, XCDR (objlist));
-           else
-             XSETCDR (prev, XCDR (objlist));
-         }
-       break;
+       if (font->driver->close)
+         font->driver->close (f, font);
+       XSAVE_VALUE (font_object)->pointer = NULL;
+       if (NILP (prev))
+         ASET (font->entity, FONT_OBJLIST_INDEX, XCDR (objlist));
+       else
+         XSETCDR (prev, XCDR (objlist));
+       return;
       }
+  abort ();
 }
 
 int
-font_has_char (f, font_entity, c)
+font_has_char (f, font, c)
      FRAME_PTR f;
-     Lisp_Object font_entity;
+     Lisp_Object font;
      int c;
 {
-  Lisp_Object type = AREF (font_entity, FONT_TYPE_INDEX);
-  struct font_driver_list *driver_list;
+  struct font *fontp;
 
-  for (driver_list = f->font_driver_list;
-       driver_list && ! EQ (driver_list->driver->type, type);
-       driver_list = driver_list->next);
-  if (! driver_list)
-    return -1;
-  return driver_list->driver->has_char (font_entity, c);
+  if (FONT_ENTITY_P (font))
+    {
+      Lisp_Object type = AREF (font, FONT_TYPE_INDEX);
+      struct font_driver_list *driver_list;
+
+      for (driver_list = f->font_driver_list;
+          driver_list && ! EQ (driver_list->driver->type, type);
+          driver_list = driver_list->next);
+      if (! driver_list)
+       return 0;
+      if (! driver_list->driver->has_char)
+       return -1;
+      return driver_list->driver->has_char (font, c);
+    }
+
+  xassert (FONT_OBJECT_P (font));
+  fontp = XSAVE_VALUE (font)->pointer;
+
+  if (fontp->driver->has_char)
+    {
+      int result = fontp->driver->has_char (fontp->entity, c);
+
+      if (result >= 0)
+       return result;
+    }
+  return (fontp->driver->encode_char (fontp, c) != FONT_INVALID_CODE);
 }
 
 unsigned
@@ -1648,15 +2545,30 @@ font_encode_char (font_object, c)
   return font->driver->encode_char (font, c);
 }
 
-char *
+Lisp_Object
 font_get_name (font_object)
      Lisp_Object font_object;
 {
   struct font *font = XSAVE_VALUE (font_object)->pointer;
+  char *name = (font->font.full_name ? font->font.full_name
+               : font->font.name ? font->font.name
+               : NULL);
+
+  return (name ? make_unibyte_string (name, strlen (name)) : null_string);
+}
+
+Lisp_Object
+font_get_spec (font_object)
+     Lisp_Object font_object;
+{
+  struct font *font = XSAVE_VALUE (font_object)->pointer;
+  Lisp_Object spec = Ffont_spec (0, NULL);
+  int i;
 
-  return (font->font.full_name ? font->font.full_name
-         : font->file_name ? font->file_name
-         : "");
+  for (i = 0; i < FONT_SIZE_INDEX; i++)
+    ASET (spec, i, AREF (font->entity, i));
+  ASET (spec, FONT_SIZE_INDEX, make_number (font->pixel_size));
+  return spec;
 }
 
 Lisp_Object
@@ -1669,7 +2581,8 @@ font_get_frame (font)
   return AREF (font, FONT_FRAME_INDEX);
 }
 
-extern Lisp_Object Qunspecified, Qignore_defface;
+/* Find a font entity best matching with LFACE.  If SPEC is non-nil,
+   the font must exactly match with it.  */
 
 Lisp_Object
 font_find_for_lface (f, lface, spec)
@@ -1677,106 +2590,69 @@ font_find_for_lface (f, lface, spec)
      Lisp_Object *lface;
      Lisp_Object spec;
 {
-  Lisp_Object attrs[LFACE_SLANT_INDEX + 1];
-  Lisp_Object frame, val, entities;
+  Lisp_Object frame, entities;
   int i;
-  unsigned char try_unspecified[FONT_SPEC_MAX];
-
-  for (i = 0; i <= LFACE_SLANT_INDEX; i++)
-    {
-      val = lface[i];
-      if (EQ (val, Qunspecified) || EQ (val, Qignore_defface))
-       val = Qnil;
-      attrs[i] = val;
-    }
-  if (NILP (spec))
-    for (i = 0; i < FONT_SPEC_MAX; i++)
-      ASET (scratch_font_spec, i, Qnil);
-  else
-    for (i = 0; i < FONT_SPEC_MAX; i++)
-      ASET (scratch_font_spec, i, AREF (spec, i));
-
-  /* If SPEC doesn't specify a specific property, it can be tried with
-     nil even if FACE specifies it.  */
-  for (i = FONT_FOUNDRY_INDEX; i <= FONT_SIZE_INDEX; i++)
-    try_unspecified[i] = NILP (AREF (scratch_font_spec, i));
-
-  if (STRINGP (attrs[LFACE_FONT_INDEX]))
-    font_merge_old_spec (attrs[LFACE_FONT_INDEX], Qnil, Qnil,
-                             scratch_font_spec);
-  if (NILP (AREF (scratch_font_spec, FONT_FAMILY_INDEX))
-      && ! NILP (attrs[LFACE_FAMILY_INDEX]))
-    font_merge_old_spec (Qnil, attrs[LFACE_FAMILY_INDEX], Qnil,
-                             scratch_font_spec);
-  if (NILP (AREF (scratch_font_spec, FONT_REGISTRY_INDEX)))
-    {
-      ASET (scratch_font_spec, FONT_REGISTRY_INDEX, intern ("iso8859-1"));
-      try_unspecified[FONT_REGISTRY_INDEX] = 0;
-    }
-
-  for (i = FONT_FAMILY_INDEX; i <= FONT_SIZE_INDEX; i++)
-    if (try_unspecified[i]
-       && NILP (AREF (scratch_font_spec, i)))
-      try_unspecified[i] = 0;
 
   XSETFRAME (frame, f);
-  entities = font_list_entities (frame, scratch_font_spec);
-  while (ASIZE (entities) == 0)
+
+  if (NILP (spec))
     {
-      if (try_unspecified[FONT_WEIGHT_INDEX]
-         || try_unspecified[FONT_SLANT_INDEX]
-         || try_unspecified[FONT_WIDTH_INDEX]
-         || try_unspecified[FONT_SIZE_INDEX])
+      for (i = 0; i < FONT_SPEC_MAX; i++)
+       ASET (scratch_font_spec, i, Qnil);
+      ASET (scratch_font_spec, FONT_REGISTRY_INDEX, Qiso8859_1);
+
+      if (! NILP (lface[LFACE_FAMILY_INDEX]))
+       font_merge_old_spec (Qnil, lface[LFACE_FAMILY_INDEX], Qnil,
+                            scratch_font_spec);
+      entities = font_list_entities (frame, scratch_font_spec);
+      while (ASIZE (entities) == 0)
        {
-         for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
+         /* Try without FOUNDRY or FAMILY.  */
+         if (! NILP (AREF (scratch_font_spec, FONT_FOUNDRY_INDEX)))
            {
-             try_unspecified[i] = 0;
-             ASET (scratch_font_spec, i, Qnil);
+             ASET (scratch_font_spec, FONT_FOUNDRY_INDEX, Qnil);
+             entities = font_list_entities (frame, scratch_font_spec);
            }
-         entities = font_list_entities (frame, scratch_font_spec);
-       }
-      else if (try_unspecified[FONT_FOUNDRY_INDEX])
-       {
-         try_unspecified[FONT_FOUNDRY_INDEX] = 0;
-         ASET (scratch_font_spec, FONT_FOUNDRY_INDEX, Qnil);
-         entities = font_list_entities (frame, scratch_font_spec);
-       }
-      else if (try_unspecified[FONT_FAMILY_INDEX])
-       {
-         try_unspecified[FONT_FAMILY_INDEX] = 0;
-         ASET (scratch_font_spec, FONT_FAMILY_INDEX, Qnil);
-         entities = font_list_entities (frame, scratch_font_spec);
+         else if (! NILP (AREF (scratch_font_spec, FONT_FAMILY_INDEX)))
+           {
+             ASET (scratch_font_spec, FONT_FAMILY_INDEX, Qnil);
+             entities = font_list_entities (frame, scratch_font_spec);
+           }
+         else
+           break;
        }
-      else
-       return Qnil;
+    }
+  else
+    {
+      for (i = 0; i < FONT_SPEC_MAX; i++)
+       ASET (scratch_font_spec, i, AREF (spec, i));
+      if (NILP (AREF (spec, FONT_REGISTRY_INDEX)))
+       ASET (scratch_font_spec, FONT_REGISTRY_INDEX, Qiso8859_1);
+      entities = font_list_entities (frame, scratch_font_spec);
     }
 
+  if (ASIZE (entities) == 0)
+    return Qnil;
   if (ASIZE (entities) > 1)
     {
+      /* Sort fonts by properties specified in LFACE.  */
       Lisp_Object prefer = scratch_font_prefer;
+      double pt;
+
+      if (! NILP (lface[LFACE_FAMILY_INDEX]))
+       font_merge_old_spec (Qnil, lface[LFACE_FAMILY_INDEX], Qnil, prefer);
+      ASET (prefer, FONT_WEIGHT_INDEX,
+           font_prop_validate_style (FONT_WEIGHT_INDEX, QCweight,
+                                     lface[LFACE_WEIGHT_INDEX]));
+      ASET (prefer, FONT_SLANT_INDEX,
+           font_prop_validate_style (FONT_SLANT_INDEX, QCslant,
+                                     lface[LFACE_SLANT_INDEX]));
+      ASET (prefer, FONT_WIDTH_INDEX,
+           font_prop_validate_style (FONT_WIDTH_INDEX, QCwidth,
+                                     lface[LFACE_SWIDTH_INDEX]));
+      pt = XINT (lface[LFACE_HEIGHT_INDEX]);
+      ASET (prefer, FONT_SIZE_INDEX, make_float (pt / 10));
 
-      for (i = 0; i < FONT_WEIGHT_INDEX; i++)
-       ASET (prefer, i, Qnil);
-      if (! NILP (attrs[LFACE_WEIGHT_INDEX]))
-       ASET (prefer, FONT_WEIGHT_INDEX,
-             font_prop_validate_style (FONT_WEIGHT_INDEX,
-                                       attrs[LFACE_WEIGHT_INDEX]));
-      if (! NILP (attrs[LFACE_SLANT_INDEX]))
-       ASET (prefer, FONT_SLANT_INDEX,
-             font_prop_validate_style (FONT_SLANT_INDEX,
-                                       attrs[LFACE_SLANT_INDEX]));
-      if (! NILP (attrs[LFACE_SWIDTH_INDEX]))
-       ASET (prefer, FONT_WIDTH_INDEX,
-             font_prop_validate_style (FONT_WIDTH_INDEX,
-                                       attrs[LFACE_SWIDTH_INDEX]));
-      if (! NILP (attrs[LFACE_HEIGHT_INDEX]))
-       {
-         int size;
-
-         val = attrs[LFACE_HEIGHT_INDEX];
-         size = POINT_TO_PIXEL (XINT (val), f->resy);
-         ASET (prefer, FONT_SIZE_INDEX, make_number (size));
-       }
       font_sort_entites (entities, prefer, frame, spec);
     }
 
@@ -1789,9 +2665,11 @@ font_open_for_lface (f, lface, entity)
      Lisp_Object *lface;
      Lisp_Object entity;
 {
-  int pt = XINT (lface[LFACE_HEIGHT_INDEX]);
-  int size = POINT_TO_PIXEL (pt, f->resy);
+  double pt = XINT (lface[LFACE_HEIGHT_INDEX]);
+  int size;
 
+  pt /= 10;
+  size = POINT_TO_PIXEL (pt, f->resy);
   return font_open_entity (f, entity, size);
 }
 
@@ -1800,30 +2678,33 @@ font_load_for_face (f, face)
      FRAME_PTR f;
      struct face *face;
 {
-  Lisp_Object entity;
-
-  face->font_info_id = -1;
-  face->font_info = NULL;
-  face->font = NULL;
-  face->font_name = NULL;
+  Lisp_Object font_object = face->lface[LFACE_FONT_INDEX];
 
-  entity = font_find_for_lface (f, face->lface, Qnil);
-  if (! NILP (entity))
+  if (NILP (font_object))
     {
-      Lisp_Object font_object = font_open_for_lface (f, face->lface, entity);
+      Lisp_Object entity = font_find_for_lface (f, face->lface, Qnil);
 
-      if (! NILP (font_object))
-       {
-         struct font *font = XSAVE_VALUE (font_object)->pointer;
+      if (! NILP (entity))
+       font_object = font_open_for_lface (f, face->lface, entity);
+    }
 
-         face->font = font->font.font;
-         face->font_info = (struct font_info *) font;
-         face->font_info_id = 0;
-         face->font_name = font->font.full_name;
-       }
+  if (! NILP (font_object))
+    {
+      struct font *font = XSAVE_VALUE (font_object)->pointer;
+
+      face->font = font->font.font;
+      face->font_info = (struct font_info *) font;
+      face->font_info_id = 0;
+      face->font_name = font->font.full_name;
+    }
+  else
+    {
+      face->font = NULL;
+      face->font_info = NULL;
+      face->font_info_id = -1;
+      face->font_name = NULL;
+      add_to_log ("Unable to load font for a face%s", null_string, Qnil);
     }
-  if (! face->font)
-    add_to_log ("Unable to load font for a face%s", null_string, Qnil);
 }
 
 void
@@ -1854,32 +2735,60 @@ font_open_by_name (f, name)
      FRAME_PTR f;
      char *name;
 {
-  Lisp_Object spec = Ffont_spec (0, NULL);
-  Lisp_Object entities = Qnil;
+  Lisp_Object args[2];
+  Lisp_Object spec, prefer, size, entity, entity_list;
   Lisp_Object frame;
+  int i;
   int pixel_size;
 
   XSETFRAME (frame, f);
 
-  ASET (spec, FONT_EXTRA_INDEX,
-       Fcons (Fcons (QCname, make_unibyte_string (name, strlen (name))), 
-              Qnil));
-  entities = font_list_entities (frame, spec);
-  if (ASIZE (entities) == 0)
-    return Qnil;
-  pixel_size = XINT (AREF (AREF (entities, 0), FONT_SIZE_INDEX));
+  args[0] = QCname;
+  args[1] = make_unibyte_string (name, strlen (name));
+  spec = Ffont_spec (2, args);
+  prefer = scratch_font_prefer;
+  for (i = FONT_WEIGHT_INDEX; i < FONT_SIZE_INDEX; i++)
+    if (NILP (AREF (spec, i)))
+      ASET (prefer, i, make_number (100));
+  size = AREF (spec, FONT_SIZE_INDEX);
+  if (NILP (size))
+    pixel_size = 0;
+  else if (INTEGERP (size))
+    pixel_size = XINT (size);
+  else                         /* FLOATP (size) */
+    {
+      double pt = XFLOAT_DATA (size);
+
+      pixel_size = POINT_TO_PIXEL (pt, f->resy);
+      size = make_number (pixel_size);
+      ASET (spec, FONT_SIZE_INDEX, size);
+    }
   if (pixel_size == 0)
-    pixel_size = 12;
-  return font_open_entity (f, AREF (entities, 0), pixel_size);
+    {
+      pixel_size = POINT_TO_PIXEL (12.0, f->resy);
+      size = make_number (pixel_size);
+    }
+  ASET (prefer, FONT_SIZE_INDEX, size);
+  if (NILP (AREF (spec, FONT_REGISTRY_INDEX)))
+    ASET (spec, FONT_REGISTRY_INDEX, Qiso8859_1);
+
+  entity_list = Flist_fonts (spec, frame, make_number (1), prefer);
+  if (NILP (entity_list))
+    entity = font_matching_entity (frame, spec);
+  else
+    entity = XCAR (entity_list);
+  return (NILP (entity)
+         ? Qnil
+         : font_open_entity (f, entity, pixel_size));
 }
 
 
 /* Register font-driver DRIVER.  This function is used in two ways.
 
-   The first is with frame F non-NULL.  In this case, DRIVER is
-   registered to be used for drawing characters on F.  All frame
-   creaters (e.g. Fx_create_frame) must call this function at least
-   once with an available font-driver.
+   The first is with frame F non-NULL.  In this case, make DRIVER
+   available (but not yet activated) on F.  All frame creaters
+   (e.g. Fx_create_frame) must call this function at least once with
+   an available font-driver.
 
    The second is with frame F NULL.  In this case, DRIVER is globally
    registered in the variable `font_driver_list'.  All font-driver
@@ -1899,10 +2808,11 @@ register_font_driver (driver, f)
           SDATA (SYMBOL_NAME (driver->type)));
 
   for (prev = NULL, list = root; list; prev = list, list = list->next)
-    if (list->driver->type == driver->type)
+    if (EQ (list->driver->type, driver->type))
       error ("Duplicated font driver: %s", SDATA (SYMBOL_NAME (driver->type)));
 
   list = malloc (sizeof (struct font_driver_list));
+  list->on = 0;
   list->driver = driver;
   list->next = NULL;
   if (prev)
@@ -1930,6 +2840,71 @@ free_font_driver_list (f)
     }
 }
 
+/* Make the frame F use font backends listed in NEW_BACKENDS (list of
+   symbols).  If NEW_BACKENDS is nil, make F use all available font
+   drivers.  If no backend is available, dont't alter
+   f->font_driver_list.
+
+   A caller must free all realized faces and clear all font caches if
+   any in advance.  The return value is a list of font backends
+   actually made used for on F.  */
+
+Lisp_Object
+font_update_drivers (f, new_drivers)
+     FRAME_PTR f;
+     Lisp_Object new_drivers;
+{
+  Lisp_Object active_drivers = Qnil;
+  struct font_driver_list *list;
+
+  /* At first check which font backends are available.  */
+  for (list = f->font_driver_list; list; list = list->next)
+    if (NILP (new_drivers)
+       || ! NILP (Fmemq (list->driver->type, new_drivers)))
+      {
+       list->on = 2;
+       active_drivers = nconc2 (active_drivers,
+                                Fcons (list->driver->type, Qnil));
+      }
+  /* If at least one backend is available, update all list->on.  */
+  if (! NILP (active_drivers))
+    for (list = f->font_driver_list; list; list = list->next)
+      list->on = (list->on == 2);
+
+  return active_drivers;
+}
+
+
+Lisp_Object
+font_at (c, pos, face, w, object)
+     int c;
+     EMACS_INT pos;
+     struct face *face;
+     struct window *w;
+     Lisp_Object object;
+{
+  FRAME_PTR f;
+  int face_id;
+  int dummy;
+
+  f = XFRAME (w->frame);
+  if (! face)
+    {
+      if (STRINGP (object))
+       face_id = face_at_string_position (w, object, pos, 0, -1, -1, &dummy,
+                                          DEFAULT_FACE_ID, 0);
+      else
+       face_id = face_at_buffer_position (w, pos, -1, -1, &dummy,
+                                          pos + 100, 0);
+      face = FACE_FROM_ID (f, face_id);
+    }
+  face_id = FACE_FOR_CHAR (f, face, c, pos, object);
+  face = FACE_FROM_ID (f, face_id);
+  if (! face->font_info)
+    return Qnil;
+  return font_lispy_object ((struct font *) face->font_info);
+}
+
 \f
 /* Lisp API */
 
@@ -1949,7 +2924,6 @@ usage: (font-spec &rest properties)  */)
      Lisp_Object *args;
 {
   Lisp_Object spec = Fmake_vector (make_number (FONT_SPEC_MAX), Qnil);
-  Lisp_Object extra = Qnil;
   int i;
 
   for (i = 0; i < nargs; i += 2)
@@ -1957,28 +2931,49 @@ usage: (font-spec &rest properties)  */)
       enum font_property_index prop;
       Lisp_Object key = args[i], val = args[i + 1];
 
-      prop = check_font_prop_name (key);
+      prop = get_font_prop_index (key, 0);
       if (prop < FONT_EXTRA_INDEX)
-       ASET (spec, prop, (font_property_table[prop].validater) (prop, val));
+       ASET (spec, prop, val);
       else
-       extra = Fcons (Fcons (key, val), extra);
-    }  
-  ASET (spec, FONT_EXTRA_INDEX, extra);
+       {
+         if (EQ (key, QCname))
+           {
+             CHECK_STRING (val);
+             font_parse_name ((char *) SDATA (val), spec);
+           }
+         font_put_extra (spec, key, val);
+       }
+    }
+  CHECK_VALIDATE_FONT_SPEC (spec);
   return spec;
 }
 
 
 DEFUN ("font-get", Ffont_get, Sfont_get, 2, 2, 0,
        doc: /* Return the value of FONT's PROP property.
-FONT may be a font-spec or font-entity.
-If FONT is font-entity and PROP is :extra, always nil is returned.  */)
+FONT is a font-spec, a font-entity, or a font-object.  */)
      (font, prop)
      Lisp_Object font, prop;
 {
   enum font_property_index idx;
 
-  CHECK_FONT (font);
-  idx = check_font_prop_name (prop);
+  if (FONT_OBJECT_P (font))
+    {
+      struct font *fontp = XSAVE_VALUE (font)->pointer;
+
+      if (EQ (prop, QCotf))
+       {
+#ifdef HAVE_LIBOTF
+         return font_otf_capability (fontp);
+#else  /* not HAVE_LIBOTF */
+         return Qnil;
+#endif /* not HAVE_LIBOTF */
+       }
+      font = fontp->entity;
+    }
+  else
+    CHECK_FONT (font);
+  idx = get_font_prop_index (prop, 0);
   if (idx < FONT_EXTRA_INDEX)
     return AREF (font, idx);
   if (FONT_ENTITY_P (font))
@@ -1996,7 +2991,7 @@ DEFUN ("font-put", Ffont_put, Sfont_put, 3, 3, 0,
   Lisp_Object extra, slot;
 
   CHECK_FONT_SPEC (font_spec);
-  idx = check_font_prop_name (prop);
+  idx = get_font_prop_index (prop, 0);
   if (idx < FONT_EXTRA_INDEX)
     return ASET (font_spec, idx, val);
   extra = AREF (font_spec, FONT_EXTRA_INDEX);
@@ -2012,8 +3007,8 @@ DEFUN ("list-fonts", Flist_fonts, Slist_fonts, 1, 4, 0,
        doc: /* List available fonts matching FONT-SPEC on the current frame.
 Optional 2nd argument FRAME specifies the target frame.
 Optional 3rd argument NUM, if non-nil, limits the number of returned fonts.
-Optional 4th argument PREFER, if non-nil, is a font-spec to sort fonts
-by closeness to PREFER.  */)
+Optional 4th argument PREFER, if non-nil, is a font-spec
+to which closeness fonts are sorted.  */)
      (font_spec, frame, num, prefer)
      Lisp_Object font_spec, frame, num, prefer;
 {
@@ -2145,42 +3140,49 @@ DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0,
       struct font_driver_list *driver_list = f->font_driver_list;
 
       for (; driver_list; driver_list = driver_list->next)
-       {
-         Lisp_Object cache = driver_list->driver->get_cache (frame);
-         Lisp_Object tail, elt;
+       if (driver_list->on)
+         {
+           Lisp_Object cache = driver_list->driver->get_cache (frame);
+           Lisp_Object tail, elt;
            
-         for (tail = XCDR (cache); CONSP (tail); tail = XCDR (tail))
-           {
-             elt = XCAR (tail);
-             if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)))
-               {
-                 Lisp_Object vec = XCDR (elt);
-                 int i;
-
-                 for (i = 0; i < ASIZE (vec); i++)
-                   {
-                     Lisp_Object entity = AREF (vec, i);
-                     Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX);
-
-                     for (; CONSP (objlist); objlist = XCDR (objlist))
-                       {
-                         Lisp_Object val = XCAR (objlist);
-                         struct Lisp_Save_Value *p = XSAVE_VALUE (val);
-                         struct font *font = p->pointer;
-
-                         xassert (font
-                                  && driver_list->driver == font->driver);
-                         driver_list->driver->close (f, font);
-                         p->pointer = NULL;
-                         p->integer = 0;
-                       }
-                     if (driver_list->driver->free_entity)
-                       driver_list->driver->free_entity (entity);
-                   }
-               }
-           }
-         XSETCDR (cache, Qnil);
-       }
+           for (tail = XCDR (cache); CONSP (tail); tail = XCDR (tail))
+             {
+               elt = XCAR (tail);
+               if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)))
+                 {
+                   Lisp_Object vec = XCDR (elt);
+                   int i;
+
+                   for (i = 0; i < ASIZE (vec); i++)
+                     {
+                       Lisp_Object entity = AREF (vec, i);
+
+                       if (EQ (driver_list->driver->type,
+                               AREF (entity, FONT_TYPE_INDEX)))
+                         {
+                           Lisp_Object objlist
+                             = AREF (entity, FONT_OBJLIST_INDEX);
+
+                           for (; CONSP (objlist); objlist = XCDR (objlist))
+                             {
+                               Lisp_Object val = XCAR (objlist);
+                               struct Lisp_Save_Value *p = XSAVE_VALUE (val);
+                               struct font *font = p->pointer;
+
+                               xassert (font && (driver_list->driver
+                                                 == font->driver));
+                               driver_list->driver->close (f, font);
+                               p->pointer = NULL;
+                               p->integer = 0;
+                             }
+                           if (driver_list->driver->free_entity)
+                             driver_list->driver->free_entity (entity);
+                         }
+                     }
+                 }
+             }
+           XSETCDR (cache, Qnil);
+         }
     }
 
   return Qnil;
@@ -2224,8 +3226,26 @@ sorted by numeric values.  */)
 }
   
 DEFUN ("font-make-gstring", Ffont_make_gstring, Sfont_make_gstring, 2, 2, 0,
-       doc: /* Return a newly created glyph-string for FONT-OBJECT with NUM glyphs.
-FONT-OBJECT may be nil if it is not yet known.  */)
+       doc: /* Return a newly created g-string for FONT-OBJECT with NUM glyphs.
+FONT-OBJECT may be nil if it is not yet known.
+
+G-string is sequence of glyphs of a specific font,
+and is a vector of this form:
+    [ HEADER GLYPH ... ]
+HEADER is a vector of this form:
+    [FONT-OBJECT LBEARING RBEARING WIDTH ASCENT DESCENT]
+where
+    FONT-OBJECT is a font-object for all glyphs in the G-string,
+    LBEARING thry DESCENT is the metrics (in pixels) of the whole G-string.
+GLYPH is a vector of this form:
+    [ FROM-IDX TO-IDX C CODE WIDTH [ [X-OFF Y-OFF WADJUST] | nil] ]
+where
+    FROM-IDX and TO-IDX are used internally and should not be touched.
+    C is the character of the glyph.
+    CODE is the glyph-code of C in FONT-OBJECT.
+    X-OFF and Y-OFF are offests to the base position for the glyph.
+    WIDTH is the normal width of the glyph.
+    WADJUST is the adjustment to the normal width of the glyph.  */)
      (font_object, num)
      Lisp_Object font_object, num;
 {
@@ -2243,7 +3263,7 @@ FONT-OBJECT may be nil if it is not yet known.  */)
   ASET (g, 0, font_object);
   ASET (gstring, 0, g);
   for (i = 1; i < len; i++)
-    ASET (gstring, i, Fmake_vector (make_number (8), make_number (0)));
+    ASET (gstring, i, Fmake_vector (make_number (8), Qnil));
   return gstring;
 }
 
@@ -2262,7 +3282,7 @@ FONT-OBJECT may be nil if GSTRING already already contains one.  */)
 
   CHECK_VECTOR (gstring);
   if (NILP (font_object))
-    font_object = Faref (Faref (gstring, make_number (0)), make_number (0));
+    font_object = LGSTRING_FONT (gstring);
   CHECK_FONT_GET_OBJECT (font_object, font);
 
   if (STRINGP (object))
@@ -2273,7 +3293,7 @@ FONT-OBJECT may be nil if GSTRING already already contains one.  */)
       CHECK_NATNUM (end);
       if (XINT (start) > XINT (end)
          || XINT (end) > ASIZE (object)
-         || XINT (end) - XINT (start) >= XINT (Flength (gstring)))
+         || XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
        args_out_of_range (start, end);
 
       len = XINT (end) - XINT (start);
@@ -2286,8 +3306,8 @@ FONT-OBJECT may be nil if GSTRING already already contains one.  */)
          code = font->driver->encode_char (font, c);
          if (code > MOST_POSITIVE_FIXNUM)
            error ("Glyph code 0x%X is too large", code);
-         ASET (g, 0, make_number (i));
-         ASET (g, 1, make_number (i + 1));
+         LGLYPH_SET_FROM (g, make_number (i));
+         LGLYPH_SET_TO (g, make_number (i + 1));
          LGLYPH_SET_CHAR (g, make_number (c));
          LGLYPH_SET_CODE (g, make_number (code));
        }
@@ -2299,7 +3319,7 @@ FONT-OBJECT may be nil if GSTRING already already contains one.  */)
       if (! NILP (object))
        Fset_buffer (object);
       validate_region (&start, &end);
-      if (XINT (end) - XINT (start) > len)
+      if (XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
        args_out_of_range (start, end);
       len = XINT (end) - XINT (start);
       pos = XINT (start);
@@ -2312,15 +3332,166 @@ FONT-OBJECT may be nil if GSTRING already already contains one.  */)
          code = font->driver->encode_char (font, c);
          if (code > MOST_POSITIVE_FIXNUM)
            error ("Glyph code 0x%X is too large", code);
-         ASET (g, 0, make_number (i));
-         ASET (g, 1, make_number (i + 1));
+         LGLYPH_SET_FROM (g, make_number (i));
+         LGLYPH_SET_TO (g, make_number (i + 1));
          LGLYPH_SET_CHAR (g, make_number (c));
          LGLYPH_SET_CODE (g, make_number (code));
        }
     }
+  for (i = LGSTRING_LENGTH (gstring) - 1; i >= len; i--)
+    {
+      Lisp_Object g = LGSTRING_GLYPH (gstring, i);
+
+      LGLYPH_SET_FROM (g, Qnil);
+    }
   return Qnil;
 }
 
+DEFUN ("font-otf-gsub", Ffont_otf_gsub, Sfont_otf_gsub, 6, 6, 0,
+       doc: /* Apply OpenType "GSUB" features on glyph-string GSTRING-IN.
+FEATURE-SPEC specifies which featuress to apply in this format:
+  (SCRIPT LANGSYS FEATURE ...)
+where
+  SCRIPT is a symbol specifying a script tag of OpenType,
+  LANGSYS is a symbol specifying a langsys tag of OpenType,
+  FEATURE is a symbol specifying a feature tag of Opentype.
+
+If LANGYS is nil, the default langsys is selected.
+
+The features are applied in the order appeared in the list.  FEATURE
+may be a symbol `*', in which case all available features not appeared
+in this list are applied, and the remaining FEATUREs are not ignored.
+For instance, (mlym nil vatu pstf * haln) means to apply vatu and pstf
+in this order, then to apply all available features other than vatu,
+pstf, and haln.
+
+The features are applied to the glyphs in the range FROM and TO of
+GSTRING-IN.
+
+If some of a feature is actually applicable, the resulting glyphs are
+produced in the glyph-string GSTRING-OUT from the index INDEX.  In
+this case, the value is the number of produced glyphs.
+
+If no feature is applicable, no glyph is produced in GSTRING-OUT, and
+the value is 0.
+
+If GSTRING-OUT is too short to hold produced glyphs, no glyphs is
+produced in GSTRING-OUT, and the value is nil.
+
+See the documentation of `font-make-gstring' for the format of
+glyph-string.  */)
+     (feature_spec, gstring_in, from, to, gstring_out, index)
+     Lisp_Object feature_spec, gstring_in, from, to, gstring_out, index;
+{
+  Lisp_Object font_object = LGSTRING_FONT (gstring_in);
+  struct font *font = XSAVE_VALUE (font_object)->pointer;
+  int len, num;
+
+  CHECK_FONT_GET_OBJECT (font_object, font);
+  if (! font->driver->otf_gsub)
+    error ("Font backend %s can't drive OpenType GSUB table",
+          SDATA (SYMBOL_NAME (font->driver->type)));
+  CHECK_CONS (feature_spec);
+  len = check_gstring (gstring_in);
+  CHECK_VECTOR (gstring_out);
+  CHECK_NATNUM (from);
+  CHECK_NATNUM (to);
+  CHECK_NATNUM (index);
+
+  if (XINT (from) >= XINT (to) || XINT (to) > len)
+    args_out_of_range_3 (from, to, make_number (len));
+  if (XINT (index) >= ASIZE (gstring_out))
+    args_out_of_range (index, make_number (ASIZE (gstring_out)));
+  num = font->driver->otf_gsub (font, feature_spec,
+                               gstring_in, XINT (from), XINT (to),
+                               gstring_out, XINT (index), 0);
+  if (num < 0)
+    return Qnil;
+  return make_number (num);
+}
+
+
+DEFUN ("font-otf-gpos", Ffont_otf_gpos, Sfont_otf_gpos, 4, 4, 0,
+       doc: /* Apply OpenType "GPOS" features on glyph-string GSTRING.
+FEATURE-SPEC specifies which features to apply in this format:
+  (SCRIPT LANGSYS FEATURE ...)
+See the documentation of `font-otf-gsub' for more detail.
+
+The features are applied to the glyphs in the range FROM and TO of
+GSTRING.  */)
+     (gpos_spec, gstring, from, to)
+     Lisp_Object gpos_spec, gstring, from, to;
+{
+  Lisp_Object font_object = LGSTRING_FONT (gstring);
+  struct font *font;
+  int len, num;
+
+  CHECK_FONT_GET_OBJECT (font_object, font);
+  if (! font->driver->otf_gpos)
+    error ("Font backend %s can't drive OpenType GPOS table",
+          SDATA (SYMBOL_NAME (font->driver->type)));
+  CHECK_CONS (gpos_spec);
+  len = check_gstring (gstring);
+  CHECK_NATNUM (from);
+  CHECK_NATNUM (to);
+
+  if (XINT (from) >= XINT (to) || XINT (to) > len)
+    args_out_of_range_3 (from, to, make_number (len));
+  num = font->driver->otf_gpos (font, gpos_spec,
+                               gstring, XINT (from), XINT (to));
+  return (num <= 0 ? Qnil : Qt);
+}
+
+
+DEFUN ("font-otf-alternates", Ffont_otf_alternates, Sfont_otf_alternates,
+       3, 3, 0,
+       doc: /* Return a list of alternate glyphs of CHARACTER in FONT-OBJECT.
+FEATURE-SPEC specifies which features of the font FONT-OBJECT to apply
+in this format:
+  (SCRIPT LANGSYS FEATURE ...)
+See the documentation of `font-otf-gsub' for more detail.
+
+The value is a list of cons cells of the format (GLYPH-ID . CHARACTER),
+where GLYPH-ID is a glyph index of the font, and CHARACTER is a
+character code corresponding to the glyph or nil if there's no
+corresponding character.  */)
+     (font_object, character, feature_spec)
+     Lisp_Object font_object, character, feature_spec;
+{
+  struct font *font;
+  Lisp_Object gstring_in, gstring_out, g;
+  Lisp_Object alternates;
+  int i, num;
+
+  CHECK_FONT_GET_OBJECT (font_object, font);
+  if (! font->driver->otf_gsub)
+    error ("Font backend %s can't drive OpenType GSUB table",
+          SDATA (SYMBOL_NAME (font->driver->type)));
+  CHECK_CHARACTER (character);
+  CHECK_CONS (feature_spec);
+
+  gstring_in = Ffont_make_gstring (font_object, make_number (1));
+  g = LGSTRING_GLYPH (gstring_in, 0);
+  LGLYPH_SET_CHAR (g, character);
+  gstring_out = Ffont_make_gstring (font_object, make_number (10));
+  while ((num = font->driver->otf_gsub (font, feature_spec, gstring_in, 0, 1,
+                                       gstring_out, 0, 1)) < 0)
+    gstring_out = Ffont_make_gstring (font_object,
+                                     make_number (ASIZE (gstring_out) * 2));
+  alternates = Qnil;
+  for (i = 0; i < num; i++)
+    {
+      Lisp_Object g = LGSTRING_GLYPH (gstring_out, i);
+      int c = XINT (LGLYPH_CHAR (g));
+      unsigned code = XUINT (LGLYPH_CODE (g));
+
+      alternates = Fcons (Fcons (make_number (code),
+                                c > 0 ? make_number (c) : Qnil),
+                         alternates);
+    }
+  return Fnreverse (alternates);
+}
+
 
 #ifdef FONT_DEBUG
 
@@ -2362,7 +3533,46 @@ DEFUN ("close-font", Fclose_font, Sclose_font, 1, 2, 0,
 }
 
 DEFUN ("query-font", Fquery_font, Squery_font, 1, 1, 0,
-       doc: /* Return information about FONT-OBJECT.  */)
+       doc: /* Return information about FONT-OBJECT.
+The value is a vector:
+  [ NAME FILENAME PIXEL-SIZE SIZE ASCENT DESCENT SPACE-WIDTH AVERAGE-WIDTH
+    CAPABILITY ]
+
+NAME is a string of the font name (or nil if the font backend doesn't
+provide a name).
+
+FILENAME is a string of the font file (or nil if the font backend
+doesn't provide a file name).
+
+PIXEL-SIZE is a pixel size by which the font is opened.
+
+SIZE is a maximum advance width of the font in pixel.
+
+ASCENT, DESCENT, SPACE-WIDTH, AVERAGE-WIDTH are metrics of the font in
+pixel.
+
+CAPABILITY is a list whose first element is a symbol representing the
+font format \(x, opentype, truetype, type1, pcf, or bdf) and the
+remaining elements describes a detail of the font capability.
+
+If the font is OpenType font, the form of the list is
+  \(opentype GSUB GPOS)
+where GSUB shows which "GSUB" features the font supports, and GPOS
+shows which "GPOS" features the font supports.  Both GSUB and GPOS are
+lists of the format:
+  \((SCRIPT (LANGSYS FEATURE ...) ...) ...)
+
+If the font is not OpenType font, currently the length of the form is
+one.
+
+SCRIPT is a symbol representing OpenType script tag.
+
+LANGSYS is a symbol representing OpenType langsys tag, or nil
+representing the default langsys.
+
+FEATURE is a symbol representing OpenType feature tag.  
+
+If the font is not OpenType font, OTF-CAPABILITY is nil.  */)
      (font_object)
      Lisp_Object font_object;
 {
@@ -2372,7 +3582,9 @@ DEFUN ("query-font", Fquery_font, Squery_font, 1, 1, 0,
   CHECK_FONT_GET_OBJECT (font_object, font);
 
   val = Fmake_vector (make_number (9), Qnil);
-  ASET (val, 0, Ffont_xlfd_name (font_object));
+  if (font->font.full_name)
+    ASET (val, 0, make_unibyte_string (font->font.full_name,
+                                      strlen (font->font.full_name)));
   if (font->file_name)
     ASET (val, 1, make_unibyte_string (font->file_name,
                                       strlen (font->file_name)));
@@ -2383,7 +3595,9 @@ DEFUN ("query-font", Fquery_font, Squery_font, 1, 1, 0,
   ASET (val, 6, make_number (font->font.space_width));
   ASET (val, 7, make_number (font->font.average_width));
   if (font->driver->otf_capability)
-    ASET (val, 8, font->driver->otf_capability (font));
+    ASET (val, 8, Fcons (Qopentype, font->driver->otf_capability (font)));
+  else
+    ASET (val, 8, Fcons (font->format, Qnil));
   return val;
 }
 
@@ -2429,6 +3643,46 @@ Each element is a vector [GLYPH-CODE LBEARING RBEARING WIDTH ASCENT DESCENT].  *
   return vec;
 }
 
+DEFUN ("font-match-p", Ffont_match_p, Sfont_match_p, 2, 2, 0,
+       doc: /* Return t iff font-spec SPEC matches with FONT.
+FONT is a font-spec, font-entity, or font-object. */)
+     (spec, font)
+     Lisp_Object spec, font;
+{
+  CHECK_FONT_SPEC (spec);
+  if (FONT_OBJECT_P (font))
+    font = ((struct font *) XSAVE_VALUE (font)->pointer)->entity;
+  else if (! FONT_ENTITY_P (font))
+    CHECK_FONT_SPEC (font);
+
+  return (font_match_p (spec, font) ? Qt : Qnil);
+}
+
+DEFUN ("font-at", Ffont_at, Sfont_at, 1, 2, 0,
+       doc: /* Return a font-object for displaying a character at POSISTION.
+Optional second arg WINDOW, if non-nil, is a window displaying
+the current buffer.  It defaults to the currently selected window.  */)
+     (position, window)
+     Lisp_Object position, window;
+{
+  struct window *w;
+  EMACS_INT pos, pos_byte;
+  int c;
+
+  CHECK_NUMBER_COERCE_MARKER (position);
+  pos = XINT (position);
+  if (pos < BEGV || pos >= ZV)
+    args_out_of_range_3 (position, make_number (BEGV), make_number (ZV));
+  pos_byte = CHAR_TO_BYTE (pos);
+  c = FETCH_CHAR (pos_byte);
+  if (NILP (window))
+    window = selected_window;
+  CHECK_LIVE_WINDOW (window);
+  w = XWINDOW (selected_window);
+
+  return font_at (c, pos, NULL, w, Qnil);
+}
+
 #if 0
 DEFUN ("draw-string", Fdraw_string, Sdraw_string, 2, 2, 0,
        doc: /*  Draw STRING by FONT-OBJECT on the top left corner of the current frame.
@@ -2493,7 +3747,7 @@ syms_of_font ()
   sort_shift_bits[FONT_FOUNDRY_INDEX] = 29;
   sort_shift_bits[FONT_FAMILY_INDEX] = 30;
   sort_shift_bits[FONT_REGISTRY_INDEX] = 31;
-  /* Note that sort_shift_bits[FONT_SLANT_TYPE] is never used.  */
+  /* Note that sort_shift_bits[FONT_TYPE_INDEX] is never used.  */
 
   staticpro (&font_style_table);
   font_style_table = Fmake_vector (make_number (3), Qnil);
@@ -2502,6 +3756,12 @@ syms_of_font ()
   font_family_alist = Qnil;
 
   DEFSYM (Qfontp, "fontp");
+  DEFSYM (Qopentype, "opentype");
+
+  DEFSYM (Qiso8859_1, "iso8859-1");
+  DEFSYM (Qiso10646_1, "iso10646-1");
+  DEFSYM (Qunicode_bmp, "unicode-bmp");
+  DEFSYM (Qunicode_sip, "unicode-sip");
 
   DEFSYM (QCotf, ":otf");
   DEFSYM (QClanguage, ":language");
@@ -2510,8 +3770,16 @@ syms_of_font ()
   DEFSYM (QCfoundry, ":foundry");
   DEFSYM (QCadstyle, ":adstyle");
   DEFSYM (QCregistry, ":registry");
+  DEFSYM (QCspacing, ":spacing");
+  DEFSYM (QCdpi, ":dpi");
+  DEFSYM (QCscalable, ":scalable");
   DEFSYM (QCextra, ":extra");
 
+  DEFSYM (Qc, "c");
+  DEFSYM (Qm, "m");
+  DEFSYM (Qp, "p");
+  DEFSYM (Qd, "d");
+
   staticpro (&null_string);
   null_string = build_string ("");
   staticpro (&null_vector);
@@ -2534,12 +3802,17 @@ syms_of_font ()
   defsubr (&Sinternal_set_font_style_table);
   defsubr (&Sfont_make_gstring);
   defsubr (&Sfont_fill_gstring);
+  defsubr (&Sfont_otf_gsub);
+  defsubr (&Sfont_otf_gpos);
+  defsubr (&Sfont_otf_alternates);
 
 #ifdef FONT_DEBUG
   defsubr (&Sopen_font);
   defsubr (&Sclose_font);
   defsubr (&Squery_font);
   defsubr (&Sget_font_glyphs);
+  defsubr (&Sfont_match_p);
+  defsubr (&Sfont_at);
 #if 0
   defsubr (&Sdraw_string);
 #endif