]> code.delx.au - gnu-emacs/blobdiff - src/font.c
* term/ns-win.el: Standardize references to "Nextstep" in
[gnu-emacs] / src / font.c
index 6c29a4487bd7f2341fa3b5035413c9073a3d5876..9ceedddb2977cdec05413ac74c8e3fe35fad65a0 100644 (file)
@@ -46,17 +46,31 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "w32term.h"
 #endif /* HAVE_NTGUI */
 
+#ifdef HAVE_NS
+#include "nsterm.h"
+#endif /* HAVE_NS */
+
 #ifdef MAC_OS
 #include "macterm.h"
 #endif /* MAC_OS */
 
 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
+
 /* 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;
@@ -126,7 +140,9 @@ static struct table_entry width_table[] =
 extern Lisp_Object Qnormal;
 
 /* Symbols representing keys of normal font properties.  */
-extern Lisp_Object QCtype, QCfamily, QCweight, QCslant, QCwidth, QCsize, QCname;
+extern Lisp_Object QCtype, QCfamily, QCweight, QCslant, QCwidth;
+extern Lisp_Object QCheight, QCsize, QCname;
+
 Lisp_Object QCfoundry, QCadstyle, QCregistry;
 /* Symbols representing keys of font extra info.  */
 Lisp_Object QCspacing, QCdpi, QCscalable, QCotf, QClang, QCscript, QCavgwidth;
@@ -187,15 +203,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;
 }
 
@@ -371,7 +404,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;
@@ -1107,7 +1140,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
     {
@@ -1357,18 +1390,21 @@ 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 == '-')
        {
-         int size_found = 1;
+         int decimal = 0, size_found = 1;
          for (q = p + 1; *q && *q != ':'; q++)
-           if (! isdigit(*q) && *q != '.')
+           if (! isdigit(*q))
              {
-               size_found = 0;
-               break;
+               if (*q != '.' || decimal)
+                 {
+                   size_found = 0;
+                   break;
+                 }
+               decimal = 1;
              }
          if (size_found)
            {
@@ -1394,33 +1430,26 @@ 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;
-
-#define PROP_MATCH(STR,N) ((word_len == N) && memcmp (p, STR, N) == 0)
-
              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)
+
                  if (PROP_MATCH ("light", 5)
                      || PROP_MATCH ("medium", 6)
                      || PROP_MATCH ("demibold", 8)
@@ -1440,48 +1469,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 (PROP_MATCH ("pixelsize=", 10))
+                 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);
 
-                 val = font_intern_prop (p, word_len, 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;
-#undef PROP_MATCH
+             p = q;
            }
-         if (name != copy)
-           font_put_extra (font, QCfc_unknown_spec,
-                           make_unibyte_string (name, copy - name));
        }
     }
   else
@@ -1495,8 +1510,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))
                  {
@@ -1569,7 +1584,7 @@ font_parse_fcname (name, font)
          ASET (font, FONT_FAMILY_INDEX, family);
        }
     }
-      
+
   return 0;
 }
 
@@ -1584,6 +1599,7 @@ font_unparse_fcname (font, pixel_size, name, nbytes)
      char *name;
      int nbytes;
 {
+  Lisp_Object family, foundry;
   Lisp_Object tail, val;
   int point_size;
   int dpi;
@@ -1593,9 +1609,17 @@ font_unparse_fcname (font, pixel_size, name, nbytes)
   char *style_names[3] = { "weight", "slant", "width" };
   char work[256];
 
-  val = AREF (font, FONT_FAMILY_INDEX);
-  if (STRINGP (val))
-    len += SBYTES (val);
+  family = AREF (font, FONT_FAMILY_INDEX);
+  if (! NILP (family))
+    {
+      if (SYMBOLP (family))
+       {
+         family = SYMBOL_NAME (family);
+         len += SBYTES (family);
+       }
+      else
+       family = Qnil;
+    }
 
   val = AREF (font, FONT_SIZE_INDEX);
   if (INTEGERP (val))
@@ -1612,10 +1636,17 @@ font_unparse_fcname (font, pixel_size, name, nbytes)
       len += 11;               /* for "-NUM" */
     }
 
