(font_style_to_value): Set value for unknown symbols to
[bpt/emacs.git] / src / font.c
index 962e8a3..780413f 100644 (file)
@@ -1,6 +1,6 @@
 /* font.c -- "Font" primitives.
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
-   Copyright (C) 2006, 2007, 2008
+   Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008, 2009
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H13PRO009
 
@@ -23,9 +23,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
-#ifdef HAVE_M17N_FLT
-#include <m17n-flt.h>
-#endif
 
 #include "lisp.h"
 #include "buffer.h"
@@ -46,17 +43,28 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "w32term.h"
 #endif /* HAVE_NTGUI */
 
-#ifdef MAC_OS
-#include "macterm.h"
-#endif /* MAC_OS */
+#ifdef HAVE_NS
+#include "nsterm.h"
+#endif /* HAVE_NS */
 
-Lisp_Object Qfont_spec, Qfont_entity, Qfont_object;
+#ifdef HAVE_NS
+extern Lisp_Object Qfontsize;
+#endif
 
 Lisp_Object Qopentype;
 
 /* Important character set strings.  */
 Lisp_Object Qascii_0, Qiso8859_1, Qiso10646_1, Qunicode_bmp, Qunicode_sip;
 
+#ifdef HAVE_NS
+#define DEFAULT_ENCODING Qiso10646_1
+#else
+#define DEFAULT_ENCODING Qiso8859_1
+#endif
+
+/* Unicode category `Cf'.  */
+static Lisp_Object QCf;
+
 /* Special vector of zero length.  This is repeatedly used by (struct
    font_driver *)->list when a specified font is not found. */
 static Lisp_Object null_vector;
@@ -88,7 +96,7 @@ static struct table_entry weight_table[] =
   { 40, { "extra-light", "extralight" }},
   { 50, { "light" }},
   { 75, { "semi-light", "semilight", "demilight", "book" }},
-  { 100, { "normal", "medium", "regular" }},
+  { 100, { "normal", "medium", "regular", "unspecified" }},
   { 180, { "semi-bold", "semibold", "demibold", "demi" }},
   { 200, { "bold" }},
   { 205, { "extra-bold", "extrabold" }},
@@ -102,7 +110,7 @@ static struct table_entry slant_table[] =
 {
   { 0, { "reverse-oblique", "ro" }},
   { 10, { "reverse-italic", "ri" }},
-  { 100, { "normal", "r" }},
+  { 100, { "normal", "r", "unspecified" }},
   { 200, { "italic" ,"i", "ot" }},
   { 210, { "oblique", "o" }}
 };
@@ -116,7 +124,7 @@ static struct table_entry width_table[] =
   { 63, { "extra-condensed", "extracondensed" }},
   { 75, { "condensed", "compressed", "narrow" }},
   { 87, { "semi-condensed", "semicondensed", "demicondensed" }},
-  { 100, { "normal", "medium", "regular" }},
+  { 100, { "normal", "medium", "regular", "unspecified" }},
   { 113, { "semi-expanded", "semiexpanded", "demiexpanded" }},
   { 125, { "expanded" }},
   { 150, { "extra-expanded", "extraexpanded" }},
@@ -189,15 +197,32 @@ font_make_entity ()
   return font_entity;
 }
 
+/* Create a font-object whose structure size is SIZE.  If ENTITY is
+   not nil, copy properties from ENTITY to the font-object.  If
+   PIXELSIZE is positive, set the `size' property to PIXELSIZE.  */
 Lisp_Object
-font_make_object (size)
+font_make_object (size, entity, pixelsize)
      int size;
+     Lisp_Object entity;
+     int pixelsize;
 {
   Lisp_Object font_object;
   struct font *font
     = (struct font *) allocate_pseudovector (size, FONT_OBJECT_MAX, PVEC_FONT);
+  int i;
+
   XSETFONT (font_object, font);
 
+  if (! NILP (entity))
+    {
+      for (i = 1; i < FONT_SPEC_MAX; i++)
+       font->props[i] = AREF (entity, i);
+      if (! NILP (AREF (entity, FONT_EXTRA_INDEX)))
+       font->props[FONT_EXTRA_INDEX]
+         = Fcopy_sequence (AREF (entity, FONT_EXTRA_INDEX));
+    }
+  if (size > 0)
+    font->props[FONT_SIZE_INDEX] = make_number (pixelsize);
   return font_object;
 }
 
@@ -227,6 +252,7 @@ font_intern_prop (str, len, force_symbol)
   int i;
   Lisp_Object tem;
   Lisp_Object obarray;
+  int nbytes, nchars;
 
   if (len == 1 && *str == '*')
     return Qnil;
@@ -239,14 +265,25 @@ font_intern_prop (str, len, force_symbol)
        return make_number (atoi (str));
     }
 
-  /* The following code is copied from the function intern (in lread.c).  */
+  /* The following code is copied from the function intern (in
+     lread.c), and modified to suite our purpose.  */
   obarray = Vobarray;
   if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
     obarray = check_obarray (obarray);
-  tem = oblookup (obarray, str, len, len);
+  parse_str_as_multibyte (str, len, &nchars, &nbytes);
+  if (len == nchars || len != nbytes)
+    /* CONTENTS contains no multibyte sequences or contains an invalid
+       multibyte sequence.  We'll make a unibyte string.  */
+    tem = oblookup (obarray, str, len, len);
+  else
+    tem = oblookup (obarray, str, nchars, len);
   if (SYMBOLP (tem))
     return tem;
-  return Fintern (make_unibyte_string (str, len), obarray);
+  if (len == nchars || len != nbytes)
+    tem = make_unibyte_string (str, len);
+  else
+    tem = make_multibyte_string (str, nchars, len);
+  return Fintern (tem, obarray);
 }
 
 /* Return a pixel size of font-spec SPEC on frame F.  */
@@ -323,12 +360,12 @@ font_style_to_value (prop, val, noerror)
        return -1;
       if (len == 255)
        abort ();
-      elt = Fmake_vector (make_number (2), make_number (255));
+      elt = Fmake_vector (make_number (2), make_number (100));
       ASET (elt, 1, val);
       args[0] = table;
       args[1] = Fmake_vector (make_number (1), elt);
       ASET (font_style_table, prop - FONT_WEIGHT_INDEX, Fvconcat (2, args));
-      return (255 << 8) | (i << 4);
+      return (100 << 8) | (i << 4);
     }
   else
     {
@@ -373,7 +410,7 @@ font_style_symbolic (font, prop, for_face)
   font_assert (((i >> 4) & 0xF) < ASIZE (table));
   elt = AREF (table, ((i >> 4) & 0xF));
   font_assert ((i & 0xF) + 1 < ASIZE (elt));
-  return (for_face ? AREF (elt, 1) : AREF (elt, (i & 0xF) + 1));  
+  return (for_face ? AREF (elt, 1) : AREF (elt, (i & 0xF) + 1));
 }
 
 extern Lisp_Object Vface_alternative_font_family_alist;
@@ -1027,11 +1064,11 @@ font_parse_xlfd (name, font)
   Lisp_Object val;
   char *p;
 
-  if (len > 255)
+  if (len > 255 || !len)
     /* Maximum XLFD name length is 255. */
     return -1;
   /* Accept "*-.." as a fully specified XLFD. */
-  if (name[0] == '*' && name[1] == '-')
+  if (name[0] == '*' && (len == 1 || name[1] == '-'))
     i = 1, f[XLFD_FOUNDRY_INDEX] = name;
   else
     i = 0;
@@ -1109,7 +1146,7 @@ font_parse_xlfd (name, font)
       if (*p == '~')
        p++;
       ASET (font, FONT_AVGWIDTH_INDEX,
-           font_intern_prop (p, f[XLFD_REGISTRY_INDEX] - 1 - p, 1));
+           font_intern_prop (p, f[XLFD_REGISTRY_INDEX] - 1 - p, 0));
     }
   else
     {
@@ -1359,8 +1396,7 @@ font_parse_fcname (name, font)
        p++;
       else if (*p == ':')
        {
-         family_end = p;
-         props_beg = p + 1;
+         props_beg = family_end = p;
          break;
        }
       else if (*p == '-')
@@ -1400,30 +1436,22 @@ font_parse_fcname (name, font)
          double point_size = strtod (size_beg, &size_end);
          ASET (font, FONT_SIZE_INDEX, make_float (point_size));
          if (*size_end == ':' && size_end[1])
-           props_beg = size_end + 1;
+           props_beg = size_end;
        }
       if (props_beg)
        {
-         /* Now parse ":KEY=VAL" patterns.  Store known keys and values in
-            extra, copy unknown ones to COPY.  It is stored in extra slot by
-            the key QCfc_unknown_spec.  */
-         char *copy_start, *copy;
-
-         copy_start = copy = alloca (name + len - props_beg + 2);
-         if (! copy)
-           return -1;
+         /* Now parse ":KEY=VAL" patterns.  */
+         Lisp_Object val;
 
-         p = props_beg;
-         while (*p)
+         for (p = props_beg; *p; p = q)
            {
-             Lisp_Object val;
-             int word_len, prop;
-
              for (q = p + 1; *q && *q != '=' && *q != ':'; q++);
-             word_len = q - p;
              if (*q != '=')
                {
                  /* Must be an enumerated value.  */
+                 int word_len;
+                 p = p + 1;
+                 word_len = q - p;
                  val = font_intern_prop (p, q - p, 1);
 
 #define PROP_MATCH(STR,N) ((word_len == N) && memcmp (p, STR, N) == 0)
@@ -1447,21 +1475,15 @@ font_parse_fcname (name, font)
                  else if (PROP_MATCH ("proportional", 12))
                    ASET (font, FONT_SPACING_INDEX,
                          make_number (FONT_SPACING_PROPORTIONAL));
-                 else
-                   {
-                     /* Unknown key  */
-                     *copy++ = ':';
-                     bcopy (p, copy, word_len);
-                     copy += word_len;
-                   }
 #undef PROP_MATCH
                }
-             else /* KEY=VAL pairs  */
+             else
                {
+                 /* KEY=VAL pairs  */
                  Lisp_Object key;
-                 char *keyhead = p;
+                 int prop;
 
-                 if (word_len == 9 && memcmp (p, "pixelsize=", 10) == 0)
+                 if (q - p == 10 && memcmp (p + 1, "pixelsize", 9) == 0)
                    prop = FONT_SIZE_INDEX;
                  else
                    {
@@ -1473,27 +1495,14 @@ font_parse_fcname (name, font)
                  for (q = p; *q && *q != ':'; q++);
                  val = font_intern_prop (p, q - p, 0);
 
-                 if (! NILP (val))
-                   {
-                     if (prop >= FONT_FOUNDRY_INDEX
-                         && prop < FONT_EXTRA_INDEX)
-                       ASET (font, prop,
-                             font_prop_validate (prop, Qnil, val));
-                     else if (prop >= 0)
-                       Ffont_put (font, key, val);
-                     else
-                       {
-                         *copy++ = ':';
-                         bcopy (keyhead, copy, q - keyhead);
-                         copy += q - keyhead;
-                       }
-                   }
+                 if (prop >= FONT_FOUNDRY_INDEX
+                     && prop < FONT_EXTRA_INDEX)
+                   ASET (font, prop, font_prop_validate (prop, Qnil, val));
+                 else
+                   Ffont_put (font, key, val);
                }
-             p = *q ? q + 1 : q;
+             p = q;
            }
-         if (copy_start != copy)
-           font_put_extra (font, QCfc_unknown_spec,
-                           make_unibyte_string (copy_start, copy - copy_start));
        }
     }
   else
