diff src/font.c @ 90481:93690200f520

(POINT_TO_PIXEL): Don't divice POINT by 10. (QCspacing, QCdpi): New variables. (syms_of_font): Initialize them. (font_pixel_size): New function. (font_put_extra): New function. (font_parse_xlfd): Fix handling of font size. Add QCdpi property in FONT_EXTRA. (font_parse_fcname): Handle enumenrated values (e.g. bold). Fix handling font size. Add QCname property that contains only unknown properties. (font_score): Change argument. Caller changed. Pay attention to FONT_PIXEL_SIZE_QUANTUM. (font_sort_entites): Fix handling of font size. (font_list_entities): Likewise. (font_find_for_lface): Likewise. (font_open_for_lface): Likewise. (font_open_by_name): Likewise. (Ffont_spec): Add QCname property that contains only unknown properties.
author Kenichi Handa <handa@m17n.org>
date Mon, 19 Jun 2006 12:43:59 +0000
parents 017a6aec5d77
children 72186e5bf7ed
line wrap: on
line diff
--- a/src/font.c	Mon Jun 19 12:36:58 2006 +0000
+++ b/src/font.c	Mon Jun 19 12:43:59 2006 +0000
@@ -64,10 +64,12 @@
 /* Number of pt per inch (from the TeXbook).  */
 #define PT_PER_INCH 72.27
 
-/* Return a pixel size corresponding to POINT size (1/10 pt unit) on
-   resolution RESY.  */
-#define POINT_TO_PIXEL(POINT, RESY) ((POINT) * (RESY) / PT_PER_INCH / 10 + 0.5)
-
+/* Return a pixel size (integer) corresponding to POINT size (double)
+   on resolution RESY.  */
+#define POINT_TO_PIXEL(POINT, RESY) ((POINT) * (RESY) / PT_PER_INCH + 0.5)
+
+/* Return a point size (double) corresponding to POINT size (integer)
+   on resolution RESY.  */
 #define PIXEL_TO_POINT(PIXEL, RESY) ((PIXEL) * PT_PER_INCH * 10 / (RESY) + 0.5)
 
 /* Special string of zero length.  It is used to specify a NULL name
@@ -99,7 +101,7 @@
 extern Lisp_Object QCtype, QCfamily, QCweight, QCslant, QCwidth, QCsize, QCname;
 Lisp_Object QCfoundry, QCadstyle, QCregistry, QCextra;
 /* Symbols representing keys of font extra info.  */
-Lisp_Object QCotf, QClanguage, QCscript;
+Lisp_Object QCspacing, QCdpi, QCotf, QClanguage, QCscript;
 
 /* List of all font drivers.  All font-backends (XXXfont.c) call
    add_font_driver in syms_of_XXXfont to register the font-driver
@@ -114,6 +116,33 @@
 /* Number of registered font drivers.  */
 static int num_font_drivers;
 
+/* Return a pixel size of font-spec SPEC on frame F.  */
+static int
+font_pixel_size (f, spec)
+     FRAME_PTR f;
+     Lisp_Object spec;
+{
+  Lisp_Object size = AREF (spec, FONT_SIZE_INDEX);
+  double point_size;
+  int pixel_size, dpi;
+  Lisp_Object extra, val;
+      
+  if (INTEGERP (size))
+    return XINT (size);
+  if (NILP (size))
+    return 0;
+  point_size = XFLOAT_DATA (size);
+  extra = AREF (spec, FONT_EXTRA_INDEX);
+  val = assq_no_quit (extra, QCdpi);
+
+  if (CONSP (val) && INTEGERP (XCDR (val)))
+    dpi = XINT (XCDR (val));
+  else
+    dpi = f->resy;
+  pixel_size = POINT_TO_PIXEL (point_size, dpi);
+  return pixel_size;
+}
+
 /* Return a numeric value corresponding to PROP's NAME (symbol).  If
    NAME is not registered in font_style_table, return Qnil.  PROP must
    be one of FONT_{WEIGHT|SLANT|SWIDTH}_INDEX.  */
@@ -345,6 +374,26 @@
   return spec;
 }
       