-  val = AREF (font, FONT_FOUNDRY_INDEX);
-  if (STRINGP (val))
-    /* ":foundry=NAME" */
-    len += 9 + SBYTES (val);
+  foundry = AREF (font, FONT_FOUNDRY_INDEX);
+  if (! NILP (foundry))
+    {
+      if (SYMBOLP (foundry))
+       {
+         foundry = SYMBOL_NAME (foundry);
+         len += 9 + SBYTES (foundry); /* ":foundry=NAME" */
+       }
+      else
+       foundry = Qnil;
+    }
 
   for (i = 0; i < 3; i++)
     {
@@ -1647,8 +1678,8 @@ font_unparse_fcname (font, pixel_size, name, nbytes)
   if (len > nbytes)
     return -1;
   p = name;
-  if (! NILP (AREF (font, FONT_FAMILY_INDEX)))
-    p += sprintf(p, "%s", SDATA (SYMBOL_NAME (AREF (font, FONT_FAMILY_INDEX))));
+  if (! NILP (family))
+    p += sprintf (p, "%s", SDATA (family));
   if (point_size > 0)
     {
       if (p == name)
@@ -1679,6 +1710,94 @@ font_unparse_fcname (font, pixel_size, name, nbytes)
   return (p - name);
 }
 
+/* Store GTK-style font name of FONT (font-spec or font-entity) in
+   NAME (NBYTES length), and return the name length.  F is the frame
+   on which the font is displayed; it is used to calculate the point
+   size.  */
+
+int
+font_unparse_gtkname (font, f, name, nbytes)
+     Lisp_Object font;
+     struct frame *f;
+     char *name;
+     int nbytes;
+{
+  char *p;
+  int len = 1;
+  Lisp_Object family, weight, slant, size;
+  int point_size = -1;
+
+  family = AREF (font, FONT_FAMILY_INDEX);
+  if (! NILP (family))
+    {
+      if (! SYMBOLP (family))
+       return -1;
+      family = SYMBOL_NAME (family);
+      len += SBYTES (family);
+    }
+
+  weight = font_style_symbolic (font, FONT_WEIGHT_INDEX, 0);
+  if (EQ (weight, Qnormal))
+    weight = Qnil;
+  else if (! NILP (weight))
+    {
+      weight = SYMBOL_NAME (weight);
+      len += SBYTES (weight);
+    }
+
+  slant = font_style_symbolic (font, FONT_SLANT_INDEX, 0);
+  if (EQ (slant, Qnormal))
+    slant = Qnil;
+  else if (! NILP (slant))
+    {
+      slant = SYMBOL_NAME (slant);
+      len += SBYTES (slant);
+    }
+
+  size = AREF (font, FONT_SIZE_INDEX);
+  /* Convert pixel size to point size.  */
+  if (INTEGERP (size))
+    {
+      Lisp_Object font_dpi = AREF (font, FONT_DPI_INDEX);
+      int dpi = 75;
+      if (INTEGERP (font_dpi))
+       dpi = XINT (font_dpi);
+      else if (f)
+       dpi = f->resy;
+      point_size = PIXEL_TO_POINT (XINT (size), dpi);
+      len += 11;
+    }
+  else if (FLOATP (size))
+    {
+      point_size = (int) XFLOAT_DATA (size);
+      len += 11;
+    }
+
+  if (len > nbytes)
+    return -1;
+
+  p = name + sprintf (name, "%s", SDATA (family));
+
+  if (! NILP (weight))
+    {
+      char *q = p;
+      p += sprintf (p, " %s", SDATA (weight));
+      q[1] = toupper (q[1]);
+    }
+
+  if (! NILP (slant))
+    {
+      char *q = p;
+      p += sprintf (p, " %s", SDATA (slant));
+      q[1] = toupper (q[1]);
+    }
+
+  if (point_size > 0)
+    p += sprintf (p, " %d", point_size);
+
+  return (p - name);
+}
+
 /* Parse NAME (null terminated) and store information in FONT
    (font-spec or font-entity).  If NAME is successfully parsed, return
    0.  Otherwise return -1.  */
@@ -2077,8 +2196,7 @@ font_prepare_composition (cmp, f)
 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
@@ -2097,10 +2215,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)
@@ -2117,15 +2232,13 @@ font_score (entity, spec_prop)
 
        if (diff < 0)
          diff = - diff;