@@ -1507,8 +1516,8 @@ font_parse_fcname (name, font)
        {
          if (isdigit (*p))
            {
-             char *r;
              int size_found = 1;
+
              for (q = p + 1; *q && *q != ' '; q++)
                if (! isdigit (*q))
                  {
@@ -1599,7 +1608,6 @@ font_unparse_fcname (font, pixel_size, name, nbytes)
   Lisp_Object family, foundry;
   Lisp_Object tail, val;
   int point_size;
-  int dpi;
   int i, len = 1;
   char *p;
   Lisp_Object styles[3];
@@ -1654,7 +1662,7 @@ font_unparse_fcname (font, pixel_size, name, nbytes)
     }
 
   if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
-    len += sprintf (work, ":dpi=%d", dpi);
+    len += sprintf (work, ":dpi=%d", XINT (AREF (font, FONT_DPI_INDEX)));
   if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
     len += strlen (":spacing=100");
   if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
@@ -1804,7 +1812,7 @@ font_parse_name (name, font)
      char *name;
      Lisp_Object font;
 {
-  if (name[0] == '-' || index (name, '*'))
+  if (name[0] == '-' || index (name, '*') || index (name, '?'))
     return font_parse_xlfd (name, font);
   return font_parse_fcname (name, font);
 }
@@ -1894,7 +1902,7 @@ check_gstring (gstring)
   if (!NILP (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT)))
     CHECK_NUMBER (LGSTRING_SLOT (gstring, LGSTRING_IX_ASCENT));
 
-  for (i = 0; i < LGSTRING_LENGTH (gstring); i++)
+  for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
     {
       val = LGSTRING_GLYPH (gstring, i);
       CHECK_VECTOR (val);
@@ -2159,42 +2167,45 @@ font_otf_Anchor (anchor)
 #endif /* HAVE_LIBOTF */
 #endif /* 0 */
 
-/* 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, f)
-     struct composition *cmp;
-     FRAME_PTR f;
-{
-  Lisp_Object gstring
-    = AREF (XHASH_TABLE (composition_hash_table)->key_and_value,
-           cmp->hash_index * 2);
-
-  cmp->font = XFONT_OBJECT (LGSTRING_FONT (gstring));
-  cmp->glyph_len = LGSTRING_LENGTH (gstring);
-  cmp->pixel_width = LGSTRING_WIDTH (gstring);
-  cmp->lbearing = LGSTRING_LBEARING (gstring);
-  cmp->rbearing = LGSTRING_RBEARING (gstring);
-  cmp->ascent = LGSTRING_ASCENT (gstring);
-  cmp->descent = LGSTRING_DESCENT (gstring);
-  cmp->width = cmp->pixel_width / FRAME_COLUMN_WIDTH (f);
-  if (cmp->width == 0)
-    cmp->width = 1;
-
-  return cmp->font;
-}
-
 \f
 /* Font sorting */
 
 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,
-                                         int));
+                                         Lisp_Object, int));
+
+/* Return a rescaling ratio of FONT_ENTITY.  */
+extern Lisp_Object Vface_font_rescale_alist;
+
+static double
+font_rescale_ratio (font_entity)
+     Lisp_Object font_entity;
+{
+  Lisp_Object tail, elt;
+  Lisp_Object name = Qnil;
+
+  for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail))
+    {
+      elt = XCAR (tail);
+      if (FLOATP (XCDR (elt)))
+       {
+         if (STRINGP (XCAR (elt)))
+           {
+             if (NILP (name))
+               name = Ffont_xlfd_name (font_entity, Qnil);
+             if (fast_string_match_ignore_case (XCAR (elt), name) >= 0)
+               return XFLOAT_DATA (XCDR (elt));
+           }
+         else if (FONT_SPEC_P (XCAR (elt)))
+           {
+             if (font_match_p (XCAR (elt), font_entity))
+               return XFLOAT_DATA (XCDR (elt));
+           }
+       }
+    }
+  return 1.0;
+}
 
 /* We sort fonts by scoring each of them against a specified
    font-spec.  The score value is 32 bit (`unsigned'), and the smaller
@@ -2213,10 +2224,7 @@ static int sort_shift_bits[FONT_SIZE_INDEX + 1];
 
 /* Score font-entity ENTITY against properties of font-spec SPEC_PROP.
    The return value indicates how different ENTITY is compared with
-   SPEC_PROP.
-
-   ALTERNATE_FAMILIES, if non-nil, is a pre-calculated list of
-   alternate family names for AREF (SPEC_PROP, FONT_FAMILY_INDEX).  */
+   SPEC_PROP.  */
 
 static unsigned
 font_score (entity, spec_prop)
@@ -2239,13 +2247,17 @@ font_score (entity, spec_prop)
 
   /* Score the size.  Maximum difference is 127.  */
   i = FONT_SIZE_INDEX;
-  if (! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i])
-      && XINT (AREF (entity, i)) > 0)
+  if (! NILP (spec_prop[FONT_SIZE_INDEX])
+      && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
     {
       /* We use the higher 6-bit for the actual size difference.  The
         lowest bit is set if the DPI is different.  */
-      int diff = XINT (spec_prop[i]) - XINT (AREF (entity, i));
+      int diff;
+      int pixel_size = XINT (spec_prop[FONT_SIZE_INDEX]);
 
+      if (CONSP (Vface_font_rescale_alist))
+       pixel_size *= font_rescale_ratio (entity);
+      diff = pixel_size - XINT (AREF (entity, FONT_SIZE_INDEX));
       if (diff < 0)
        diff = - diff;
       diff <<= 1;
@@ -2280,15 +2292,14 @@ 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 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.
+   of FRAME before sorting.
 
    If BEST-ONLY is nonzero, return the best matching entity.  Otherwise,
    return the sorted VEC.  */
 
 static Lisp_Object
-font_sort_entites (vec, prefer, frame, spec, best_only)
-     Lisp_Object vec, prefer, frame, spec;
+font_sort_entites (vec, prefer, frame, best_only)
+     Lisp_Object vec, prefer, frame;
      int best_only;
 {
   Lisp_Object prefer_prop[FONT_SPEC_MAX];
@@ -2305,22 +2316,8 @@ font_sort_entites (vec, prefer, frame, spec, best_only)
   if (len <= 1)
     return best_only ? AREF (vec, 0) : vec;
 
-  for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
+  for (i = FONT_WEIGHT_INDEX; i <= FONT_DPI_INDEX; i++)
     prefer_prop[i] = AREF (prefer, i);
-
-  if (! NILP (spec))
-    {
-      /* A font driver may return a font that has a property value
-        different from the value specified in SPEC if the driver
-        thinks they are the same.  That happens, for instance, such a
-        generic family name as "serif" is specified.  So, to ignore
-        such a difference, for all properties specified in SPEC, set
-        the corresponding properties in PREFER_PROP to nil.  */
-      for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
-       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));
@@ -2354,7 +2351,7 @@ font_sort_entites (vec, prefer, frame, spec, best_only)
            break;
        }
     }
-  if (NILP (best_entity))
+  if (! best_only)
     {
       qsort (data, len, sizeof *data, font_compare);
       for (i = 0; i < len; i++)
@@ -2396,32 +2393,183 @@ font_update_sort_order (order)
     }
 }
 
+static int
+font_check_otf_features (script, langsys, features, table)
+     Lisp_Object script, langsys, features, table;
+{
+  Lisp_Object val;
+  int negative;
+
+  table = assq_no_quit (script, table);
+  if (NILP (table))
+    return 0;
+  table = XCDR (table);
+  if (! NILP (langsys))
+    {
+      table = assq_no_quit (langsys, table);
+      if (NILP (table))
+       return 0;
+    }
+  else
+    {
+      val = assq_no_quit (Qnil, table);
+      if (NILP (val))
+       table = XCAR (table);
+      else
+       table = val;
+    }
+  table = XCDR (table);
+  for (negative = 0; CONSP (features); features = XCDR (features))
+    {
+      if (NILP (XCAR (features)))
+       {
+         negative = 1;
+         continue;
+       }
+      if (NILP (Fmemq (XCAR (features), table)) != negative)
+       return 0;
+    }
+  return 1;
+}
+
+/* Check if OTF_CAPABILITY satisfies SPEC (otf-spec).  */
 
