(font_match_p): Fix previous change.
[bpt/emacs.git] / src / font.c
index 60c0b4f..a8753ba 100644 (file)
@@ -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,30 @@ 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;
@@ -189,15 +199,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;
 }
 
@@ -357,11 +384,12 @@ font_style_to_value (prop, val, noerror)
 }
 
 Lisp_Object
-font_style_symbolic_from_value (prop, val, for_face)
+font_style_symbolic (font, prop, for_face)
+     Lisp_Object font;
      enum font_property_index prop;
-     Lisp_Object val;
      int for_face;
 {
+  Lisp_Object val = AREF (font, prop);
   Lisp_Object table, elt;
   int i;
 
@@ -375,16 +403,6 @@ font_style_symbolic_from_value (prop, val, for_face)
   return (for_face ? AREF (elt, 1) : AREF (elt, (i & 0xF) + 1));  
 }
 
-Lisp_Object
-font_style_symbolic (font, prop, for_face)
-     Lisp_Object font;
-     enum font_property_index prop;
-     int for_face;
-{
-  Lisp_Object val = AREF (font, prop);
-  return font_style_symbolic_from_value (prop, val, for_face);
-}
-
 extern Lisp_Object Vface_alternative_font_family_alist;
 
 extern Lisp_Object find_font_encoding P_ ((Lisp_Object));
@@ -1118,7 +1136,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
     {
@@ -1368,8 +1386,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 == '-')
@@ -1409,30 +1426,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;
-
-         name = copy = alloca (name + len - props_beg);
-         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)
@@ -1456,48 +1465,34 @@ font_parse_fcname (name, font)
                  else if (PROP_MATCH ("proportional", 12))
                    ASET (font, FONT_SPACING_INDEX,
                          make_number (FONT_SPACING_PROPORTIONAL));
-                 else
-                   {
-                     /* Unknown key  */
-                     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
                    {
                      key = font_intern_prop (p, q - p, 1);
                      prop = get_font_prop_index (key);
                    }
+
                  p = q + 1;
                  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
-                       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 (name != copy)
-           font_put_extra (font, QCfc_unknown_spec,
-                           make_unibyte_string (name, copy - name));
        }
     }
   else
@@ -1511,8 +1506,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))
                  {
@@ -1738,7 +1733,7 @@ font_unparse_gtkname (font, f, name, nbytes)
     }
 
   weight = font_style_symbolic (font, FONT_WEIGHT_INDEX, 0);
-  if (weight == Qnormal)
+  if (EQ (weight, Qnormal))
     weight = Qnil;
   else if (! NILP (weight))
     {
@@ -1747,7 +1742,7 @@ font_unparse_gtkname (font, f, name, nbytes)
     }
 
   slant = font_style_symbolic (font, FONT_SLANT_INDEX, 0);
-  if (slant == Qnormal)
+  if (EQ (slant, Qnormal))
     slant = Qnil;
   else if (! NILP (slant))
     {
@@ -1898,7 +1893,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);
@@ -2163,42 +2158,13 @@ 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));
 
 /* We sort fonts by scoring each of them against a specified
    font-spec.  The score value is 32 bit (`unsigned'), and the smaller
@@ -2217,10 +2183,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)
@@ -2243,8 +2206,7 @@ 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[i]) && XINT (AREF (entity, i)) > 0)
     {
       /* We use the higher 6-bit for the actual size difference.  The
         lowest bit is set if the DPI is different.  */
@@ -2284,15 +2246,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];
@@ -2309,22 +2270,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));
@@ -2358,7 +2305,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++)
@@ -2400,32 +2347,180 @@ 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;
 