-       /* This is to prefer the exact symbol style.  */
-       diff++;
-       score |= min (diff, 127) << sort_shift_bits[i];
+       if (diff > 0)
+         score |= min (diff, 127) << sort_shift_bits[i];
       }
 
   /* 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.  */
@@ -2165,15 +2278,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];
@@ -2190,22 +2302,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));
@@ -2239,7 +2337,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++)
@@ -2281,53 +2379,156 @@ 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;
+      if (NILP (Fmemq (XCAR (features), table)) != negative)
+       return 0;
+    }
+  return 1;
+}
 
-/* Check if ENTITY matches with the font specification SPEC.  */
+/* Check if OTF_CAPABILITY satisfies SPEC (otf-spec).  */
 
-int
-font_match_p (spec, entity)
-     Lisp_Object spec, entity;
+static int
+font_check_otf (Lisp_Object spec, Lisp_Object otf_capability)
 {
-  Lisp_Object prefer_prop[FONT_SPEC_MAX];
-  Lisp_Object alternate_families = Qnil;
-  int i;
+  Lisp_Object script, langsys = Qnil, gsub = Qnil, gpos = Qnil;
 
-  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]))
+  script = XCAR (spec);
+  spec = XCDR (spec);
+  if (! NILP (spec))
     {
-      alternate_families
-       = Fassoc_string (prefer_prop[FONT_FAMILY_INDEX],
-                        Vface_alternative_font_family_alist, Qt);
-      if (CONSP (alternate_families))
-       alternate_families = XCDR (alternate_families);
+      langsys = XCAR (spec);
+      spec = XCDR (spec);
+      if (! NILP (spec))
+       {
+         gsub = XCAR (spec);
+         spec = XCDR (spec);
+         if (! NILP (spec))
+           gpos = XCAR (spec);
+       }
     }
 
-  return (font_score (entity, prefer_prop) == 0);
+  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 a lispy font object corresponding to FONT.  */
+
+/* Check if FONT (font-entity or font-object) matches with the font
+   specification SPEC.  */
 
 int