-/* Check if ENTITY matches with the font specification SPEC.  */
+static int
+font_check_otf (Lisp_Object spec, Lisp_Object otf_capability)
+{
+  Lisp_Object script, langsys = Qnil, gsub = Qnil, gpos = Qnil;
+
+  script = XCAR (spec);
+  spec = XCDR (spec);
+  if (! NILP (spec))
+    {
+      langsys = XCAR (spec);
+      spec = XCDR (spec);
+      if (! NILP (spec))
+       {
+         gsub = XCAR (spec);
+         spec = XCDR (spec);
+         if (! NILP (spec))
+           gpos = XCAR (spec);
+       }
+    }
+
+  if (! NILP (gsub) && ! font_check_otf_features (script, langsys, gsub,
+                                                 XCAR (otf_capability)))
+    return 0;
+  if (! NILP (gpos) && ! font_check_otf_features (script, langsys, gpos,
+                                                 XCDR (otf_capability)))
+    return 0;
+  return 1;
+}
+
+
+
+/* Check if FONT (font-entity or font-object) matches with the font
+   specification SPEC.  */
 
 int
-font_match_p (spec, entity)
-     Lisp_Object spec, entity;
+font_match_p (spec, font)
+     Lisp_Object spec, font;
 {
-  Lisp_Object prefer_prop[FONT_SPEC_MAX];
-  Lisp_Object alternate_families = Qnil;
+  Lisp_Object prop[FONT_SPEC_MAX], *props;
+  Lisp_Object extra, font_extra;
   int i;
 
-  for (i = FONT_FOUNDRY_INDEX; i <= FONT_SIZE_INDEX; i++)
-    prefer_prop[i] = AREF (spec, i);
-  if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
-    prefer_prop[FONT_SIZE_INDEX]
-      = make_number (font_pixel_size (XFRAME (selected_frame), spec));
-  if (! NILP (prefer_prop[FONT_FAMILY_INDEX]))
+  for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
+    if (! NILP (AREF (spec, i))
+       && ! NILP (AREF (font, i))
+       && ! EQ (AREF (spec, i), AREF (font, i)))
+      return 0;
+  props = XFONT_SPEC (spec)->props;
+  if (FLOATP (props[FONT_SIZE_INDEX]))
     {
-      alternate_families
-       = Fassoc_string (prefer_prop[FONT_FAMILY_INDEX],
-                        Vface_alternative_font_family_alist, Qt);
-      if (CONSP (alternate_families))
-       alternate_families = XCDR (alternate_families);
+      for (i = FONT_FOUNDRY_INDEX; i < FONT_SIZE_INDEX; i++)
+       prop[i] = AREF (spec, i);
+      prop[FONT_SIZE_INDEX]
+       = make_number (font_pixel_size (XFRAME (selected_frame), spec));
+      props = prop;
+    }
+
+  if (font_score (font, props) > 0)
+    return 0;
+  extra = AREF (spec, FONT_EXTRA_INDEX);
+  font_extra = AREF (font, FONT_EXTRA_INDEX);
+  for (; CONSP (extra); extra = XCDR (extra))
+    {
+      Lisp_Object key = XCAR (XCAR (extra));
+      Lisp_Object val = XCDR (XCAR (extra)), val2;
+
+      if (EQ (key, QClang))
+       {
+         val2 = assq_no_quit (key, font_extra);
+         if (NILP (val2))
+           return 0;
+         val2 = XCDR (val2);
+         if (CONSP (val))
+           {
+             if (! CONSP (val2))
+               return 0;
+             while (CONSP (val))
+               if (NILP (Fmemq (val, val2)))
+                 return 0;
+           }
+         else
+           if (CONSP (val2)
+               ? NILP (Fmemq (val, XCDR (val2)))
+               : ! EQ (val, val2))
+             return 0;
+       }
+      else if (EQ (key, QCscript))
+       {
+         val2 = assq_no_quit (val, Vscript_representative_chars);
+         if (CONSP (val2))
+           {
+             val2 = XCDR (val2);
+             if (CONSP (val2))
+               {
+                 /* All characters in the list must be supported.  */
+                 for (; CONSP (val2); val2 = XCDR (val2))
+                   {
+                     if (! NATNUMP (XCAR (val2)))
+                       continue;
+                     if (font_encode_char (font, XFASTINT (XCAR (val2)))
+                         == FONT_INVALID_CODE)
+                       return 0;
+                   }
+               }
+             else if (VECTORP (val2))
+               {
+                 /* At most one character in the vector must be supported.  */
+                 for (i = 0; i < ASIZE (val2); i++)
+                   {
+                     if (! NATNUMP (AREF (val2, i)))
+                       continue;
+                     if (font_encode_char (font, XFASTINT (AREF (val2, i)))
+                         != FONT_INVALID_CODE)
+                       break;
+                   }
+                 if (i == ASIZE (val2))
+                   return 0;
+               }
+           }
+       }
+      else if (EQ (key, QCotf))
+       {
+         struct font *fontp;
+
+         if (! FONT_OBJECT_P (font))
+           return 0;
+         fontp = XFONT_OBJECT (font);
+         if (! fontp->driver->otf_capability)
+           return 0;
+         val2 = fontp->driver->otf_capability (fontp);
+         if (NILP (val2) || ! font_check_otf (val, val2))
+           return 0;
+       }
     }
 
-  return (font_score (entity, prefer_prop) == 0);
+  return 1;
 }
 \f
 
@@ -2516,21 +2664,21 @@ font_clear_cache (f, cache, driver)
      struct font_driver *driver;
 {
   Lisp_Object tail, elt;
+  Lisp_Object tail2, entity;
 
   /* CACHE = (DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...) */
   for (tail = XCDR (XCDR (cache)); CONSP (tail); tail = XCDR (tail))
     {
       elt = XCAR (tail);
-      if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)) && VECTORP (XCDR (elt)))
+      /* elt should have the form (FONT-SPEC FONT-ENTITY ...) */
+      if (CONSP (elt) && FONT_SPEC_P (XCAR (elt)))
        {
-         Lisp_Object vec = XCDR (elt);
-         int i;
-
-         for (i = 0; i < ASIZE (vec); i++)
+         for (tail2 = XCDR (elt); CONSP (tail2); tail2 = XCDR (tail2))
            {
-             Lisp_Object entity = AREF (vec, i);
+             entity = XCAR (tail2);
 
-             if (EQ (driver->type, AREF (entity, FONT_TYPE_INDEX)))
+             if (FONT_ENTITY_P (entity)
+                 && EQ (driver->type, AREF (entity, FONT_TYPE_INDEX)))
                {
                  Lisp_Object objlist = AREF (entity, FONT_OBJLIST_INDEX);
 
@@ -2574,7 +2722,7 @@ font_delete_unmatched (list, spec, size)
            && ((XINT (AREF (spec, prop)) >> 8)
                != (XINT (AREF (entity, prop)) >> 8)))
          prop = FONT_SPEC_MAX;
-      if (prop++ <= FONT_SIZE_INDEX
+      if (prop < FONT_SPEC_MAX
          && size
          && XINT (AREF (entity, FONT_SIZE_INDEX)) > 0)
        {
@@ -2585,6 +2733,19 @@ font_delete_unmatched (list, spec, size)
                  : diff > FONT_PIXEL_SIZE_QUANTUM))
            prop = FONT_SPEC_MAX;
        }
+      if (prop < FONT_SPEC_MAX
+         && INTEGERP (AREF (spec, FONT_DPI_INDEX))
+         && INTEGERP (AREF (entity, FONT_DPI_INDEX))
+         && XINT (AREF (entity, FONT_DPI_INDEX)) != 0
+         && ! EQ (AREF (spec, FONT_DPI_INDEX), AREF (entity, FONT_DPI_INDEX)))
+       prop = FONT_SPEC_MAX;
+      if (prop < FONT_SPEC_MAX
+         && INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
+         && INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
+         && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) != 0
+         && ! EQ (AREF (spec, FONT_AVGWIDTH_INDEX),
+                  AREF (entity, FONT_AVGWIDTH_INDEX)))
+       prop = FONT_SPEC_MAX;
       if (prop < FONT_SPEC_MAX)
        val = Fcons (entity, val);
     }
@@ -2677,12 +2838,18 @@ font_matching_entity (f, attrs, spec)
   struct font_driver_list *driver_list = f->font_driver_list;
   Lisp_Object ftype, size, entity;
   Lisp_Object frame;
+  Lisp_Object work = Fcopy_font_spec (spec);
 
   XSETFRAME (frame, f);
   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)));
+    ASET (work, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
+  FONT_SET_STYLE (work, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
+  FONT_SET_STYLE (work, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
+  FONT_SET_STYLE (work, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
+
   entity = Qnil;
   for (; driver_list; driver_list = driver_list->next)
     if (driver_list->on
@@ -2691,23 +2858,21 @@ font_matching_entity (f, attrs, spec)
        Lisp_Object cache = font_get_cache (f, driver_list->driver);
        Lisp_Object copy;
 
-       ASET (spec, FONT_TYPE_INDEX, driver_list->driver->type);
-       entity = assoc_no_quit (spec, XCDR (cache));
+       ASET (work, FONT_TYPE_INDEX, driver_list->driver->type);
+       entity = assoc_no_quit (work, XCDR (cache));
        if (CONSP (entity))
          entity = XCDR (entity);
        else
          {
-           entity = driver_list->driver->match (frame, spec);
-           copy = Fcopy_font_spec (spec);
+           entity = driver_list->driver->match (frame, work);
+           copy = Fcopy_font_spec (work);
            ASET (copy, FONT_TYPE_INDEX, driver_list->driver->type);
            XSETCDR (cache, Fcons (Fcons (copy, entity), XCDR (cache)));
          }
        if (! NILP (entity))
          break;
       }
-  ASET (spec, FONT_TYPE_INDEX, ftype);
-  ASET (spec, FONT_SIZE_INDEX, size);
-  font_add_log ("match", spec, entity);
+  font_add_log ("match", work, entity);
   return entity;
 }
 
@@ -2724,12 +2889,15 @@ font_open_entity (f, entity, pixel_size)
   struct font_driver_list *driver_list;
   Lisp_Object objlist, size, val, font_object;
   struct font *font;
-  int min_width;
+  int min_width, height;
+  int scaled_pixel_size;
 
   font_assert (FONT_ENTITY_P (entity));
   size = AREF (entity, FONT_SIZE_INDEX);
   if (XINT (size) != 0)
-    pixel_size = XINT (size);
+    scaled_pixel_size = pixel_size = XINT (size);
+  else if (CONSP (Vface_font_rescale_alist))
+    scaled_pixel_size = pixel_size * font_rescale_ratio (entity);
 
   for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist);
        objlist = XCDR (objlist))
@@ -2744,7 +2912,8 @@ font_open_entity (f, entity, pixel_size)
   if (! driver_list)
     return Qnil;
 
-  font_object = driver_list->driver->open (f, entity, pixel_size);
+  font_object = driver_list->driver->open (f, entity, scaled_pixel_size);
+  ASET (font_object, FONT_SIZE_INDEX, make_number (pixel_size));
   font_add_log ("open", entity, font_object);
   if (NILP (font_object))
     return Qnil;
@@ -2758,20 +2927,21 @@ font_open_entity (f, entity, pixel_size)
               : font->average_width ? font->average_width
               : font->space_width ? font->space_width
               : 1);