+static void
+font_put_extra (font, prop, val, force)
+     Lisp_Object font, prop, val;
+     int force;
+{
+  Lisp_Object extra = AREF (font, FONT_EXTRA_INDEX);
+  Lisp_Object slot = (NILP (extra) ? Qnil : Fassq (prop, extra));
+
+  if (NILP (slot))
+    {
+      extra = Fcons (Fcons (prop, val), extra);
+      ASET (font, FONT_EXTRA_INDEX, extra);
+      return;
+    }
+  if (! NILP (XCDR (slot)) && ! force)
+    return;
+  XSETCDR (slot, val);
+  return;
+}
+
 
 /* Font name parser and unparser */
 
@@ -635,8 +684,19 @@
 }
 
 /* Parse NAME (null terminated) as XLFD and store information in FONT
-   (font-spec or font-entity).  See font_parse_name for more
-   detail.  */
+   (font-spec or font-entity).  Size property of FONT is set as
+   follows:
+	specified XLFD fields		FONT property
+	---------------------		-------------
+	PIXEL_SIZE			PIXEL_SIZE (Lisp integer)
+	POINT_SIZE and RESY		calculated pixel size (Lisp integer)
+	POINT_SIZE			POINT_SIZE/10 (Lisp float)
+
+   If NAME is successfully parsed, return 2 (size is specified), 1
+   (size is not specified), or 0 (size is not specified but resolution
+   is specified).  Otherwise return -1.
+
+   See font_parse_name for more detail.  */
 
 int
 font_parse_xlfd (name, font, merge)
@@ -690,6 +750,8 @@
 		}
 	      else if (i == XLFD_POINT_INDEX)
 		{
+		  /* If PIXEL_SIZE is specified, we don't have to
+		     calculate POINT_SIZE.  */
 		  if (pixel_size < 0)
 		    {
 		      if (isdigit (*name))
@@ -707,6 +769,8 @@
 	      else if (i == XLFD_RESY_INDEX)
 		{
 		  /* Stuff RESY, SPACING, and AVGWIDTH.  */
+		  /* If PIXEL_SIZE is specified, we don't have to
+		     calculate RESY.  */
 		  if (pixel_size < 0 && isdigit (*name))
 		    resy = atoi (name);
 		  for (p++; *p != '-'; p++);
@@ -776,10 +840,15 @@
 	return -1;
       if (! NILP (f[XLFD_PIXEL_INDEX]))
 	pixel_size = XINT (f[XLFD_PIXEL_INDEX]);
-      if (! NILP (f[XLFD_POINT_INDEX]))
-	point_size = XINT (f[XLFD_POINT_INDEX]);
-      if (! NILP (f[XLFD_RESY_INDEX]))
-	resy = XINT (f[XLFD_RESY_INDEX]);
+      /* If PIXEL_SIZE is specified, we don't have to
+	 calculate POINT_SIZE and RESY.  */
+      if (pixel_size < 0)
+	{
+	  if (! NILP (f[XLFD_POINT_INDEX]))
+	    point_size = XINT (f[XLFD_POINT_INDEX]);
+	  if (! NILP (f[XLFD_RESY_INDEX]))
+	    resy = XINT (f[XLFD_RESY_INDEX]);
+	}
       if (! NILP (f[XLFD_AVGWIDTH_INDEX]))
 	avgwidth = XINT (f[XLFD_AVGWIDTH_INDEX]);
       if (NILP (f[XLFD_REGISTRY_INDEX]))
@@ -828,22 +897,16 @@
       if (pixel_size >= 0)
 	ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
       else if (point_size >= 0)
-	{
-	  if (resy > 0)
-	    {
-	      pixel_size = POINT_TO_PIXEL (point_size, resy);
-	      ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
-	    }
-	  else
-	    {
-	      ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
-	    }
-	}
+	ASET (font, FONT_SIZE_INDEX, make_float (point_size / 10));
     }
 
-  if (FONT_ENTITY_P (font)
-      && EQ (AREF (font, FONT_TYPE_INDEX), Qx))
-    ASET (font, FONT_EXTRA_INDEX, f[XLFD_RESY_INDEX]);
+  if (FONT_ENTITY_P (font))
+    {
+      if (EQ (AREF (font, FONT_TYPE_INDEX), Qx))
+	ASET (font, FONT_EXTRA_INDEX, f[XLFD_RESY_INDEX]);
+    }
+  else if (resy >= 0)
+    font_put_extra (font, QCdpi, make_number (resy), merge);
 
   return (avgwidth > 0 ? 2 : resy == 0);
 }
@@ -930,7 +993,7 @@
     {
       i = XINT (val);
       if (i > 0)
-	len += sprintf (work, "%d", i) + 1;
+	len += sprintf (work, "%d-*", i) + 1;
       else 			/* i == 0 */
 	len += sprintf (work, "%d-*", pixel_size) + 1;
       pixel_point = work;
@@ -972,8 +1035,8 @@
 }
 
 /* Parse NAME (null terminated) as Fonconfig's name format and store
-   information in FONT (font-spec or font-entity).  See
-   font_parse_name for more detail.  */
+   information in FONT (font-spec or font-entity).  If NAME is
+   successfully parsed, return 0.  Otherwise return -1.  */
 
 int
 font_parse_fcname (name, font, merge)
@@ -986,6 +1049,8 @@
   double point_size = 0;
   int pixel_size = 0;
   Lisp_Object extra = AREF (font, FONT_EXTRA_INDEX);
+  int len = strlen (name);
+  char *copy;
 
   /* It is assured that (name[0] && name[0] != '-').  */
   if (name[0] == ':')
@@ -1009,57 +1074,114 @@
       if (! merge || NILP (AREF (font, FONT_FAMILY_INDEX)))
 	ASET (font, FONT_FAMILY_INDEX, family);
     }