-font_check_object (font)
-     struct font *font;
+font_match_p (spec, font)
+     Lisp_Object spec, font;
 {
-  Lisp_Object tail, elt;
+  Lisp_Object prop[FONT_SPEC_MAX], *props;
+  Lisp_Object extra, font_extra;
+  int i;
 
-  for (tail = font->props[FONT_OBJLIST_INDEX]; CONSP (tail);
-       tail = XCDR (tail))
+  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]))
     {
-      elt = XCAR (tail);
-      if (font == XFONT_OBJECT (elt))
-       return 1;
+      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 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 (! NILP (val2))
+           for (val2 = XCDR (val2); CONSP (val2); val2 = XCDR (val2))
+             if (font_encode_char (font, XINT (XCAR (val2)))
+                 == FONT_INVALID_CODE)
+               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
 
 /* Font cache
@@ -2444,9 +2645,12 @@ font_clear_cache (f, cache, driver)
                      Lisp_Object val = XCAR (objlist);
                      struct font *font = XFONT_OBJECT (val);
 
-                     font_assert (font && driver == font->driver);
-                     driver->close (f, font);
-                     num_fonts--;
+                     if (! NILP (AREF (val, FONT_TYPE_INDEX)))
+                       {
+                         font_assert (font && driver == font->driver);
+                         driver->close (f, font);
+                         num_fonts--;
+                       }
                    }
                  if (driver->free_entity)
                    driver->free_entity (entity);
@@ -2476,7 +2680,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)
        {
@@ -2487,6 +2691,17 @@ 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))
+         && ! 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))
+         && ! EQ (AREF (spec, FONT_AVGWIDTH_INDEX),
+                  AREF (entity, FONT_AVGWIDTH_INDEX)))
+       prop = FONT_SPEC_MAX;
       if (prop < FONT_SPEC_MAX)
        val = Fcons (entity, val);
     }
@@ -2626,7 +2841,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);
@@ -2635,7 +2850,8 @@ font_open_entity (f, entity, pixel_size)
 
   for (objlist = AREF (entity, FONT_OBJLIST_INDEX); CONSP (objlist);
        objlist = XCDR (objlist))
-    if (XFONT_OBJECT (XCAR (objlist))->pixel_size == pixel_size)
+    if (! NILP (AREF (XCAR (objlist), FONT_TYPE_INDEX))
+       && XFONT_OBJECT (XCAR (objlist))->pixel_size == pixel_size)
       return  XCAR (objlist);
 
   val = AREF (entity, FONT_TYPE_INDEX);
@@ -2651,7 +2867,7 @@ font_open_entity (f, entity, pixel_size)
     return Qnil;
   ASET (entity, FONT_OBJLIST_INDEX,
        Fcons (font_object, AREF (entity, FONT_OBJLIST_INDEX)));
-  ASET (font_object, FONT_OBJLIST_INDEX, AREF (entity, FONT_OBJLIST_INDEX));
+  ASET (font_object, FONT_OBJLIST_INDEX, Qnil);
   num_fonts++;
 
   font = XFONT_OBJECT (font_object);
@@ -2659,20 +2875,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
 
@@ -2688,28 +2905,17 @@ font_close_object (f, font_object)
      Lisp_Object font_object;
 {
   struct font *font = XFONT_OBJECT (font_object);
-  Lisp_Object objlist;
-  Lisp_Object tail, prev = Qnil;
 
-  objlist = AREF (font_object, FONT_OBJLIST_INDEX);
-  for (prev = Qnil, tail = objlist; CONSP (tail);
-       prev = tail, tail = XCDR (tail))
-    if (EQ (font_object, XCAR (tail)))
-      {
-       font_add_log ("close", font_object, Qnil);
-       font->driver->close (f, font);
+  if (NILP (AREF (font_object, FONT_TYPE_INDEX)))
+    /* Already closed.  */
+    return;
+  font_add_log ("close", font_object, Qnil);
+  font->driver->close (f, font);
 #ifdef HAVE_WINDOW_SYSTEM
-       font_assert (FRAME_X_DISPLAY_INFO (f)->n_fonts);
-       FRAME_X_DISPLAY_INFO (f)->n_fonts--;
+  font_assert (FRAME_X_DISPLAY_INFO (f)->n_fonts);
+  FRAME_X_DISPLAY_INFO (f)->n_fonts--;
 #endif
-       if (NILP (prev))
-         ASET (font_object, FONT_OBJLIST_INDEX, XCDR (objlist));
-       else
-         XSETCDR (prev, XCDR (objlist));
-       num_fonts--;
-       return;
-      }
-  abort ();
+  num_fonts--;
 }
 
 
@@ -2897,9 +3103,19 @@ 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;
+  Lisp_Object size, foundry[3], *family, registry[3], adstyle[3];
   int pixel_size;