+  height = (font->height ? font->height : 1);
 #ifdef HAVE_WINDOW_SYSTEM
   FRAME_X_DISPLAY_INFO (f)->n_fonts++;
   if (FRAME_X_DISPLAY_INFO (f)->n_fonts == 1)
     {
       FRAME_SMALLEST_CHAR_WIDTH (f) = min_width;
-      FRAME_SMALLEST_FONT_HEIGHT (f) = font->height;
+      FRAME_SMALLEST_FONT_HEIGHT (f) = height;
       fonts_changed_p = 1;
     }
   else
     {
       if (FRAME_SMALLEST_CHAR_WIDTH (f) > min_width)
        FRAME_SMALLEST_CHAR_WIDTH (f) = min_width, fonts_changed_p = 1;
-      if (FRAME_SMALLEST_FONT_HEIGHT (f) > font->height)
-       FRAME_SMALLEST_FONT_HEIGHT (f) = font->height, fonts_changed_p = 1;
+      if (FRAME_SMALLEST_FONT_HEIGHT (f) > height)
+       FRAME_SMALLEST_FONT_HEIGHT (f) = height, fonts_changed_p = 1;
     }
 #endif
 
@@ -2882,15 +3052,21 @@ font_get_spec (font_object)
   return spec;
 }
 
+
+/* Create a new font spec from FONT_NAME, and return it.  If FONT_NAME
+   could not be parsed by font_parse_name, return Qnil.  */
+
 Lisp_Object
 font_spec_from_name (font_name)
      Lisp_Object font_name;
 {
-  Lisp_Object args[2];
+  Lisp_Object spec = Ffont_spec (0, NULL);
 
-  args[0] = QCname;
-  args[1] = font_name;
-  return Ffont_spec (2, args);
+  CHECK_STRING (font_name);
+  if (font_parse_name ((char *) SDATA (font_name), spec) == -1)
+    return Qnil;
+  font_put_extra (spec, QCname, font_name);
+  return spec;
 }
 
 
@@ -2904,7 +3080,9 @@ font_clear_prop (attrs, prop)
   if (! FONTP (font))
     return;
   if (NILP (AREF (font, prop))
-      && prop != FONT_FAMILY_INDEX && prop != FONT_FOUNDRY_INDEX
+      && prop != FONT_FAMILY_INDEX
+      && prop != FONT_FOUNDRY_INDEX
+      && prop != FONT_WIDTH_INDEX
       && prop != FONT_SIZE_INDEX)
     return;
   font = Fcopy_font_spec (font);
@@ -2912,7 +3090,13 @@ font_clear_prop (attrs, prop)
   if (prop == FONT_FAMILY_INDEX || prop == FONT_FOUNDRY_INDEX)
     {
       if (prop == FONT_FAMILY_INDEX)
-       ASET (font, FONT_FOUNDRY_INDEX, Qnil);
+       {
+         ASET (font, FONT_FOUNDRY_INDEX, Qnil);
+         /* If we are setting the font family, we must also clear
+            FONT_WIDTH_INDEX to avoid rejecting families that lack
+            support for some widths.  */
+         ASET (font, FONT_WIDTH_INDEX, Qnil);
+       }
       ASET (font, FONT_ADSTYLE_INDEX, Qnil);
       ASET (font, FONT_REGISTRY_INDEX, Qnil);
       ASET (font, FONT_SIZE_INDEX, Qnil);
@@ -2926,6 +3110,8 @@ font_clear_prop (attrs, prop)
       ASET (font, FONT_SPACING_INDEX, Qnil);
       ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
     }
+  else if (prop == FONT_WIDTH_INDEX)
+    ASET (font, FONT_AVGWIDTH_INDEX, Qnil);
   attrs[LFACE_FONT_INDEX] = font;
 }
 
@@ -2947,7 +3133,7 @@ font_update_lface (f, attrs)
   if (! NILP (AREF (spec, FONT_WEIGHT_INDEX)))
     attrs[LFACE_WEIGHT_INDEX] = FONT_WEIGHT_FOR_FACE (spec);
   if (! NILP (AREF (spec, FONT_SLANT_INDEX)))
-    attrs[LFACE_SLANT_INDEX] = FONT_SLANT_FOR_FACE (spec);;
+    attrs[LFACE_SLANT_INDEX] = FONT_SLANT_FOR_FACE (spec);
   if (! NILP (AREF (spec, FONT_WIDTH_INDEX)))
     attrs[LFACE_SWIDTH_INDEX] = FONT_WIDTH_FOR_FACE (spec);
   if (! NILP (AREF (spec, FONT_SIZE_INDEX)))
@@ -2964,10 +3150,13 @@ font_update_lface (f, attrs)
            dpi = XINT (val);
          point = PIXEL_TO_POINT (XINT (AREF (spec, FONT_SIZE_INDEX)) * 10,
                                  dpi);
+         attrs[LFACE_HEIGHT_INDEX] = make_number (point);
        }
       else if (FLOATP (AREF (spec, FONT_SIZE_INDEX)))
-       point = XFLOAT_DATA (AREF (spec, FONT_SIZE_INDEX)) * 10;
-      attrs[LFACE_HEIGHT_INDEX] = make_number (point);
+       {
+         point = XFLOAT_DATA (AREF (spec, FONT_SIZE_INDEX)) * 10;
+         attrs[LFACE_HEIGHT_INDEX] = make_number (point);
+       }
     }
 }
 
@@ -2985,14 +3174,14 @@ font_find_for_lface (f, attrs, spec, c)
 {
   Lisp_Object work;
   Lisp_Object frame, entities, val, props[FONT_REGISTRY_INDEX + 1] ;
-  Lisp_Object size, foundry[3], *family, registry[3];
+  Lisp_Object size, foundry[3], *family, registry[3], adstyle[3];
   int pixel_size;
-  int i, j, k, result;
+  int i, j, k, l, result;
 
   registry[0] = AREF (spec, FONT_REGISTRY_INDEX);
   if (NILP (registry[0]))
     {
-      registry[0] = Qiso8859_1;
+      registry[0] = DEFAULT_ENCODING;
       registry[1] = Qascii_0;
       registry[2] = null_vector;
     }
@@ -3034,18 +3223,40 @@ font_find_for_lface (f, attrs, spec, c)
     foundry[1] = null_vector;
   else if (STRINGP (attrs[LFACE_FOUNDRY_INDEX]))
     {
-      foundry[0] = font_intern_prop (SDATA (attrs[LFACE_FOUNDRY_INDEX]),
-                                    SBYTES (attrs[LFACE_FOUNDRY_INDEX]), 1);
+      val = attrs[LFACE_FOUNDRY_INDEX];
+      foundry[0] = font_intern_prop ((char *) SDATA (val), SBYTES (val), 1);
       foundry[1] = Qnil;
       foundry[2] = null_vector;
     }
   else
     foundry[0] = Qnil, foundry[1] = null_vector;
 
+  adstyle[0] = AREF (work, FONT_ADSTYLE_INDEX);
+  if (! NILP (adstyle[0]))
+    adstyle[1] = null_vector;
+  else if (FONTP (attrs[LFACE_FONT_INDEX]))
+    {
+      Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
+
+      if (! NILP (AREF (face_font, FONT_ADSTYLE_INDEX)))
+       {
+         adstyle[0] = AREF (face_font, FONT_ADSTYLE_INDEX);
+         adstyle[1] = Qnil;
+         adstyle[2] = null_vector;
+       }
+      else
+       adstyle[0] = Qnil, adstyle[1] = null_vector;
+    }
+  else
+    adstyle[0] = Qnil, adstyle[1] = null_vector;
+
+
   val = AREF (work, FONT_FAMILY_INDEX);
   if (NILP (val) && STRINGP (attrs[LFACE_FAMILY_INDEX]))
-    val = font_intern_prop (SDATA (attrs[LFACE_FAMILY_INDEX]),
-                           SBYTES (attrs[LFACE_FAMILY_INDEX]), 1);
+    {
+      val = attrs[LFACE_FAMILY_INDEX];
+      val = font_intern_prop ((char *) SDATA (val), SBYTES (val), 1);
+    }
   if (NILP (val))
     {
       family = alloca ((sizeof family[0]) * 2);
@@ -3055,7 +3266,13 @@ font_find_for_lface (f, attrs, spec, c)
   else
     {
       Lisp_Object alters
-       = Fassoc_string (val, Vface_alternative_font_family_alist, Qt);
+       = Fassoc_string (val, Vface_alternative_font_family_alist,
+#ifndef HAVE_NS
+                        Qt
+#else
+                        Qnil
+#endif
+                        );
 
       if (! NILP (alters))
        {
@@ -3086,9 +3303,13 @@ font_find_for_lface (f, attrs, spec, c)
          for (k = 0; SYMBOLP (registry[k]); k++)
            {
              ASET (work, FONT_REGISTRY_INDEX, registry[k]);
-             entities = font_list_entities (frame, work);
-             if (ASIZE (entities) > 0)
-               goto found;
+             for (l = 0; SYMBOLP (adstyle[l]); l++)
+               {
+                 ASET (work, FONT_ADSTYLE_INDEX, adstyle[l]);
+                 entities = font_list_entities (frame, work);
+                 if (ASIZE (entities) > 0)
+                   goto found;
+               }
            }
        }
     }
@@ -3121,7 +3342,7 @@ font_find_for_lface (f, attrs, spec, c)
       if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
        FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
       ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
-      entities = font_sort_entites (entities, prefer, frame, work, c < 0);
+      entities = font_sort_entites (entities, prefer, frame, c < 0);
     }
   if (c < 0)
     return entities;
@@ -3174,10 +3395,28 @@ font_open_for_lface (f, entity, attrs, spec)
     size = font_pixel_size (f, spec);
   else
     {
-      double pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
+      double pt;
+      if (INTEGERP (attrs[LFACE_HEIGHT_INDEX]))
+       pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
+      else
+       {
+         struct face *def = FACE_FROM_ID (f, DEFAULT_FACE_ID);
+         Lisp_Object height = def->lface[LFACE_HEIGHT_INDEX];
+         if (INTEGERP (height))
+           pt = XINT (height);
+         else
+           abort(); /* We should never end up here.  */
+       }
 
       pt /= 10;
       size = POINT_TO_PIXEL (pt, f->resy);
+#ifdef HAVE_NS
+      if (size == 0)
+        {
+          Lisp_Object ffsize = get_frame_param(f, Qfontsize);
+          size = NUMBERP (ffsize) ? POINT_TO_PIXEL (XINT (ffsize), f->resy) : 0;
+        }
+#endif
     }
   return font_open_entity (f, entity, size);
 }