+
+  len -= p0 - name;
+  copy = alloca (len + 1);
+  if (! copy)
+    return -1;
+  name = copy;
+  
+  /* Now parse ":KEY=VAL" patterns.  Store known keys and values in
+     extra, copy unknown ones to COPY.  */
   while (*p0)
     {
       Lisp_Object key, val;
       enum font_property_index prop;
 
-      p1 = index (name, '=');
-      if (! p1)
-	return -1;
-      if (memcmp (p0 + 1, "pixelsize=", 10) == 0)
-	prop = FONT_SIZE_INDEX;
-      else
+      for (p1 = p0 + 1; islower (*p1); p1++);
+      if (*p1 != '=')
 	{
-	  key = intern_font_field (p0, p1 - p0);
-	  prop = check_font_prop_name (key);
-	}
-      p0 = p1 + 1;
-      for (p1 = p0; *p1 && *p1 != ':'; p1++);
-      if (prop == FONT_SIZE_INDEX)
-	{
-	  pixel_size = atoi (p0);
+	  /* Must be an enumerated value.  */
+	  val = intern_font_field (p0 + 1, p1 - p0 - 1);
+
+	  if (memcmp (p0 + 1, "light", 5) == 0
+	      || memcmp (p0 + 1, "medium", 6) == 0
+	      || memcmp (p0 + 1, "demibold", 8) == 0
+	      || memcmp (p0 + 1, "bold", 4) == 0
+	      || memcmp (p0 + 1, "black", 5) == 0)
+	    {
+	      if (! merge || NILP (AREF (font, FONT_WEIGHT_INDEX)))
+		ASET (font, FONT_WEIGHT_INDEX,
+		      prop_name_to_numeric (FONT_WEIGHT_INDEX, val));
+	    }
+	  else if (memcmp (p0 + 1, "roman", 5) == 0
+		   || memcmp (p0 + 1, "italic", 6) == 0
+		   || memcmp (p0 + 1, "oblique", 7) == 0)
+	    {
+	      if (! merge || NILP (AREF (font, FONT_SLANT_INDEX)))
+		ASET (font, FONT_SLANT_INDEX,
+		      prop_name_to_numeric (FONT_SLANT_INDEX, val));
+	    }
+	  else if (memcmp (p0 + 1, "charcell", 8) == 0
+		   || memcmp (p0 + 1, "mono", 4) == 0
+		   || memcmp (p0 + 1, "proportional", 12) == 0)
+	    {
+	      font_put_extra (font, QCspacing,
+			      p0[1] == 'c' ? make_number (FONT_SPACING_CHARCELL)
+			      : p0[1] == 'm' ? make_number (FONT_SPACING_MONO)
+			      : make_number (FONT_SPACING_PROPORTIONAL),
+			      merge);
+	    }
+	  else
+	    {
+	      /* unknown key */
+	      bcopy (p0, copy, p1 - p0);
+	      copy += p1 - p0;
+	    }
 	}
       else
 	{
-	  val = intern_font_field (p0, p1 - p0);
-	  if (prop < FONT_EXTRA_INDEX)
+	  if (memcmp (p0 + 1, "pixelsize=", 10) == 0)
+	    prop = FONT_SIZE_INDEX;
+	  else
+	    {
+	      key = intern_font_field (p0, p1 - p0);
+	      prop = check_font_prop_name (key);
+	    }
+	  p0 = p1 + 1;
+	  for (p1 = p0; *p1 && *p1 != ':'; p1++);
+	  if (prop == FONT_SIZE_INDEX)
+	    {
+	      pixel_size = atoi (p0);
+	    }
+	  else if (prop < FONT_EXTRA_INDEX)
 	    {
 	      if (! merge || NILP (AREF (font, prop)))
 		{
-		  val = font_property_table[prop].validater (prop, val);
+		  val = intern_font_field (p0, p1 - p0);
+		  if (prop >= FONT_WEIGHT_INDEX && prop <= FONT_WIDTH_INDEX)
+		    val = font_property_table[prop].validater (prop, val);
 		  if (! EQ (val, Qerror))
 		    ASET (font, prop, val);
 		}
 	    }
+	  else if (EQ (key, QCdpi))
+	    {
+	      if (INTEGERP (val))
+		font_put_extra (font, key, val, merge);
+	    }
 	  else
 	    {
-	      if (! merge || NILP (Fplist_get (extra, key)))
-		extra = Fplist_put (extra, key, val);
+	      /* unknown key */
+	      bcopy (p0, copy, p1 - p0);
+	      copy += p1 - p0;
 	    }
 	}
       p0 = p1;
     }