-  int i, j, result;
+  int i, j, k, l, result;
+
+  registry[0] = AREF (spec, FONT_REGISTRY_INDEX);
+  if (NILP (registry[0]))
+    {
+      registry[0] = DEFAULT_ENCODING;
+      registry[1] = Qascii_0;
+      registry[2] = null_vector;
+    }
+  else
+    registry[1] = null_vector;
 
   if (c >= 0 && ! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
     {
@@ -2944,6 +3160,26 @@ font_find_for_lface (f, attrs, spec, c)
   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]),
@@ -2979,21 +3215,27 @@ font_find_for_lface (f, attrs, spec, c)
        }
     }
 
-  for (j = 0; SYMBOLP (family[j]); j++)
+  for (i = 0; SYMBOLP (family[i]); i++)
     {
-      ASET (work, FONT_FAMILY_INDEX, family[j]);
-      for (i = 0; SYMBOLP (foundry[i]); i++)
+      ASET (work, FONT_FAMILY_INDEX, family[i]);
+      for (j = 0; SYMBOLP (foundry[j]); j++)
        {
-         ASET (work, FONT_FOUNDRY_INDEX, foundry[i]);
-         entities = font_list_entities (frame, work);
-         if (ASIZE (entities) > 0)
-           break;
+         ASET (work, FONT_FOUNDRY_INDEX, foundry[j]);
+         for (k = 0; SYMBOLP (registry[k]); k++)
+           {
+             ASET (work, FONT_REGISTRY_INDEX, registry[k]);
+             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;
+               }
+           }
        }
-      if (ASIZE (entities) > 0)
-       break;
     }
-  if (ASIZE (entities) == 0)
-    return Qnil;
+  return Qnil;
+ found:
   if (ASIZE (entities) == 1)
     {
       if (c < 0)
@@ -3021,7 +3263,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;
@@ -3078,6 +3320,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);
 }
@@ -3152,7 +3401,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);
@@ -3252,7 +3505,7 @@ font_update_drivers (f, new_drivers)
   if (! EQ (new_drivers, Qt))
     {
       /* Re-order the driver list according to new_drivers.  */
-      struct font_driver_list **list_table, *list;
+      struct font_driver_list **list_table, **next;
       Lisp_Object tail;
       int i;
 
@@ -3270,15 +3523,13 @@ font_update_drivers (f, new_drivers)
          list_table[i] = list;
       list_table[i] = NULL;
 
-      f->font_driver_list = list = NULL;
+      next = &f->font_driver_list;
       for (i = 0; list_table[i]; i++)
        {
-         if (list)
-           list->next = list_table[i], list = list->next;
-         else
-           f->font_driver_list = list = list_table[i];
+         *next = list_table[i];
+         next = &(*next)->next;
        }
-      list->next = NULL;
+      *next = NULL;
     }
 
   for (list = f->font_driver_list; list; list = list->next)
@@ -3415,7 +3666,6 @@ font_at (c, pos, face, w, string)
   if (! face->font)
     return Qnil;
 
-  font_assert (font_check_object ((struct font *) face->font));
   XSETFONT (font_object, face->font);
   return font_object;
 }