@@ -3252,7 +3491,11 @@ font_open_by_name (f, name)
   attrs[LFACE_FAMILY_INDEX] = attrs[LFACE_FOUNDRY_INDEX] = Qnil;
   attrs[LFACE_SWIDTH_INDEX] = attrs[LFACE_WEIGHT_INDEX]
     = attrs[LFACE_SLANT_INDEX] = Qnormal;
+#ifndef HAVE_NS
   attrs[LFACE_HEIGHT_INDEX] = make_number (120);
+#else
+  attrs[LFACE_HEIGHT_INDEX] = make_number (0);
+#endif
   attrs[LFACE_FONT_INDEX] = Qnil;
 
   return font_load_for_lface (f, attrs, spec);
@@ -3287,7 +3530,7 @@ register_font_driver (driver, f)
     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 = xmalloc (sizeof (struct font_driver_list));
   list->on = 0;
   list->driver = driver;
   list->next = NULL;
@@ -3301,6 +3544,20 @@ register_font_driver (driver, f)
     num_font_drivers++;
 }
 
+void
+free_font_driver_list (f)
+     FRAME_PTR f;
+{
+  struct font_driver_list *list, *next;
+
+  for (list = f->font_driver_list; list; list = next)
+    {
+      next = list->next;
+      xfree (list);
+    }
+  f->font_driver_list = NULL;
+}
+
 
 /* Make the frame F use font backends listed in NEW_DRIVERS (list of
    symbols, e.g. xft, x).  If NEW_DRIVERS is t, make F use all
@@ -3367,7 +3624,7 @@ font_update_drivers (f, new_drivers)
        }
       for (list = f->font_driver_list; list; list = list->next)
        if (! list->on)
-         list_table[i] = list;
+         list_table[i++] = list;
       list_table[i] = NULL;
 
       next = &f->font_driver_list;
@@ -3413,9 +3670,7 @@ font_put_frame_data (f, driver, data)
 
   if (! list)
     {
-      list = malloc (sizeof (struct font_data_list));
-      if (! list)
-       return -1;
+      list = xmalloc (sizeof (struct font_data_list));
       list->driver = driver;
       list->next = f->font_data_list;
       f->font_data_list = list;
@@ -3458,11 +3713,13 @@ font_at (c, pos, face, w, string)
   int multibyte;
   Lisp_Object font_object;
 
+  multibyte = (NILP (string)
+              ? ! NILP (current_buffer->enable_multibyte_characters)
+              : STRING_MULTIBYTE (string));
   if (c < 0)
     {
       if (NILP (string))
        {
-         multibyte = ! NILP (current_buffer->enable_multibyte_characters);
          if (multibyte)
            {
              EMACS_INT pos_byte = CHAR_TO_BYTE (pos);
@@ -3518,66 +3775,101 @@ font_at (c, pos, face, w, string)
 }
 
 
-/* Check how many characters after POS (at most to LIMIT) can be
-   displayed by the same font.  FACE is the face selected for the
-   character as POS on frame F.  STRING, if not nil, is the string to
-   check instead of the current buffer.
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* Check how many characters after POS (at most to *LIMIT) can be
+   displayed by the same font on the window W.  FACE, if non-NULL, is
+   the face selected for the character at POS.  If STRING is not nil,
+   it is the string to check instead of the current buffer.  In that
+   case, FACE must be not NULL.
 
-   The return value is the position of the character that is displayed
-   by the differnt font than that of the character as POS.  */
+   The return value is the font-object for the character at POS.
+   *LIMIT is set to the position where that font can't be used.
 
-EMACS_INT
-font_range (pos, limit, face, f, string)
-     EMACS_INT pos, limit;
+   It is assured that the current buffer (or STRING) is multibyte.  */
+
+Lisp_Object
+font_range (pos, limit, w, face, string)
+     EMACS_INT pos, *limit;
+     struct window *w;
      struct face *face;
-     FRAME_PTR f;
      Lisp_Object string;
 {
-  int multibyte;
-  EMACS_INT pos_byte;
+  EMACS_INT pos_byte, ignore, start, start_byte;
   int c;
-  struct font *font;
-  int first = 1;
+  Lisp_Object font_object = Qnil;
 
   if (NILP (string))
     {
-      multibyte = ! NILP (current_buffer->enable_multibyte_characters);
       pos_byte = CHAR_TO_BYTE (pos);
+      if (! face)
+       {
+         int face_id;
+
+         face_id = face_at_buffer_position (w, pos, 0, 0, &ignore, *limit, 0);
+         face = FACE_FROM_ID (XFRAME (w->frame), face_id);
+       }
     }
   else
     {
-      multibyte = STRING_MULTIBYTE (string);
+      font_assert (face);
       pos_byte = string_char_to_byte (string, pos);
     }
 
-  if (! multibyte)
-    /* All unibyte character are displayed by the same font.  */
-    return limit;
-
-  while (pos < limit)
+  start = pos, start_byte = pos_byte;
+  while (pos < *limit)
     {
-      int face_id;
+      Lisp_Object category;
 
       if (NILP (string))
        FETCH_CHAR_ADVANCE_NO_CHECK (c, pos, pos_byte);
       else
        FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, pos, pos_byte);
-      face_id = FACE_FOR_CHAR (f, face, c, pos, string);
-      face = FACE_FROM_ID (f, face_id);
-      if (first)
+      if (NILP (font_object))
        {
-         font = face->font;
-         first = 0;
+         font_object = font_for_char (face, c, pos - 1, string);
+         if (NILP (font_object))
+           return Qnil;
          continue;
        }
-      else if (font != face->font)
+
+      category = CHAR_TABLE_REF (Vunicode_category_table, c);
+      if (! EQ (category, QCf)
+         && ! CHAR_VARIATION_SELECTOR_P (c)
+         && font_encode_char (font_object, c) == FONT_INVALID_CODE)
        {
-         pos--;
-         break;
+         Lisp_Object f = font_for_char (face, c, pos - 1, string);
+         EMACS_INT i, i_byte;
+
+
+         if (NILP (f))
+           {
+             *limit = pos - 1;
+             return font_object;
+           }
+         i = start, i_byte = start_byte;
+         while (i < pos - 1)
+           {
+
+             if (NILP (string))
+               FETCH_CHAR_ADVANCE_NO_CHECK (c, i, i_byte);
+             else
+               FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, i, i_byte);
+             category = CHAR_TABLE_REF (Vunicode_category_table, c);
+             if (! EQ (category, QCf)
+                 && ! CHAR_VARIATION_SELECTOR_P (c)
+                 && font_encode_char (f, c) == FONT_INVALID_CODE)
+               {
+                 *limit = pos - 1;
+                 return font_object;
+               }
+           }
+         font_object = f;
        }
     }
-  return pos;
+  return font_object;
 }
+#endif
 
 \f
 /* Lisp API */
@@ -3630,13 +3922,43 @@ encoding of a font, e.g. ``iso8859-1''.
 `:size'
 
 VALUE must be a non-negative integer or a floating point number
-specifying the font size.  It specifies the font size in pixels
-(if VALUE is an integer), or in points (if VALUE is a float).
+specifying the font size.  It specifies the font size in pixels (if
+VALUE is an integer), or in points (if VALUE is a float).
 
 `:name'
 
 VALUE must be a string of XLFD-style or fontconfig-style font name.