-  ASET (font, FONT_EXTRA_INDEX, extra);
+
   if (! merge || NILP (AREF (font, FONT_SIZE_INDEX)))
     {
-      if (point_size > 0)
-	ASET (font, FONT_SIZE_INDEX, make_float (point_size));
-      else if (pixel_size > 0)
+      if (pixel_size > 0)
 	ASET (font, FONT_SIZE_INDEX, make_number (pixel_size));
+      else if (point_size > 0)
+	ASET (font, FONT_SIZE_INDEX, make_float (point_size));
     }
-
-  return (NILP (AREF (font, FONT_SIZE_INDEX)) ? 1 : 2);
+  if (name < copy)
+    font_put_extra (font, QCname, make_unibyte_string (name, copy - name),
+		    merge);
+
+  return 0;
 }
 
 /* Store fontconfig's font name of FONT (font-spec or font-entity) in
@@ -1135,8 +1257,7 @@
 
 /* Parse NAME (null terminated) and store information in FONT
    (font-spec or font-entity).  If NAME is successfully parsed, return
-   2 (size is specified), 1 (size is not specified), or 0 (size is not
-   specified but resolution is specified).  Otherwise return -1.
+   a non-negative value.  Otherwise return -1.
 
    If NAME is XLFD and FONT is a font-entity, store
    RESY-SPACING-AVWIDTH information as a symbol in FONT_EXTRA_INDEX.
@@ -1734,7 +1855,7 @@
 
 /* Font sorting */
 
-static unsigned font_score P_ ((Lisp_Object, Lisp_Object));
+static unsigned font_score P_ ((Lisp_Object, Lisp_Object *));
 static int font_compare P_ ((const void *, const void *));
 static Lisp_Object font_sort_entites P_ ((Lisp_Object, Lisp_Object,
 					  Lisp_Object, Lisp_Object));
@@ -1753,43 +1874,45 @@
    property in a score.  */
 static int sort_shift_bits[FONT_SIZE_INDEX + 1];
 
-/* Score font-entity ENTITY against font-spec SPEC.  The return value
-   indicates how different ENTITY is compared with SPEC.  */
+/* Score font-entity ENTITY against properties of font-spec SPEC_PROP.
+   The return value indicates how different ENTITY is compared with
+   SPEC_PROP.  */
 
 static unsigned