@@ -3535,6 +3785,10 @@ 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).
+
+`:name'
+
+VALUE must be a string of XLFD-style or fontconfig-style font name.
 usage: (font-spec ARGS ...)  */)
      (nargs, args)
      int nargs;
@@ -3577,19 +3831,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;
 }
@@ -3636,11 +3895,100 @@ 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)
+
+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.  */)
+     (font, frame)
+     Lisp_Object font, frame;
+{
+  struct frame *f;
+  Lisp_Object plist[10];
+  Lisp_Object val;
+  int n = 0;
+
+  if (NILP (frame))
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame);
+  f = XFRAME (frame);
+
+  if (STRINGP (font))
+    {
+      int fontset = fs_query_fontset (font, 0);
+      Lisp_Object name = font;
+      if (fontset >= 0)
+       font = fontset_ascii (fontset);
+      font = font_spec_from_name (name);
+      if (! FONTP (font))
+       signal_error ("Invalid font name", name);
+    }
+  else if (! FONTP (font))
+    signal_error ("Invalid font object", font);
+
+  val = AREF (font, FONT_FAMILY_INDEX);
+  if (! NILP (val))
+    {
+      plist[n++] = QCfamily;
+      plist[n++] = SYMBOL_NAME (val);
+    }
+
+  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[n++] = QCheight;
+      plist[n++] = make_number (PIXEL_TO_POINT (XINT (val) * 10, dpi));
+    }
+  else if (FLOATP (val))
+    {
+      plist[n++] = QCheight;
+      plist[n++] = make_number (10 * (int) XFLOAT_DATA (val));
+    }
+
+  val = FONT_WEIGHT_FOR_FACE (font);
+  if (! NILP (val))
+    {
+      plist[n++] = QCweight;
+      plist[n++] = val;
+    }
+
+  val = FONT_SLANT_FOR_FACE (font);
+  if (! NILP (val))
+    {
+      plist[n++] = QCslant;
+      plist[n++] = val;
+    }
+
+  val = FONT_WIDTH_FOR_FACE (font);
+  if (! NILP (val))
+    {
+      plist[n++] = QCwidth;
+      plist[n++] = val;
+    }
+
+  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.  */)
@@ -3693,7 +4041,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)
@@ -4551,7 +4899,7 @@ build_style_table (entry, nelement)
 {
   int i, j;
   Lisp_Object table, elt;
-  
+
   table = Fmake_vector (make_number (nelement), Qnil);
   for (i = 0; i < nelement; i++)
     {
@@ -4559,7 +4907,7 @@ build_style_table (entry, nelement)
       elt = Fmake_vector (make_number (j + 1), Qnil);
       ASET (elt, 0, make_number (entry[i].numeric));
       for (j = 0; entry[i].names[j]; j++)
-       ASET (elt, j + 1, intern (entry[i].names[j])); 
+       ASET (elt, j + 1, intern (entry[i].names[j]));
       ASET (table, i, elt);
     }
   return table;
@@ -4586,7 +4934,13 @@ font_add_log (action, arg, result)
   if (FONTP (arg))
     arg = Ffont_xlfd_name (arg, Qt);
   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);
@@ -4619,6 +4973,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 ()
@@ -4683,6 +5038,9 @@ 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);
@@ -4738,17 +5096,17 @@ gets the repertory information by an opened font and ENCODING.  */);
               doc: /*  Vector of valid font weight values.
 Each element has the form:
     [NUMERIC-VALUE SYMBOLIC-NAME ALIAS-NAME ...]
-NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symobls. */);
+NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symbols. */);
   Vfont_weight_table = BUILD_STYLE_TABLE (weight_table);
 
   DEFVAR_LISP_NOPRO ("font-slant-table", &Vfont_slant_table,
               doc: /*  Vector of font slant symbols vs the corresponding numeric values.
-See `font-weight_table' for the format of the vector. */);
+See `font-weight-table' for the format of the vector. */);
   Vfont_slant_table = BUILD_STYLE_TABLE (slant_table);
 
   DEFVAR_LISP_NOPRO ("font-width-table", &Vfont_width_table,
               doc: /*  Alist of font width symbols vs the corresponding numeric values.
-See `font-weight_table' for the format of the vector. */);
+See `font-weight-table' for the format of the vector. */);
   Vfont_width_table = BUILD_STYLE_TABLE (width_table);
 
   staticpro (&font_style_table);
@@ -4785,6 +5143,9 @@ EMACS_FONT_LOG is set.  Otherwise, it is set to t.  */);
 #ifdef WINDOWSNT
   syms_of_w32font ();
 #endif /* WINDOWSNT */
+#ifdef HAVE_NS
+  syms_of_nsfont ();
+#endif /* HAVE_NS */
 #ifdef MAC_OS
   syms_of_atmfont ();
 #endif /* MAC_OS */