-/* Check if ENTITY matches with the font specification SPEC.  */
+  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;
+      if (NILP (Fmemq (XCAR (features), table)) != negative)
+       return 0;
+    }
+  return 1;
+}
+
+/* Check if OTF_CAPABILITY satisfies SPEC (otf-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;
     }
 
-  return (font_score (entity, prefer_prop) == 0);
+  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 1;
 }
 \f
 
@@ -2578,7 +2673,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)
        {
@@ -2589,6 +2684,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);
     }
@@ -2681,12 +2789,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
@@ -2695,23 +2809,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;
 }
 
@@ -2728,7 +2840,7 @@ 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;
 
   font_assert (FONT_ENTITY_P (entity));
   size = AREF (entity, FONT_SIZE_INDEX);
@@ -2762,20 +2874,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
 
@@ -2908,7 +3021,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);
@@ -2930,6 +3045,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;
 }
 
@@ -2989,14 +3106,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;
     }
@@ -3038,18 +3155,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);
@@ -3059,7 +3198,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))
        {
@@ -3090,9 +3235,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;
+               }
            }
        }
     }
@@ -3125,7 +3274,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;
@@ -3182,6 +3331,13 @@ font_open_for_lface (f, entity, attrs, spec)
 
       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);
 }
@@ -3256,7 +3412,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);
@@ -3522,66 +3682,99 @@ 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 font-object for the character at POS.
+   *LIMIT is set to the position where that font can't be used.
 
-   The return value is the position of the character that is displayed
-   by the differnt font than that of the character as POS.  */
+   It is assured that the current buffer (or STRING) is multibyte.  */
 
-EMACS_INT
-font_range (pos, limit, face, f, string)
-     EMACS_INT pos, limit;
+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)
+         && 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)
+                 && 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 */
@@ -3636,7 +3829,16 @@ encoding of a font, e.g. ``iso8859-1''.
 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).
-usage: (font-spec ARGS ...)  */)
+
+`: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.  */)
      (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -3678,19 +3880,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 +3934,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;
 {
@@ -3737,30 +3950,35 @@ FONT is a font-spec, a font-entity, or a font-object.  */)
   CHECK_SYMBOL (key);
 
   idx = get_font_prop_index (key);
+  if (idx >= FONT_WEIGHT_INDEX && idx <= FONT_WIDTH_INDEX)
+    return font_style_symbolic (font, idx, 0);
   if (idx >= 0 && idx < FONT_EXTRA_INDEX)
     return AREF (font, idx);
   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.
 The return value is a list of the form
 
-(:family FAMILY :height HEIGHT :weight WEIGHT :slant SLANT :width WIDTH)
+\(:family FAMILY :height HEIGHT :weight WEIGHT :slant SLANT :width WIDTH)
 
-where FAMILY, FOUNDRY, HEIGHT, WEIGHT, SLANT, and WIDTH are face
-attribute values compatible with `set-face-attribute'.
+where FAMILY, HEIGHT, WEIGHT, SLANT, and WIDTH are face attribute values
+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.  */)
+The optional argument FRAME specifies the frame that the face attributes
+are to be displayed on.  If omitted, the selected frame is used.  */)
      (font, frame)
-     Lisp_Object font;
+     Lisp_Object font, frame;
 {
   struct frame *f;
   Lisp_Object plist[10];
   Lisp_Object val;
+  int n = 0;
 
   if (NILP (frame))
     frame = selected_frame;
@@ -3780,38 +3998,53 @@ 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)
@@ -3863,7 +4096,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)
@@ -4005,272 +4238,104 @@ 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;
+  /* 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_VECTOR (gstring);
-  if (NILP (font_object))
-    font_object = LGSTRING_FONT (gstring);
-  font = XFONT_OBJECT (font_object);
+  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);
+}
 
-  if (STRINGP (object))
-    {
-      const unsigned char *p;
 
-      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);
+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.
 
-      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-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)))
+  
+  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 (NILP (this))
+       break;
+      if (NILP (LGLYPH_ADJUSTMENT (this)))
        {
-         metrics.width = LGLYPH_WIDTH (g);
-         if (LGLYPH_CHAR (g) == 0 || metrics.width == 0)
-           need_composition = 1;
+         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
        {
-         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;
+         if (from > LGLYPH_FROM (this))
+           from = LGLYPH_FROM (this);
+         if (to < LGLYPH_TO (this))
+           to = LGLYPH_TO (this);
        }
-      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);
-       }
-
-      if (need_composition)
-       {
-         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);
-       }
-      else
-       i = j;
     }
-
-  return to;
+  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));
 }
 
 #if 0
@@ -4738,6 +4803,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;
@@ -4753,10 +4827,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);
@@ -4782,6 +4895,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_ (());
@@ -4789,6 +4916,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 ()
@@ -4815,6 +4943,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");
@@ -4843,6 +4973,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);
@@ -4853,16 +4986,16 @@ 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);
 #if 0
   defsubr (&Sfont_drive_otf);
   defsubr (&Sfont_otf_alternates);
@@ -4956,9 +5089,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 */
 }