-usage: (font-spec ARGS ...)  */)
+
+`:script'
+
+VALUE must be a symbol representing a script that the font must
+support.  It may be a symbol representing a subgroup of a script
+listed in the variable `script-representative-chars'.
+
+`:lang'
+
+VALUE must be a symbol of two-letter ISO-639 language names,
+e.g. `ja'.
+
+`:otf'
+
+VALUE must be a list (SCRIPT-TAG LANGSYS-TAG GSUB [ GPOS ]) to specify
+required OpenType features.
+
+  SCRIPT-TAG: OpenType script tag symbol (e.g. `deva').
+  LANGSYS-TAG: OpenType language system tag symbol,
+     or nil for the default language system.
+  GSUB: List of OpenType GSUB feature tag symbols, or nil if none required.
+  GPOS: List of OpenType GPOS feature tag symbols, or nil if none required.
+
+GSUB and GPOS may contain `nil' element.  In such a case, the font
+must not have any of the remaining elements.
+
+For instance, if the VALUE is `(thai nil nil (mark))', the font must
+be an OpenType font, and whose GPOS table of `thai' script's default
+language system must contain `mark' feature.
+
+usage: (font-spec ARGS...)  */)
      (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -3678,19 +4000,24 @@ DEFUN ("copy-font-spec", Fcopy_font_spec, Scopy_font_spec, 1, 1, 0,
      (font)
      Lisp_Object font;
 {
-  Lisp_Object new_spec, tail, extra;
+  Lisp_Object new_spec, tail, prev, extra;
   int i;
 
   CHECK_FONT (font);
   new_spec = font_make_spec ();
   for (i = 1; i < FONT_EXTRA_INDEX; i++)
     ASET (new_spec, i, AREF (font, i));
-  extra = Qnil;
-  for (tail = AREF (font, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
-    {
-      if (! EQ (XCAR (XCAR (tail)), QCfont_entity))
-       extra = Fcons (Fcons (XCAR (XCAR (tail)), XCDR (XCAR (tail))), extra);
-    }
+  extra = Fcopy_sequence (AREF (font, FONT_EXTRA_INDEX));
+  /* We must remove :font-entity property.  */
+  for (prev = Qnil, tail = extra; CONSP (tail); prev = tail, tail = XCDR (tail))
+    if (EQ (XCAR (XCAR (tail)), QCfont_entity))
+      {
+       if (NILP (prev))
+         extra = XCDR (extra);
+       else
+         XSETCDR (prev, XCDR (tail));
+       break;
+      }
   ASET (new_spec, FONT_EXTRA_INDEX, extra);
   return new_spec;
 }
@@ -3727,7 +4054,13 @@ properties in TO.  */)
 
 DEFUN ("font-get", Ffont_get, Sfont_get, 2, 2, 0,
        doc: /* Return the value of FONT's property KEY.
-FONT is a font-spec, a font-entity, or a font-object.  */)
+FONT is a font-spec, a font-entity, or a font-object.
+KEY must be one of these symbols:
+  :family, :weight, :slant, :width, :foundry, :adstyle, :registry,
+  :size, :name, :script
+See the documentation of `font-spec' for their meanings.
+If FONT is a font-entity or font-object, the value of :script may be
+a list of scripts that are supported by the font.  */)
      (font, key)
      Lisp_Object font, key;
 {
@@ -3744,6 +4077,8 @@ FONT is a font-spec, a font-entity, or a font-object.  */)
   return Fcdr (Fassq (key, AREF (font, FONT_EXTRA_INDEX)));
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
+
 DEFUN ("font-face-attributes", Ffont_face_attributes, Sfont_face_attributes, 1, 2, 0,
        doc: /* Return a plist of face attributes generated by FONT.
 FONT is a font name, a font-spec, a font-entity, or a font-object.
@@ -3752,7 +4087,8 @@ The return value is a list of the form
 \(:family FAMILY :height HEIGHT :weight WEIGHT :slant SLANT :width WIDTH)
 
 where FAMILY, HEIGHT, WEIGHT, SLANT, and WIDTH are face attribute values
-compatible with `set-face-attribute'.
+compatible with `set-face-attribute'.  Some of these key-attribute pairs
+may be omitted from the list if they are not specified by FONT.
 
 The optional argument FRAME specifies the frame that the face attributes
 are to be displayed on.  If omitted, the selected frame is used.  */)
@@ -3762,6 +4098,7 @@ are to be displayed on.  If omitted, the selected frame is used.  */)
   struct frame *f;
   Lisp_Object plist[10];
   Lisp_Object val;
+  int n = 0;
 
   if (NILP (frame))
     frame = selected_frame;
@@ -3781,38 +4118,53 @@ are to be displayed on.  If omitted, the selected frame is used.  */)
   else if (! FONTP (font))
     signal_error ("Invalid font object", font);
 
-  plist[0] = QCfamily;
   val = AREF (font, FONT_FAMILY_INDEX);
-  plist[1] = NILP (val) ? Qnil : SYMBOL_NAME (val);
+  if (! NILP (val))
+    {
+      plist[n++] = QCfamily;
+      plist[n++] = SYMBOL_NAME (val);
+    }
 
-  plist[2] = QCheight;
   val = AREF (font, FONT_SIZE_INDEX);
   if (INTEGERP (val))
     {
       Lisp_Object font_dpi = AREF (font, FONT_DPI_INDEX);
       int dpi = INTEGERP (font_dpi) ? XINT (font_dpi) : f->resy;
-      plist[3] = make_number (10 * PIXEL_TO_POINT (XINT (val), dpi));
+      plist[n++] = QCheight;
+      plist[n++] = make_number (PIXEL_TO_POINT (XINT (val) * 10, dpi));
     }
   else if (FLOATP (val))
-    plist[3] = make_number (10 * (int) XFLOAT_DATA (val));
-  else
-    plist[3] = Qnil;
+    {
+      plist[n++] = QCheight;
+      plist[n++] = make_number (10 * (int) XFLOAT_DATA (val));
+    }
 
-  plist[4] = QCweight;
   val = FONT_WEIGHT_FOR_FACE (font);
-  plist[5] = NILP (val) ? Qnormal : val;
+  if (! NILP (val))
+    {
+      plist[n++] = QCweight;
+      plist[n++] = val;
+    }
 
-  plist[6] = QCslant;
   val = FONT_SLANT_FOR_FACE (font);
-  plist[7] = NILP (val) ? Qnormal : val;
+  if (! NILP (val))
+    {
+      plist[n++] = QCslant;
+      plist[n++] = val;
+    }
 
-  plist[8] = QCwidth;
   val = FONT_WIDTH_FOR_FACE (font);
-  plist[9] = NILP (val) ? Qnormal : val;
+  if (! NILP (val))
+    {
+      plist[n++] = QCwidth;
+      plist[n++] = val;
+    }
 
-  return Flist (10, plist);
+  return Flist (n, plist);
 }
 
+#endif
+
 DEFUN ("font-put", Ffont_put, Sfont_put, 3, 3, 0,
        doc: /* Set one property of FONT-SPEC: give property PROP value VAL.  */)
      (font_spec, prop, val)
@@ -3864,7 +4216,7 @@ how close they are to PREFER.  */)
     return Fcons (AREF (vec, 0), Qnil);
 
   if (! NILP (prefer))
-    vec = font_sort_entites (vec, prefer, frame, font_spec, 0);
+    vec = font_sort_entites (vec, prefer, frame, 0);
 
   list = tail = Fcons (AREF (vec, 0), Qnil);
   if (n == 0 || n > len)
@@ -3899,17 +4251,12 @@ Optional argument FRAME, if non-nil, specifies the target frame.  */)
     if (driver_list->driver->list_family)
       {
        Lisp_Object val = driver_list->driver->list_family (frame);
+       Lisp_Object tail = list;
 
-       if (NILP (list))
-         list = val;
-       else
-         {
-           Lisp_Object tail = list;
-
-           for (; CONSP (val); val = XCDR (val))
-             if (NILP (Fmemq (XCAR (val), tail)))
-               list = Fcons (XCAR (val), list);
-         }
+       for (; CONSP (val); val = XCDR (val))
+         if (NILP (Fmemq (XCAR (val), tail))
+             && SYMBOLP (XCAR (val)))
+           list = Fcons (SYMBOL_NAME (XCAR (val)), list);
       }
   return list;
 }
@@ -4006,272 +4353,147 @@ DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0,
   return Qnil;
 }
 
-/* The following three functions are still experimental.  */
-
-DEFUN ("font-make-gstring", Ffont_make_gstring, Sfont_make_gstring, 2, 2, 0,
-       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 WIDTH LBEARING RBEARING ASCENT DESCENT]
-where
-    FONT-OBJECT is a font-object for all glyphs in the g-string,
-    WIDTH thru DESCENT are the metrics (in pixels) of the whole G-string.
-GLYPH is a vector of this form:
-    [ FROM-IDX TO-IDX C CODE WIDTH LBEARING RBEARING ASCENT DESCENT
-      [ [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.
-    WIDTH thru DESCENT are the metrics (in pixels) of the glyph.
-    X-OFF and Y-OFF are offests to the base position for the glyph.
-    WADJUST is the adjustment to the normal width of the glyph.  */)
-     (font_object, num)
-     Lisp_Object font_object, num;
-{
-  Lisp_Object gstring, g;
-  int len;
-  int i;
-
-  if (! NILP (font_object))
-    CHECK_FONT_OBJECT (font_object);
-  CHECK_NATNUM (num);
-
-  len = XINT (num) + 1;
-  gstring = Fmake_vector (make_number (len), Qnil);
-  g = Fmake_vector (make_number (6), Qnil);
-  ASET (g, 0, font_object);
-  ASET (gstring, 0, g);
-  for (i = 1; i < len; i++)
-    ASET (gstring, i, Fmake_vector (make_number (10), Qnil));
-  return gstring;
-}
-
-DEFUN ("font-fill-gstring", Ffont_fill_gstring, Sfont_fill_gstring, 4, 5, 0,
-       doc: /* Fill in glyph-string GSTRING by characters for FONT-OBJECT.
-START and END specify the region to extract characters.
-If optional 5rd argument OBJECT is non-nil, it is a buffer or a string from
-where to extract characters.
-FONT-OBJECT may be nil if GSTRING already contains one.  */)
-     (gstring, font_object, start, end, object)
-     Lisp_Object gstring, font_object, start, end, object;
+\f
+void
+font_fill_lglyph_metrics (glyph, font_object)
+     Lisp_Object glyph, font_object;
 {
-  int len, i, c;
+  struct font *font = XFONT_OBJECT (font_object);
   unsigned code;
-  struct font *font;
-
-  CHECK_VECTOR (gstring);
-  if (NILP (font_object))
-    font_object = LGSTRING_FONT (gstring);
-  font = XFONT_OBJECT (font_object);
-
-  if (STRINGP (object))
-    {
-      const unsigned char *p;
+  /* ecode used in LGLYPH_SET_CODE to avoid compiler warnings.  */
+  EMACS_INT ecode = font->driver->encode_char (font, LGLYPH_CHAR (glyph));
+  struct font_metrics metrics;
 
-      CHECK_NATNUM (start);
-      CHECK_NATNUM (end);
-      if (XINT (start) > XINT (end)
-         || XINT (end) > ASIZE (object)
-         || XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
-       args_out_of_range_3 (object, start, end);
+  LGLYPH_SET_CODE (glyph, ecode);
+  code = ecode;
+  font->driver->text_extents (font, &code, 1, &metrics);
+  LGLYPH_SET_LBEARING (glyph, metrics.lbearing);
+  LGLYPH_SET_RBEARING (glyph, metrics.rbearing);
+  LGLYPH_SET_WIDTH (glyph, metrics.width);
+  LGLYPH_SET_ASCENT (glyph, metrics.ascent);
+  LGLYPH_SET_DESCENT (glyph, metrics.descent);
+}
 
-      len = XINT (end) - XINT (start);
-      p = SDATA (object) + string_char_to_byte (object, XINT (start));
-      for (i = 0; i < len; i++)
-       {
-         Lisp_Object g = LGSTRING_GLYPH (gstring, i);
-         /* Shut up GCC warning in comparison with
-            MOST_POSITIVE_FIXNUM below.  */
-         EMACS_INT cod;
-
-         c = STRING_CHAR_ADVANCE (p);
-         cod = code = font->driver->encode_char (font, c);
-         if (cod > MOST_POSITIVE_FIXNUM || code == FONT_INVALID_CODE)
-           break;
-         LGLYPH_SET_FROM (g, i);
-         LGLYPH_SET_TO (g, i);
-         LGLYPH_SET_CHAR (g, c);
-         LGLYPH_SET_CODE (g, code);
-       }
-    }
-  else
-    {
-      int pos, pos_byte;
 
-      if (! NILP (object))
-       Fset_buffer (object);
-      validate_region (&start, &end);
-      if (XINT (end) - XINT (start) > LGSTRING_LENGTH (gstring))
-       args_out_of_range (start, end);
-      len = XINT (end) - XINT (start);
-      pos = XINT (start);
-      pos_byte = CHAR_TO_BYTE (pos);
-      for (i = 0; i < len; i++)
-       {
-         Lisp_Object g = LGSTRING_GLYPH (gstring, i);
-         /* Shut up GCC warning in comparison with
-            MOST_POSITIVE_FIXNUM below.  */
-         EMACS_INT cod;
-
-         FETCH_CHAR_ADVANCE (c, pos, pos_byte);
-         cod = code = font->driver->encode_char (font, c);
-         if (cod > MOST_POSITIVE_FIXNUM || code == FONT_INVALID_CODE)
-           break;
-         LGLYPH_SET_FROM (g, i);
-         LGLYPH_SET_TO (g, i);
-         LGLYPH_SET_CHAR (g, c);
-         LGLYPH_SET_CODE (g, code);
-       }
-    }
-  for (; i < LGSTRING_LENGTH (gstring); i++)
-    LGSTRING_SET_GLYPH (gstring, i, Qnil);
-  return Qnil;
-}
+DEFUN ("font-shape-gstring", Ffont_shape_gstring, Sfont_shape_gstring, 1, 1, 0,
+       doc: /* Shape the glyph-string GSTRING.
+Shaping means substituting glyphs and/or adjusting positions of glyphs
+to get the correct visual image of character sequences set in the
+header of the glyph-string.
 
-DEFUN ("font-shape-text", Ffont_shape_text, Sfont_shape_text, 3, 4, 0,
-       doc: /* Shape text between FROM and TO by FONT-OBJECT.
-If optional 4th argument STRING is non-nil, it is a string to shape,
-and FROM and TO are indices to the string.
-The value is the end position of the text that can be shaped by
-FONT-OBJECT.  */)
-     (from, to, font_object, string)
-     Lisp_Object from, to, font_object, string;
+If the shaping was successful, the value is GSTRING itself or a newly
+created glyph-string.  Otherwise, the value is nil.  */)
+     (gstring)
+     Lisp_Object gstring;
 {
   struct font *font;
-  struct font_metrics metrics;
-  EMACS_INT start, end;
-  Lisp_Object gstring, n;
-  int len, i;
-
-  if (! FONT_OBJECT_P (font_object))
-    return Qnil;
+  Lisp_Object font_object, n, glyph;
+  int i, j, from, to;
+
+  if (! composition_gstring_p (gstring))
+    signal_error ("Invalid glyph-string: ", gstring);
+  if (! NILP (LGSTRING_ID (gstring)))
+    return gstring;
+  font_object = LGSTRING_FONT (gstring);
+  CHECK_FONT_OBJECT (font_object);
   font = XFONT_OBJECT (font_object);
   if (! font->driver->shape)
     return Qnil;
 
-  if (NILP (string))
-    {
-      validate_region (&from, &to);
-      start = XFASTINT (from);
-      end = XFASTINT (to);
-      modify_region (current_buffer, start, end, 0);
-    }
-  else
-    {
-      CHECK_STRING (string);
-      start = XINT (from);
-      end = XINT (to);
-      if (start < 0 || start > end || end > SCHARS (string))
-       args_out_of_range_3 (string, from, to);
-    }
-
-  len = end - start;
-  gstring = Ffont_make_gstring (font_object, make_number (len));
-  Ffont_fill_gstring (gstring, font_object, from, to, string);
-
   /* Try at most three times with larger gstring each time.  */
   for (i = 0; i < 3; i++)
     {
-      Lisp_Object args[2];
-
       n = font->driver->shape (gstring);
       if (INTEGERP (n))
        break;
-      args[0] = gstring;
-      args[1] = Fmake_vector (make_number (len), Qnil);
-      gstring = Fvconcat (2, args);
+      gstring = larger_vector (gstring,
+                              ASIZE (gstring) + LGSTRING_GLYPH_LEN (gstring),
+                              Qnil);
     }
-  if (! INTEGERP (n) || XINT (n) == 0)
+  if (i == 3 || XINT (n) == 0)
     return Qnil;
-  len = XINT (n);
-
-  for (i = 0; i < len;)
-    {
-      Lisp_Object gstr;
-      Lisp_Object g = LGSTRING_GLYPH (gstring, i);
-      EMACS_INT this_from = LGLYPH_FROM (g);
-      EMACS_INT this_to = LGLYPH_TO (g) + 1;
-      int j, k;
-      int need_composition = 0;
-
-      metrics.lbearing = LGLYPH_LBEARING (g);
-      metrics.rbearing = LGLYPH_RBEARING (g);
-      metrics.ascent = LGLYPH_ASCENT (g);
-      metrics.descent = LGLYPH_DESCENT (g);
-      if (NILP (LGLYPH_ADJUSTMENT (g)))
-       {
-         metrics.width = LGLYPH_WIDTH (g);
-         if (LGLYPH_CHAR (g) == 0 || metrics.width == 0)
-           need_composition = 1;
-       }
-      else
-       {
-         metrics.width = LGLYPH_WADJUST (g);
-         metrics.lbearing += LGLYPH_XOFF (g);
-         metrics.rbearing += LGLYPH_XOFF (g);
-         metrics.ascent -= LGLYPH_YOFF (g);
-         metrics.descent += LGLYPH_YOFF (g);
-         need_composition = 1;
-       }
-      for (j = i + 1; j < len; j++)
-       {
-         int x;
 
-         g = LGSTRING_GLYPH (gstring, j);
-         if (this_from != LGLYPH_FROM (g))
-           break;
-         need_composition = 1;
-         x = metrics.width + LGLYPH_LBEARING (g) + LGLYPH_XOFF (g);
-         if (metrics.lbearing > x)
-           metrics.lbearing = x;
-         x = metrics.width + LGLYPH_RBEARING (g) + LGLYPH_XOFF (g);
-         if (metrics.rbearing < x)
-           metrics.rbearing = x;
-         x = LGLYPH_ASCENT (g) - LGLYPH_YOFF (g);
-         if (metrics.ascent < x)
-           metrics.ascent = x;
-         x = LGLYPH_DESCENT (g) - LGLYPH_YOFF (g);
-         if (metrics.descent < x)
-           metrics.descent = x;
-         if (NILP (LGLYPH_ADJUSTMENT (g)))
-           metrics.width += LGLYPH_WIDTH (g);
-         else
-           metrics.width += LGLYPH_WADJUST (g);
-       }
+  glyph = LGSTRING_GLYPH (gstring, 0);
+  from = LGLYPH_FROM (glyph);
+  to = LGLYPH_TO (glyph);
+  for (i = 1, j = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
+    {
+      Lisp_Object this = LGSTRING_GLYPH (gstring, i);
 
-      if (need_composition)
+      if (NILP (this))
+       break;
+      if (NILP (LGLYPH_ADJUSTMENT (this)))
        {
-         gstr = Ffont_make_gstring (font_object, make_number (j - i));
-         LGSTRING_SET_WIDTH (gstr, metrics.width);
-         LGSTRING_SET_LBEARING (gstr, metrics.lbearing);
-         LGSTRING_SET_RBEARING (gstr, metrics.rbearing);
-         LGSTRING_SET_ASCENT (gstr, metrics.ascent);
-         LGSTRING_SET_DESCENT (gstr, metrics.descent);
-         for (k = i; i < j; i++)
-           {
-             Lisp_Object g = LGSTRING_GLYPH (gstring, i);
-
-             LGLYPH_SET_FROM (g, LGLYPH_FROM (g) - this_from);
-             LGLYPH_SET_TO (g, LGLYPH_TO (g) - this_from);
-             LGSTRING_SET_GLYPH (gstr, i - k, LGSTRING_GLYPH (gstring, i));
-           }
-         from = make_number (start + this_from);
-         to = make_number (start + this_to);
-         if (NILP (string))
-           Fcompose_region_internal (from, to, gstr, Qnil);
-         else
-           Fcompose_string_internal (string, from, to, gstr, Qnil);
+         if (j < i - 1)
+           for (; j < i; j++)
+             {
+               glyph = LGSTRING_GLYPH (gstring, j);
+               LGLYPH_SET_FROM (glyph, from);
+               LGLYPH_SET_TO (glyph, to);
+             }
+         from = LGLYPH_FROM (this);
+         to = LGLYPH_TO (this);
+         j = i;
        }
       else
-       i = j;
+       {
+         if (from > LGLYPH_FROM (this))
+           from = LGLYPH_FROM (this);
+         if (to < LGLYPH_TO (this))
+           to = LGLYPH_TO (this);
+       }
     }
+  if (j < i - 1)
+    for (; j < i; j++)
+      {
+       glyph = LGSTRING_GLYPH (gstring, j);
+       LGLYPH_SET_FROM (glyph, from);
+       LGLYPH_SET_TO (glyph, to);
+      }
+  return composition_gstring_put_cache (gstring, XINT (n));
+}
 
-  return to;
+DEFUN ("font-variation-glyphs", Ffont_variation_glyphs, Sfont_variation_glyphs,
+       2, 2, 0,
+       doc: /* Return a list of variation glyphs for CHAR in FONT-OBJECT.
+Each element of the value is a cons (VARIATION-SELECTOR . GLYPH-ID),
+where
+  VARIATION-SELECTOR is a chracter code of variation selection
+    (#xFE00..#xFE0F or #xE0100..#xE01EF)
+  GLYPH-ID is a glyph code of the corresponding variation glyph.  */)
+     (font_object, character)
+     Lisp_Object font_object, character;
+{
+  unsigned variations[256];
+  struct font *font;
+  int i, n;
+  Lisp_Object val;
+
+  CHECK_FONT_OBJECT (font_object);
+  CHECK_CHARACTER (character);
+  font = XFONT_OBJECT (font_object);
+  if (! font->driver->get_variation_glyphs)
+    return Qnil;
+  n = font->driver->get_variation_glyphs (font, XINT (character), variations);
+  if (! n)
+    return Qnil;
+  val = Qnil;
+  for (i = 0; i < 255; i++)
+    if (variations[i])
+      {
+       Lisp_Object code;
+       int vs = (i < 16 ? 0xFE00 + i : 0xE0100 + (i - 16));
+       /* Stops GCC whining about limited range of data type.  */
+       EMACS_INT var = variations[i];
+
+       if (var > MOST_POSITIVE_FIXNUM)
+         code = Fcons (make_number ((variations[i]) >> 16),
+                       make_number ((variations[i]) & 0xFFFF));
+       else
+         code = make_number (variations[i]);
+       val = Fcons (Fcons (make_number (vs), code), val);
+      }
+  return val;
 }
 
 #if 0
@@ -4419,7 +4641,7 @@ DEFUN ("open-font", Fopen_font, Sopen_font, 1, 3, 0,
     {
       CHECK_NUMBER_OR_FLOAT (size);
       if (FLOATP (size))
-       isize = POINT_TO_PIXEL (- isize, XFRAME (frame)->resy);
+       isize = POINT_TO_PIXEL (XFLOAT_DATA (size), XFRAME (frame)->resy);
       else
        isize = XINT (size);
       if (isize == 0)
@@ -4739,6 +4961,15 @@ build_style_table (entry, nelement)
 static Lisp_Object Vfont_log;
 static int font_log_env_checked;
 
+/* The deferred font-log data of the form [ACTION ARG RESULT].
+   If ACTION is not nil, that is added to the log when font_add_log is
+   called next time.  At that time, ACTION is set back to nil.  */
+static Lisp_Object Vfont_log_deferred;
+
+/* Prepend the font-related logging data in Vfont_log if it is not
+   `t'.  ACTION describes a kind of font-related action (e.g. listing,
+   opening), ARG is the argument for the action, and RESULT is the
+   result of the action.  */
 void
 font_add_log (action, arg, result)
      char *action;
@@ -4754,10 +4985,49 @@ font_add_log (action, arg, result)
     }
   if (EQ (Vfont_log, Qt))
     return;
+  if (STRINGP (AREF (Vfont_log_deferred, 0)))
+    {
+      char *str = (char *) SDATA (AREF (Vfont_log_deferred, 0));
+
+      ASET (Vfont_log_deferred, 0, Qnil);
+      font_add_log (str, AREF (Vfont_log_deferred, 1),
+                   AREF (Vfont_log_deferred, 2));
+    }
+
   if (FONTP (arg))
-    arg = Ffont_xlfd_name (arg, Qt);
+    {
+      Lisp_Object tail, elt;
+      Lisp_Object equalstr = build_string ("=");
+
+      val = Ffont_xlfd_name (arg, Qt);
+      for (tail = AREF (arg, FONT_EXTRA_INDEX); CONSP (tail);
+          tail = XCDR (tail))
+       {
+         elt = XCAR (tail);
+         if (EQ (XCAR (elt), QCscript)
+             && SYMBOLP (XCDR (elt)))
+           val = concat3 (val, SYMBOL_NAME (QCscript),
+                          concat2 (equalstr, SYMBOL_NAME (XCDR (elt))));
+         else if (EQ (XCAR (elt), QClang)
+                  && SYMBOLP (XCDR (elt)))
+           val = concat3 (val, SYMBOL_NAME (QClang),
+                          concat2 (equalstr, SYMBOL_NAME (XCDR (elt))));
+         else if (EQ (XCAR (elt), QCotf)
+                  && CONSP (XCDR (elt)) && SYMBOLP (XCAR (XCDR (elt))))
+           val = concat3 (val, SYMBOL_NAME (QCotf),
+                          concat2 (equalstr,
+                                   SYMBOL_NAME (XCAR (XCDR (elt)))));
+       }
+      arg = val;
+    }
   if (FONTP (result))
-    result = Ffont_xlfd_name (result, Qt);
+    {
+      val = Ffont_xlfd_name (result, Qt);
+      if (! FONT_SPEC_P (result))
+       val = concat3 (SYMBOL_NAME (AREF (result, FONT_TYPE_INDEX)),
+                      build_string (":"), val);
+      result = val;
+    }
   else if (CONSP (result))
     {
       result = Fcopy_sequence (result);
@@ -4783,6 +5053,20 @@ font_add_log (action, arg, result)
   Vfont_log = Fcons (list3 (intern (action), arg, result), Vfont_log);
 }
 
+/* Record a font-related logging data to be added to Vfont_log when
+   font_add_log is called next time.  ACTION, ARG, RESULT are the same
+   as font_add_log.  */
+
+void
+font_deferred_log (action, arg, result)
+     char *action;
+     Lisp_Object arg, result;
+{
+  ASET (Vfont_log_deferred, 0, build_string (action));
+  ASET (Vfont_log_deferred, 1, arg);
+  ASET (Vfont_log_deferred, 2, result);
+}
+
 extern void syms_of_ftfont P_ (());
 extern void syms_of_xfont P_ (());
 extern void syms_of_xftfont P_ (());
@@ -4790,6 +5074,7 @@ extern void syms_of_ftxfont P_ (());
 extern void syms_of_bdffont P_ (());
 extern void syms_of_w32font P_ (());
 extern void syms_of_atmfont P_ (());
+extern void syms_of_nsfont P_ (());
 
 void
 syms_of_font ()
@@ -4804,10 +5089,6 @@ syms_of_font ()
   staticpro (&font_charset_alist);
   font_charset_alist = Qnil;
 
-  DEFSYM (Qfont_spec, "font-spec");
-  DEFSYM (Qfont_entity, "font-entity");
-  DEFSYM (Qfont_object, "font-object");
-
   DEFSYM (Qopentype, "opentype");
 
   DEFSYM (Qascii_0, "ascii-0");
@@ -4816,6 +5097,8 @@ syms_of_font ()
   DEFSYM (Qunicode_bmp, "unicode-bmp");
   DEFSYM (Qunicode_sip, "unicode-sip");
 
+  DEFSYM (QCf, "Cf");
+
   DEFSYM (QCotf, ":otf");
   DEFSYM (QClang, ":lang");
   DEFSYM (QCscript, ":script");
@@ -4844,6 +5127,9 @@ syms_of_font ()
   staticpro (&scratch_font_prefer);
   scratch_font_prefer = Ffont_spec (0, NULL);
 
+  staticpro (&Vfont_log_deferred);
+  Vfont_log_deferred = Fmake_vector (make_number (3), Qnil);
+
 #if 0
 #ifdef HAVE_LIBOTF
   staticpro (&otf_list);
@@ -4854,16 +5140,17 @@ syms_of_font ()
   defsubr (&Sfontp);
   defsubr (&Sfont_spec);
   defsubr (&Sfont_get);
+#ifdef HAVE_WINDOW_SYSTEM
   defsubr (&Sfont_face_attributes);
+#endif
   defsubr (&Sfont_put);
   defsubr (&Slist_fonts);
   defsubr (&Sfont_family_list);
   defsubr (&Sfind_font);
   defsubr (&Sfont_xlfd_name);
   defsubr (&Sclear_font_cache);
-  defsubr (&Sfont_make_gstring);
-  defsubr (&Sfont_fill_gstring);
-  defsubr (&Sfont_shape_text);
+  defsubr (&Sfont_shape_gstring);
+  defsubr (&Sfont_variation_glyphs);
 #if 0
   defsubr (&Sfont_drive_otf);
   defsubr (&Sfont_otf_alternates);
@@ -4957,9 +5244,9 @@ EMACS_FONT_LOG is set.  Otherwise, it is set to t.  */);
 #ifdef WINDOWSNT
   syms_of_w32font ();
 #endif /* WINDOWSNT */
-#ifdef MAC_OS
-  syms_of_atmfont ();
-#endif /* MAC_OS */
+#ifdef HAVE_NS
+  syms_of_nsfont ();
+#endif /* HAVE_NS */
 #endif /* HAVE_WINDOW_SYSTEM */
 }