-font_score (entity, spec)
-     Lisp_Object entity, spec;
+font_score (entity, spec_prop)
+     Lisp_Object entity, *spec_prop;
 {
   unsigned score = 0;
   int i;
-  /* Score atomic fields.  Maximum difference is 1. */
+  /* Score four atomic fields.  Maximum difference is 1. */
   for (i = FONT_FOUNDRY_INDEX; i <= FONT_REGISTRY_INDEX; i++)
-    {
-      Lisp_Object val = AREF (spec, i);
-
-      if (! NILP (val)
-	  && ! EQ (val, AREF (entity, i)))
-	score |= 1 << sort_shift_bits[i];
-    }
-
-  /* Score numeric fields.  Maximum difference is 127. */
+    if (! NILP (spec_prop[i])
+	&& ! EQ (spec_prop[i], AREF (entity, i)))
+      score |= 1 << sort_shift_bits[i];
+
+  /* Score four numeric fields.  Maximum difference is 127. */
   for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
     {
-      Lisp_Object spec_val = AREF (spec, i);
       Lisp_Object entity_val = AREF (entity, i);
 
-      if (! NILP (spec_val) && ! EQ (spec_val, entity_val))
+      if (! NILP (spec_prop[i]) && ! EQ (spec_prop[i], entity_val))
 	{
 	  if (! INTEGERP (entity_val))
 	    score |= 127 << sort_shift_bits[i];
-	  else if (i < FONT_SIZE_INDEX
-		   || XINT (entity_val) != 0)
+	  else
 	    {
-	      int diff = XINT (entity_val) - XINT (spec_val);
+	      int diff = XINT (entity_val) - XINT (spec_prop[i]);
 
 	      if (diff < 0)
 		diff = - diff;
-	      score |= min (diff, 127) << sort_shift_bits[i];
+	      if (i == FONT_SIZE_INDEX)
+		{
+		  if (XINT (entity_val) > 0
+		      && diff > FONT_PIXEL_SIZE_QUANTUM)
+		    score |= min (diff, 127) << sort_shift_bits[i];
+		}
+	      else
+		score |= min (diff, 127) << sort_shift_bits[i];
 	    }
 	}
     }
@@ -1819,58 +1942,46 @@
 
 /* Sort font-entities in vector VEC by closeness to font-spec PREFER.
    If PREFER specifies a point-size, calculate the corresponding
-   pixel-size from the Y-resolution of FRAME before sorting.  If SPEC
-   is not nil, it is a font-spec to get the font-entities in VEC.  */
+   pixel-size from QCdpi property of PREFER or from the Y-resolution
+   of FRAME before sorting.  If SPEC is not nil, it is a font-spec to
+   get the font-entities in VEC.  */
 
 static Lisp_Object
 font_sort_entites (vec, prefer, frame, spec)
      Lisp_Object vec, prefer, frame, spec;
 {
-  Lisp_Object size;
+  Lisp_Object prefer_prop[FONT_SPEC_MAX];
   int len, i;
   struct font_sort_data *data;
-  int prefer_is_copy = 0;
   USE_SAFE_ALLOCA;
 
   len = ASIZE (vec);
   if (len <= 1)
     return vec;
 
-  size = AREF (spec, FONT_SIZE_INDEX);
-  if (FLOATP (size))
-    {
-      double point_size = XFLOAT_DATA (size) * 10;
-      int pixel_size =  POINT_TO_PIXEL (point_size, XFRAME (frame)->resy);
-
-      prefer = Fcopy_sequence (prefer);
-      ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
-      prefer_is_copy = 1;
-    }
+  for (i = FONT_FOUNDRY_INDEX; i <= FONT_SIZE_INDEX; i++)
+    prefer_prop[i] = AREF (prefer, i);
 
   if (! NILP (spec))
     {
       /* As it is assured that all fonts in VEC match with SPEC, we
 	 should ignore properties specified in SPEC.  So, set the
-	 corresponding properties in PREFER nil. */
+	 corresponding properties in PREFER_PROP to nil. */
       for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
-	if (! NILP (AREF (spec, i)) && ! NILP (AREF (prefer, i)))
-	  break;
-      if (i <= FONT_SIZE_INDEX)
-	{
-	  if (! prefer_is_copy)
-	    prefer = Fcopy_sequence (prefer);
-	  for (; i <= FONT_SIZE_INDEX; i++)
-	    if (! NILP (AREF (spec, i)) && ! NILP (AREF (prefer, i)))
-	      ASET (prefer, i, Qnil);
-	}
+	if (! NILP (AREF (spec, i)))
+	  prefer_prop[i++] = Qnil;
     }
 
+  if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
+    prefer_prop[FONT_SIZE_INDEX]
+      = make_number (font_pixel_size (XFRAME (frame), prefer));
+
   /* Scoring and sorting.  */
   SAFE_ALLOCA (data, struct font_sort_data *, (sizeof *data) * len);
   for (i = 0; i < len; i++)
     {
       data[i].entity = AREF (vec, i);
-      data[i].score = font_score (data[i].entity, prefer);
+      data[i].score = font_score (data[i].entity, prefer_prop);
     }
   qsort (data, len, sizeof *data, font_compare);
   for (i = 0; i < len; i++)
@@ -2004,7 +2115,7 @@
     }
   size = AREF (spec, FONT_SIZE_INDEX);
   if (FLOATP (size))
-    ASET (spec, FONT_SIZE_INDEX, POINT_TO_PIXEL (size * 10, f->resy));
+    ASET (spec, FONT_SIZE_INDEX, make_number (font_pixel_size (f, spec)));
 
   xassert (ASIZE (spec) == FONT_SPEC_MAX);
   ftype = AREF (spec, FONT_TYPE_INDEX);
@@ -2238,7 +2349,7 @@
   if (ASIZE (entities) > 1)
     {
       Lisp_Object prefer = scratch_font_prefer, val;
-      int size;
+      double pt;
 
       ASET (prefer, FONT_WEIGHT_INDEX,
 	    font_prop_validate_style (FONT_WEIGHT_INDEX,
@@ -2249,9 +2360,8 @@
       ASET (prefer, FONT_WIDTH_INDEX,
 	    font_prop_validate_style (FONT_WIDTH_INDEX,
 				      lface[LFACE_SWIDTH_INDEX]));
-      val = lface[LFACE_HEIGHT_INDEX];
-      size = POINT_TO_PIXEL (XINT (val), f->resy);
-      ASET (prefer, FONT_SIZE_INDEX, make_number (size));
+      pt = XINT (lface[LFACE_HEIGHT_INDEX]);
+      ASET (prefer, FONT_SIZE_INDEX, make_float (pt / 10));
 
       font_sort_entites (entities, prefer, frame, spec);
     }
@@ -2265,9 +2375,11 @@
      Lisp_Object *lface;
      Lisp_Object entity;
 {
-  int pt = XINT (lface[LFACE_HEIGHT_INDEX]);
-  int size = POINT_TO_PIXEL (pt, f->resy);
-
+  double pt = XINT (lface[LFACE_HEIGHT_INDEX]);
+  int size;
+
+  pt /= 10;
+  size = POINT_TO_PIXEL (pt, f->resy);
   return font_open_entity (f, entity, size);
 }
 
@@ -2356,7 +2468,7 @@
     pixel_size = XINT (size);
   else				/* FLOATP (size) */
     {
-      double pt = XFLOAT_DATA (size) * 10;
+      double pt = XFLOAT_DATA (size);
 
       pixel_size = POINT_TO_PIXEL (pt, f->resy);
       size = make_number (pixel_size);
@@ -2364,10 +2476,12 @@
     }
   if (pixel_size == 0)
     {
-      pixel_size = POINT_TO_PIXEL (120.0, f->resy);
+      pixel_size = POINT_TO_PIXEL (12.0, f->resy);
       size = make_number (pixel_size);
     }
   ASET (prefer, FONT_SIZE_INDEX, size);
+  if (NILP (AREF (spec, FONT_REGISTRY_INDEX)))
+    ASET (spec, FONT_REGISTRY_INDEX, Qiso8859_1);
 
   entities = Flist_fonts (spec, frame, make_number (1), prefer);
   return (NILP (entities)
@@ -2451,7 +2565,7 @@
      Lisp_Object *args;
 {
   Lisp_Object spec = Fmake_vector (make_number (FONT_SPEC_MAX), Qnil);
-  Lisp_Object extra = Qnil;
+  Lisp_Object extra = Qnil, name = Qnil;
   int i;
 
   for (i = 0; i < nargs; i += 2)
@@ -2465,11 +2579,14 @@
       else
 	{
 	  if (EQ (key, QCname))
-	    font_parse_name ((char *) SDATA (val), spec, 0);
-	  extra = Fcons (Fcons (key, val), extra);
+	    name = val;
+	  else
+	    extra = Fcons (Fcons (key, val), extra);
 	}
     }  
   ASET (spec, FONT_EXTRA_INDEX, extra);
+  if (STRINGP (name))
+    font_parse_name (SDATA (name), spec, 0);
   return spec;
 }
 
@@ -3020,6 +3137,8 @@
   DEFSYM (QCfoundry, ":foundry");
   DEFSYM (QCadstyle, ":adstyle");
   DEFSYM (QCregistry, ":registry");
+  DEFSYM (QCspacing, ":spacing");
+  DEFSYM (QCdpi, ":dpi");
   DEFSYM (QCextra, ":extra");
 
   staticpro (&null_string);