]> git.eshelyaron.com Git - emacs.git/commitdiff
(ftfont_pattern_entity): Argument FRAME removed. Make
authorKenichi Handa <handa@m17n.org>
Wed, 14 May 2008 01:28:01 +0000 (01:28 +0000)
committerKenichi Handa <handa@m17n.org>
Wed, 14 May 2008 01:28:01 +0000 (01:28 +0000)
a font-entity by font_make_entity.  Use font_intern_prop instead
of intern_downcase.  Use FONT_SET_STYLE to set a style-related
font property.  If a font is scalable, set avgwidth property to 0.
Set font-entity property by font_put_extra.
(ftfont_list_generic_family): Argument SPEC and REGISTRY removed.
(ffont_driver): Adjusted for the change of struct font_driver.
(ftfont_spec_pattern): New function.
(ftfont_list): Return a list, not vector.
(ftfont_match): Use ftfont_spec_pattern to get a pattern.
(ftfont_list_family): Don't downcase names.
(ftfont_free_entity): Deleted.
(ftfont_open): Return a font-ojbect.  Adjusted for the change of
struct font.  Get underline_thickness and underline_position from
font property.  Don't update dpyinfo->smallest_font_height and
dpyinfo->smallest_char_width.
(ftfont_close): Don't free `struct font'.
(ftfont_has_char): Adjusted for the format change of font-entity.
(ftfont_encode_char, ftfont_text_extents): Likewise.

src/ftfont.c

index a3ce243f369b2b04452a8341458ae2ad662b23d7..7360742231db78e4e680d4a9f3eb20d01ecc420d 100644 (file)
@@ -71,10 +71,8 @@ struct ftfont_info
 };
 
 static int ftfont_build_basic_charsets P_ ((void));
-static Lisp_Object ftfont_pattern_entity P_ ((FcPattern *,
-                                             Lisp_Object, Lisp_Object));
-static Lisp_Object ftfont_list_generic_family P_ ((Lisp_Object, Lisp_Object,
-                                                  Lisp_Object));
+static Lisp_Object ftfont_pattern_entity P_ ((FcPattern *, Lisp_Object));
+static Lisp_Object ftfont_list_generic_family P_ ((Lisp_Object));
 Lisp_Object ftfont_font_format P_ ((FcPattern *));
 
 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
@@ -99,10 +97,12 @@ ftfont_build_basic_charsets ()
   return 0;
 }
 
+extern Lisp_Object Qc, Qm, Qp, Qd;
+
 static Lisp_Object
-ftfont_pattern_entity (p, frame, registry)
+ftfont_pattern_entity (p, registry)
      FcPattern *p;
-     Lisp_Object frame, registry;
+     Lisp_Object registry;
 {
   Lisp_Object entity;
   FcChar8 *file, *fontformat;
@@ -110,6 +110,7 @@ ftfont_pattern_entity (p, frame, registry)
   FcChar8 *str;
   int numeric;
   double dbl;
+  FcBool b;
 
   if (FcPatternGetString (p, FC_FILE, 0, &file) != FcResultMatch)
     return Qnil;
@@ -120,38 +121,48 @@ ftfont_pattern_entity (p, frame, registry)
 #endif /* FC_FONTFORMAT */
     fontformat = NULL;
 
-  entity = Fmake_vector (make_number (FONT_ENTITY_MAX), null_string);
+  entity = font_make_entity ();
 
   ASET (entity, FONT_TYPE_INDEX, Qfreetype);
   ASET (entity, FONT_REGISTRY_INDEX, registry);
-  ASET (entity, FONT_FRAME_INDEX, frame);
-  ASET (entity, FONT_OBJLIST_INDEX, Qnil);
 
   if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
-    ASET (entity, FONT_FOUNDRY_INDEX, intern_downcase (str, strlen (str)));
+    ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (str, strlen (str)));
   if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
-    ASET (entity, FONT_FAMILY_INDEX, intern_downcase (str, strlen (str)));
+    ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (str, strlen (str)));
   if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
     {
-      if (numeric == FC_WEIGHT_REGULAR)
-       numeric = 100;
-      ASET (entity, FONT_WEIGHT_INDEX, make_number (numeric));
+      if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
+       numeric = FC_WEIGHT_MEDIUM;
+      FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
     }
   if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
-    ASET (entity, FONT_SLANT_INDEX, make_number (numeric + 100));
+    {
+      numeric += 100;
+      FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
+    }
   if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
-    ASET (entity, FONT_WIDTH_INDEX, make_number (numeric));
+    {
+      FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
+    }
   if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
     ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
   else
     ASET (entity, FONT_SIZE_INDEX, make_number (0));
+  if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
+    ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
+  if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
+    {
+      int dpi = dbl;
+      ASET (entity, FONT_DPI_INDEX, make_number (dpi));
+    }
+  if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
+      && b == FcTrue)
+    ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
 
-  if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) != FcResultMatch)
-    numeric = -1;
   file = FcStrCopy (file);
   if (! file)
     return Qnil;
-
   p = FcPatternCreate ();
   if (! p)
     return Qnil;
@@ -163,24 +174,28 @@ ftfont_pattern_entity (p, frame, registry)
       || (fontformat
          && FcPatternAddString (p, FC_FONTFORMAT, fontformat) == FcFalse)
 #endif /* FC_FONTFORMAT */
-      || (numeric >= 0
-         && FcPatternAddInteger (p, FC_SPACING, numeric) == FcFalse))
+      )
     {
       FcPatternDestroy (p);
       return Qnil;
     }
-  ASET (entity, FONT_EXTRA_INDEX, make_save_value (p, 0));
+  font_put_extra (entity, QCfont_entity, make_save_value (p, 0));
   return entity;
 }
 
+
 static Lisp_Object ftfont_generic_family_list;
 
 static Lisp_Object
-ftfont_list_generic_family (spec, frame, registry)
-     Lisp_Object spec, frame, registry;
+ftfont_list_generic_family (family)
+     Lisp_Object family;
 {
-  Lisp_Object family = AREF (spec, FONT_FAMILY_INDEX);
   Lisp_Object slot, list, val;
+  FcObjectSet *objset = NULL;
+  FcPattern *pattern = NULL, *pat = NULL;
+  FcFontSet *fontset = NULL;
+  FcChar8 *fam;
+  int i, j;
 
   if (EQ (family, Qmono))
     family = Qmonospace;
@@ -188,86 +203,53 @@ ftfont_list_generic_family (spec, frame, registry)
     family = Qsans_serif;
   slot = assq_no_quit (family, ftfont_generic_family_list);
   if (! CONSP (slot))
-    return null_vector;
+    return Qnil;
   list = XCDR (slot);
-  if (EQ (list, Qt))
+  if (! EQ (list, Qt))
+    return list;
+
+  objset = FcObjectSetBuild (FC_FAMILY, NULL);
+  if (! objset)
+    goto err;
+  pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString,
+                           SYMBOL_FcChar8 (family), (char *) 0);
+  if (! pattern)
+    goto err;
+  pat = FcPatternCreate ();
+  if (! pat)
+    goto err;
+  FcConfigSubstitute (NULL, pattern, FcMatchPattern);
+  for (i = 0, list = Qnil;
+       FcPatternGetString (pattern, FC_FAMILY, i, &fam) == FcResultMatch;
+       i++)
     {
-      /* Not yet listed.  */
-      FcObjectSet *objset = NULL;
-      FcPattern *pattern = NULL, *pat = NULL;
-      FcFontSet *fontset = NULL;
-      FcChar8 *fam;
-      int i, j;
-
-      objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
-                                FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
-                                FC_CHARSET, FC_FILE,
-#ifdef FC_FONTFORMAT
-                                FC_FONTFORMAT,
-#endif /* FC_FONTFORMAT */
-                                NULL);
-      if (! objset)
-       goto err;
-      pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString,
-                               SYMBOL_FcChar8 (family), (char *) 0);
-      if (! pattern)
+      if (strcmp ((char *) fam, (char *) SYMBOL_FcChar8 (family)) == 0)
+       continue;
+      if (! FcPatternAddString (pat, FC_FAMILY, fam))
        goto err;
-      pat = FcPatternCreate ();
-      if (! pat)
+      fontset = FcFontList (NULL, pat, objset);
+      if (! fontset)
        goto err;
-      FcConfigSubstitute (NULL, pattern, FcMatchPattern);
-      for (i = 0, val = Qnil;
-          FcPatternGetString (pattern, FC_FAMILY, i, &fam) == FcResultMatch;
-          i++)
-       {
-         if (strcmp ((char *) fam, (char *) SYMBOL_FcChar8 (family)) == 0)
-           continue;
-         if (! FcPatternAddString (pat, FC_FAMILY, fam))
-           goto err;
-         fontset = FcFontList (NULL, pat, objset);
-         if (! fontset)
-           goto err;
-         /* Here we build the list in reverse order so that the last
-            loop in this function build a list in the correct
-            order.  */
-         for (j = 0; j < fontset->nfont; j++)
-           {
-             Lisp_Object entity;
-
-             entity = ftfont_pattern_entity (fontset->fonts[j],
-                                             frame, registry);
-             if (! NILP (entity))
-               val = Fcons (entity, val);
-           }
-         FcFontSetDestroy (fontset);
-         fontset = NULL;
-         FcPatternDel (pat, FC_FAMILY);
-       }
-      list = val;
-      XSETCDR (slot, list);
-    err:
-      if (pat) FcPatternDestroy (pat);
-      if (pattern) FcPatternDestroy (pattern);
-      if (fontset) FcFontSetDestroy (fontset);
-      if (objset) FcObjectSetDestroy (objset);
-      if (EQ (list, Qt))
-       return Qnil;
+      if (fontset->nfont > 0)
+       list = Fcons (intern ((char *) fam), list);
+      FcFontSetDestroy (fontset);
+      fontset = NULL;
+      FcPatternDel (pat, FC_FAMILY);
     }
-  ASET (spec, FONT_FAMILY_INDEX, Qnil);
-  for (val = Qnil; CONSP (list); list = XCDR (list))
-    if (font_match_p (spec, XCAR (list)))
-      val = Fcons (XCAR (list), val);
-  ASET (spec, FONT_FAMILY_INDEX, family);
-  return Fvconcat (1, &val);
+  XSETCDR (slot, list);
+ err:
+  if (pat) FcPatternDestroy (pat);
+  if (pattern) FcPatternDestroy (pattern);
+  if (fontset) FcFontSetDestroy (fontset);
+  if (objset) FcObjectSetDestroy (objset);
+  return list;
 }
 
-
 static Lisp_Object ftfont_get_cache P_ ((FRAME_PTR));
 static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
 static Lisp_Object ftfont_match P_ ((Lisp_Object, Lisp_Object));
 static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
-static void ftfont_free_entity P_ ((Lisp_Object));
-static struct font *ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
+static Lisp_Object ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
 static void ftfont_close P_ ((FRAME_PTR, struct font *));
 static int ftfont_has_char P_ ((Lisp_Object, int));
 static unsigned ftfont_encode_char P_ ((struct font *, int));
@@ -282,11 +264,12 @@ static Lisp_Object ftfont_shape P_ ((Lisp_Object));
 struct font_driver ftfont_driver =
   {
     0,                         /* Qfreetype */
+    0,                         /* case insensitive */
     ftfont_get_cache,
     ftfont_list,
     ftfont_match,
     ftfont_list_family,
-    ftfont_free_entity,
+    NULL,
     ftfont_open,
     ftfont_close,
     /* We can't draw a text without device dependent functions.  */
@@ -409,41 +392,41 @@ ftfont_get_open_type_spec (Lisp_Object otf_spec)
   return spec;
 }
 
-static Lisp_Object
-ftfont_list (frame, spec)
-     Lisp_Object frame, spec;
+static FcPattern *
+ftfont_spec_pattern (spec, otlayout, otspec)
+     Lisp_Object spec;
+     char *otlayout;
+     struct OpenTypeSpec **otspec;
 {
   Lisp_Object val, tmp, extra;
   int i;
   FcPattern *pattern = NULL;
   FcCharSet *charset = NULL;
   FcLangSet *langset = NULL;
-  FcFontSet *fontset = NULL;
-  FcObjectSet *objset = NULL;
-  Lisp_Object script;
-  Lisp_Object registry = Qunicode_bmp;
-  struct OpenTypeSpec *otspec= NULL;
-  int weight = 0;
-  double dpi = -1;
+  int n;
+  int dpi = -1;
   int spacing = -1;
   int scalable = -1;
-  char otlayout[15];           /* For "otlayout:XXXX" */
-  
-  val = null_vector;
-
-  if (! fc_initialized)
-    {
-      FcInit ();
-      fc_initialized = 1;
-    }
+  Lisp_Object name = Qnil;
+  Lisp_Object script = Qnil;
+  Lisp_Object registry = Qunicode_bmp;
 
   if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX))
-      && ! EQ (AREF (spec, FONT_ADSTYLE_INDEX), null_string))
-    return val;
-  if (! NILP (AREF (spec, FONT_SLANT_INDEX))
-      && XINT (AREF (spec, FONT_SLANT_INDEX)) < 100)
+      && SBYTES (SYMBOL_NAME (AREF (spec, FONT_ADSTYLE_INDEX))) > 0)
+    /* Fontconfig doesn't support adstyle property.  */
+    return NULL;
+  if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
+      && n < 100)
     /* Fontconfig doesn't support reverse-italic/obligue.  */
-    return val;
+    return NULL;
+
+  if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
+    dpi = XINT (AREF (spec, FONT_DPI_INDEX));
+  if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
+    spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
+  if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
+      && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
+    scalable = 1;
 
   if (! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
     {
@@ -452,34 +435,27 @@ ftfont_list (frame, spec)
        {
          if (! cs_iso8859_1
              && ftfont_build_basic_charsets () < 0)
-           return Qnil;
+           return NULL;
          charset = cs_iso8859_1;
        }
       else if (! EQ (registry, Qiso10646_1)
               && ! EQ (registry, Qunicode_bmp)
               && ! EQ (registry, Qunicode_sip))
-       return val;
+       return NULL;
     }
 
   otlayout[0] = '\0';
-  script = Qnil;
   for (extra = AREF (spec, FONT_EXTRA_INDEX);
        CONSP (extra); extra = XCDR (extra))
     {
       Lisp_Object key, val;
 
-      tmp = XCAR (extra);
-      key = XCAR (tmp), val = XCDR (tmp);
-      if (EQ (key, QCotf))
-       {
-         otspec = ftfont_get_open_type_spec (val);
-         if (! otspec)
-           return null_vector;
-         strcat (otlayout, "otlayout:");
-         OTF_TAG_STR (otspec->script_tag, otlayout + 9);
-         script = otspec->script;
-       }
-      else if (EQ (key, QClanguage))
+      key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
+      if (EQ (key, QCdpi))
+       dpi = XINT (val);
+      else if (EQ (key, QCfc_unknown_spec))
+       name = val;
+      else if (EQ (key, QClang))
        {
          langset = FcLangSetCreate ();
          if (! langset)
@@ -495,12 +471,19 @@ ftfont_list (frame, spec)
                  && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
                goto err;
        }
+      else if (EQ (key, QCname))
+       name = val;
+      else if (EQ (key, QCotf))
+       {
+         *otspec = ftfont_get_open_type_spec (val);
+         if (! *otspec)
+           return NULL;
+         strcat (otlayout, "otlayout:");
+         OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
+         script = (*otspec)->script;
+       }
       else if (EQ (key, QCscript))
        script = val;
-      else if (EQ (key, QCdpi))
-       dpi = XINT (val);
-      else if (EQ (key, QCspacing))
-       spacing = XINT (val);
       else if (EQ (key, QCscalable))
        scalable = ! NILP (val);
     }
@@ -521,32 +504,15 @@ ftfont_list (frame, spec)
        }
     }
 
-  pattern = FcPatternCreate ();
+  pattern = NILP (name) ? FcPatternCreate () : FcNameParse (SDATA (name));
   if (! pattern)
     goto err;
+  FcPatternDel (pattern, FC_SIZE);
+  FcPatternDel (pattern, FC_PIXEL_SIZE);
   tmp = AREF (spec, FONT_FOUNDRY_INDEX);
-  if (SYMBOLP (tmp) && ! NILP (tmp)
+  if (! NILP (tmp)
       && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
     goto err;
-  tmp = AREF (spec, FONT_FAMILY_INDEX);
-  if (SYMBOLP (tmp) && ! NILP (tmp)
-      && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
-    goto err;
-  /* Emacs conventionally doesn't distinguish normal, regular, and
-     medium weight, but fontconfig does.  So, we can't restrict font
-     listing by weight.  We check it after getting a list.  */
-  tmp = AREF (spec, FONT_WEIGHT_INDEX);
-  if (INTEGERP (tmp))
-    weight = XINT (tmp);
-  tmp = AREF (spec, FONT_SLANT_INDEX);
-  if (INTEGERP (tmp)
-      && ! FcPatternAddInteger (pattern, FC_SLANT, XINT (tmp) - 100))
-    goto err;
-  tmp = AREF (spec, FONT_WIDTH_INDEX);
-  if (INTEGERP (tmp)
-      && ! FcPatternAddInteger (pattern, FC_WIDTH, XINT (tmp)))
-    goto err;
-
   if (charset
       && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
     goto err;
@@ -562,65 +528,100 @@ ftfont_list (frame, spec)
   if (scalable >= 0
       && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
     goto err;
+  goto finish;
+
+ err:
+  /* We come here because of unexpected error in fontconfig API call
+     (usually insufficient memory).  */
+  if (pattern)
+    {
+      FcPatternDestroy (pattern);
+      pattern = NULL;
+    }
+  if (*otspec)
+    {
+      if ((*otspec)->nfeatures[0] > 0)
+       free ((*otspec)->features[0]);
+      if ((*otspec)->nfeatures[1] > 0)
+       free ((*otspec)->features[1]);
+      free (*otspec);
+      *otspec = NULL;
+    }
 
+ finish:
+  if (charset && charset != cs_iso8859_1) FcCharSetDestroy (charset);
+  if (langset) FcLangSetDestroy (langset);
+  return pattern;
+}
+
+static Lisp_Object
+ftfont_list (frame, spec)
+     Lisp_Object frame, spec;
+{
+  Lisp_Object val, tmp, registry, family, family_list;
+  int i;
+  FcPattern *pattern;
+  FcFontSet *fontset = NULL;
+  FcObjectSet *objset = NULL;
+  double pixel_size = 0;
+  int weight = -1, slant = -1, width = -1;
+  double dpi = -1;
+  int spacing = -1;
+  int scalable = -1;
+  char otlayout[15];           /* For "otlayout:XXXX" */
+  struct OpenTypeSpec *otspec = NULL;
+  
+  if (! fc_initialized)
+    {
+      FcInit ();
+      fc_initialized = 1;
+    }
+
+  pattern = ftfont_spec_pattern (spec, otlayout, &otspec);
+  if (! pattern)
+    return Qnil;
   objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
-                            FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
+                            FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
                             FC_CHARSET, FC_FILE,
+#ifdef FC_CAPABILITY
+                            FC_CAPABILITY,
+#endif /* FC_CAPABILITY */
 #ifdef FC_FONTFORMAT
                             FC_FONTFORMAT,
 #endif /* FC_FONTFORMAT */
                             NULL);
   if (! objset)
     goto err;
-  if (otlayout[0])
+
+  registry = AREF (spec, FONT_REGISTRY_INDEX);
+  family = AREF (spec, FONT_FAMILY_INDEX);
+  if (NILP (family))
+    family_list = Fcons (Qnil, Qnil);
+  else
     {
-#ifdef FC_CAPABILITY
-      if (! FcObjectSetAdd (objset, FC_CAPABILITY))
-       goto err;
-#else  /* not FC_CAPABILITY */
-      goto finish;
-#endif /* not FC_CAPABILITY */
+      family_list = ftfont_list_generic_family (family);
+      if (NILP (family_list))
+       family_list = Fcons (family, Qnil);
     }
 
-  fontset = FcFontList (NULL, pattern, objset);
-  if (! fontset)
-    goto err;
-
-  if (fontset->nfont > 0)
+  for (val = Qnil; CONSP (family_list); family_list = XCDR (family_list))
     {
-      double pixel_size;
-
-      if (NILP (AREF (spec, FONT_SIZE_INDEX)))
-       pixel_size = 0;
-      else
-       pixel_size = XINT (AREF (spec, FONT_SIZE_INDEX));
-
-      for (i = 0, val = Qnil; i < fontset->nfont; i++)
+      family = XCAR (family_list);
+      if (! NILP (family))
+       {
+         FcPatternDel (pattern, FC_FAMILY);
+         if (! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family)))
+           goto err;
+       }
+      fontset = FcFontList (NULL, pattern, objset);
+      if (! fontset)
+       goto err;
+      for (i = 0; i < fontset->nfont; i++)
        {
          Lisp_Object entity;
+         int n;
+         double dbl;
 
-         if (pixel_size > 0)
-           {
-             double this;
-
-             if (FcPatternGetDouble (fontset->fonts[i], FC_PIXEL_SIZE, 0,
-                                     &this) == FcResultMatch
-                 && ((this < pixel_size - FONT_PIXEL_SIZE_QUANTUM)
-                     || (this > pixel_size + FONT_PIXEL_SIZE_QUANTUM)))
-               continue;
-           }
-         if (weight > 0)
-           {
-             int this;
-
-             if (FcPatternGetInteger (fontset->fonts[i], FC_WEIGHT, 0,
-                                      &this) != FcResultMatch
-                 || (this != weight
-                     && (weight != 100
-                         || this < FC_WEIGHT_REGULAR
-                         || this > FC_WEIGHT_MEDIUM)))
-               continue;
-           }
 #ifdef FC_CAPABILITY
          if (otlayout[0])
            {
@@ -655,14 +656,13 @@ ftfont_list (frame, spec)
                continue;
            }
 #endif /* HAVE_LIBOTF */
-         entity = ftfont_pattern_entity (fontset->fonts[i], frame, registry);
+         entity = ftfont_pattern_entity (fontset->fonts[i], registry);
          if (! NILP (entity))
            val = Fcons (entity, val);
        }
-      val = Fvconcat (1, &val);
+      FcFontSetDestroy (fontset);
+      fontset = NULL;
     }
-  else if (! NILP (AREF (spec, FONT_FAMILY_INDEX)))
-    val = ftfont_list_generic_family (spec, frame, registry);
   goto finish;
 
  err:
@@ -671,19 +671,9 @@ ftfont_list (frame, spec)
   val = Qnil;
 
  finish:
-  if (charset && charset != cs_iso8859_1) FcCharSetDestroy (charset);
   if (objset) FcObjectSetDestroy (objset);
   if (fontset) FcFontSetDestroy (fontset);
-  if (langset) FcLangSetDestroy (langset);
   if (pattern) FcPatternDestroy (pattern);
-  if (otspec)
-    {
-      if (otspec->nfeatures[0] > 0)
-       free (otspec->features[0]);
-      if (otspec->nfeatures[1] > 0)
-       free (otspec->features[1]);
-      free (otspec);
-    }
   return val;
 }
 
@@ -692,8 +682,10 @@ ftfont_match (frame, spec)
      Lisp_Object frame, spec;
 {
   Lisp_Object extra, val, entity;
-  FcPattern *pattern = NULL, *match = NULL;
+  FcPattern *pattern, *match = NULL;
   FcResult result;
+  char otlayout[15];           /* For "otlayout:XXXX" */
+  struct OpenTypeSpec *otspec = NULL;
 
   if (! fc_initialized)
     {
@@ -701,35 +693,35 @@ ftfont_match (frame, spec)
       fc_initialized = 1;
     }
 
-  extra = AREF (spec, FONT_EXTRA_INDEX);
-  val = assq_no_quit (QCname, extra);
-  if (! CONSP (val) || ! STRINGP (XCDR (val)))
+  pattern = ftfont_spec_pattern (spec, otlayout, &otspec);
+  if (! pattern)
     return Qnil;
 
-  entity = Qnil;
-  pattern = FcNameParse (SDATA (XCDR (val)));
-  if (pattern)
+  if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
     {
-      if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
-       {
-         FcValue value;
+      FcValue value;
 
-         value.type = FcTypeDouble;
-         value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
-         FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
-       }
-      if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
+      value.type = FcTypeDouble;
+      value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
+      FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
+    }
+  if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
+    {
+      FcDefaultSubstitute (pattern);
+      match = FcFontMatch (NULL, pattern, &result);
+      if (match)
        {
-         FcDefaultSubstitute (pattern);
-         match = FcFontMatch (NULL, pattern, &result);
-         if (match)
-           {
-             entity = ftfont_pattern_entity (match, frame, Qunicode_bmp);
-             FcPatternDestroy (match);
-           }
+         entity = ftfont_pattern_entity (match, Qunicode_bmp);
+         FcPatternDestroy (match);
+         if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
+             && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
+                                    ftfont_generic_family_list))
+             && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
+                                     AREF (entity, FONT_FAMILY_INDEX))))
+           entity = Qnil;
        }
-      FcPatternDestroy (pattern);
     }
+  FcPatternDestroy (pattern);
 
   return entity;
 }
@@ -767,8 +759,7 @@ ftfont_list_family (frame)
       FcChar8 *str;
 
       if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
-       list = Fcons (intern_downcase ((char *) str, strlen ((char *) str)),
-                     list);
+       list = Fcons (intern ((char *) str), list);
     }
 
  finish:
@@ -780,17 +771,7 @@ ftfont_list_family (frame)
 }
 
 
-static void 
-ftfont_free_entity (entity)
-     Lisp_Object entity;
-{
-  Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
-  FcPattern *pattern = XSAVE_VALUE (val)->pointer;
-
-  FcPatternDestroy (pattern);
-}
-
-static struct font *
+static Lisp_Object
 ftfont_open (f, entity, pixel_size)
      FRAME_PTR f;
      Lisp_Object entity;
@@ -801,42 +782,45 @@ ftfont_open (f, entity, pixel_size)
   FT_Face ft_face;
   FT_Size ft_size;
   FT_UInt size;
-  Lisp_Object val;
+  Lisp_Object val, font_object;
   FcPattern *pattern;
-  FcChar8 *file;
+  FcChar8 *file = NULL, *fmt = NULL;
+  FcBool scalable;
   int spacing;
-  char *name;
-  int len;
+  char name[256];
+  int i, len;
+  int upEM;
 
-  val = AREF (entity, FONT_EXTRA_INDEX);
-  if (XTYPE (val) != Lisp_Misc
-      || XMISCTYPE (val) != Lisp_Misc_Save_Value)
-    return NULL;
+  val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+  if (! CONSP (val))
+    return Qnil;
+  val = XCDR (val);
   pattern = XSAVE_VALUE (val)->pointer;
   if (XSAVE_VALUE (val)->integer == 0)
     {
       /* We have not yet created FT_Face for this font.  */
       if (! ft_library
          && FT_Init_FreeType (&ft_library) != 0)
-       return NULL;
+       return Qnil;
       if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
-       return NULL;
+       return Qnil;
       if (FT_New_Face (ft_library, (char *) file, 0, &ft_face) != 0)
-       return NULL;
+       return Qnil;
       FcPatternAddFTFace (pattern, FC_FT_FACE, ft_face);
       ft_size = ft_face->size;
+      XSAVE_VALUE (val)->integer++;
     }
   else
     {
       if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
          != FcResultMatch)
-       return NULL;
+       return Qnil;
       if (FT_New_Size (ft_face, &ft_size) != 0)
-       return NULL;
+       return Qnil;
       if (FT_Activate_Size (ft_size) != 0)
        {
          FT_Done_Size (ft_size);
-         return NULL;
+         return Qnil;
        }
     } 
 
@@ -847,84 +831,99 @@ ftfont_open (f, entity, pixel_size)
     {
       if (XSAVE_VALUE (val)->integer == 0)
        FT_Done_Face (ft_face);
-      return NULL;
+      return Qnil;
     }
 
-  ftfont_info = malloc (sizeof (struct ftfont_info));
-  if (! ftfont_info)
-    return NULL;
+  font_object = font_make_object (VECSIZE (struct ftfont_info));
+  ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
+  for (i = 1;i < FONT_ENTITY_MAX; i++)
+    ASET (font_object, i, AREF (entity, i));
+  ASET (font_object, FONT_SIZE_INDEX, make_number (size));
+  len = font_unparse_xlfd (entity, size, name, 256);
+  if (len > 0)
+    ASET (font_object, FONT_NAME_INDEX, make_unibyte_string (name, len));
+  len = font_unparse_fcname (entity, size, name, 256);
+  if (len > 0)
+    ASET (font_object, FONT_FULLNAME_INDEX, make_unibyte_string (name, len));
+  else
+    ASET (font_object, FONT_FULLNAME_INDEX,
+         AREF (font_object, FONT_NAME_INDEX));
+  if (! file
+      && ! FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
+    return Qnil;
+  ASET (font_object, FONT_FILE_INDEX,
+       make_unibyte_string ((char *) file, strlen ((char *) file)));
+  ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (pattern));
+  font = XFONT_OBJECT (font_object);
+  ftfont_info = (struct ftfont_info *) font;
   ftfont_info->ft_size = ft_size;
 #ifdef HAVE_LIBOTF
   ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
   ftfont_info->otf = NULL;
 #endif /* HAVE_LIBOTF */
-
-  font = (struct font *) ftfont_info;
-  font->format = ftfont_font_format (pattern);
-  font->entity = entity;
   font->pixel_size = size;
   font->driver = &ftfont_driver;
-  len = 96;
-  name = malloc (len);
-  while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
-    {
-      char *new = realloc (name, len += 32);
+  font->encoding_charset = font->repertory_charset = -1;
 
-      if (! new)
-       free (name);
-      name = new;
+  upEM = ft_face->units_per_EM;
+  if (! FcPatternGetBool (pattern, FC_SCALABLE, 0, &scalable) == FcResultMatch)
+    scalable = FcFalse;
+  if (scalable)
+    {
+      font->ascent = ft_face->ascender * size / upEM;
+      font->descent = - ft_face->descender * size / upEM;
+      font->height = ft_face->height * size / upEM;
+    }
+  else
+    {
+      font->ascent = ft_face->size->metrics.ascender >> 6;
+      font->descent = - ft_face->size->metrics.descender >> 6;
+      font->height = ft_face->size->metrics.height >> 6;
     }
-  font->font.full_name = font->font.name = name;
-  font->file_name = (char *) file;
-  font->font.size = ft_face->size->metrics.max_advance >> 6;
-  if (font->font.size <= 0)
-    font->font.size = size;
-  font->font.charset = font->encoding_charset = font->repertory_charset = -1;
-  font->ascent = ft_face->size->metrics.ascender >> 6;
-  font->descent = - ft_face->size->metrics.descender >> 6;
-  font->font.height = font->ascent + font->descent;
   if (FcPatternGetInteger (pattern, FC_SPACING, 0, &spacing) != FcResultMatch)
     spacing = FC_PROPORTIONAL;
   if (spacing != FC_PROPORTIONAL)
-    font->font.average_width = font->font.space_width = font->font.size;
+    font->min_width = font->average_width = font->space_width
+      = (scalable ? ft_face->max_advance_width * size / upEM
+        : ft_face->size->metrics.max_advance >> 6);
   else
     {
-      int i;
+      int n;
 
-      font->font.average_width = font->font.space_width = 0;
-      for (i = 32; i < 127; i++)
-       {
-         if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) != 0)
-           break;
-         if (i == 32)
-           font->font.space_width = ft_face->glyph->metrics.horiAdvance >> 6;
-         font->font.average_width += ft_face->glyph->metrics.horiAdvance >> 6;
-       }
-      if (i == 127)
-       {
-         /* The font contains all ASCII printable characters.  */
-         font->font.average_width /= 95;
-       }
-      else
-       {
-         if (i == 32)
-           font->font.space_width = font->font.size;
-         font->font.average_width = font->font.size;
-       }
+      font->min_width = font->average_width = font->space_width = 0;
+      for (i = 32, n = 0; i < 127; i++)
+       if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) != 0)
+         {
+           int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
+
+           if (this_width > 0
+               && (! font->min_width || font->min_width > this_width))
+             font->min_width = this_width;
+           if (i == 32)
+             font->space_width = this_width;
+           font->average_width += this_width;
+           n++;
+         }
+      if (n > 0)
+       font->average_width /= n;
     }
 
-  /* Unfortunately FreeType doesn't provide a way to get minimum char
-     width.  So, we use space_width instead.  */
-  font->min_width = font->font.space_width;
-
-  font->font.baseline_offset = 0;
-  font->font.relative_compose = 0;
-  font->font.default_ascent = 0;
-  font->font.vertical_centering = 0;
-
-  (XSAVE_VALUE (val)->integer)++;
+  font->baseline_offset = 0;
+  font->relative_compose = 0;
+  font->default_ascent = 0;
+  font->vertical_centering = 0;
+  if (scalable)
+    {
+      font->underline_position = -ft_face->underline_position * size / upEM;
+      font->underline_thickness = -ft_face->underline_thickness * size / upEM;
+    }
+  else
+    {
+      font->underline_position = -1;
+      font->underline_thickness = 0;
+    }
 
-  return font;
+  return font_object;
 }
 
 static void
@@ -933,9 +932,10 @@ ftfont_close (f, font)
      struct font *font;
 {
   struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
-  Lisp_Object entity = font->entity;
-  Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
+  Lisp_Object val;
 
+  val = assq_no_quit (QCfont_entity, font->props[FONT_EXTRA_INDEX]);
+  val = XCDR (val);
   (XSAVE_VALUE (val)->integer)--;
   if (XSAVE_VALUE (val)->integer == 0)
     {
@@ -947,8 +947,6 @@ ftfont_close (f, font)
     }
   else
     FT_Done_Size (ftfont_info->ft_size);
-
-  free (font);
 }
 
 static int 
@@ -960,7 +958,8 @@ ftfont_has_char (entity, c)
   FcPattern *pattern;
   FcCharSet *charset;
 
-  val = AREF (entity, FONT_EXTRA_INDEX);
+  val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+  val = XCDR (val);
   pattern = XSAVE_VALUE (val)->pointer;
   if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
     return -1;
@@ -1019,7 +1018,7 @@ ftfont_text_extents (font, code, nglyphs, metrics)
        }
       else
        {
-         width += font->font.space_width;
+         width += font->space_width;
        }
     }
   if (metrics)
@@ -1161,7 +1160,7 @@ ftfont_get_metrics (font, gstring, from, to)
        else
          {
            g->lbearing = 0;
-           g->rbearing = g->xadv = flt_font_ft->font->font.space_width << 6;
+           g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
            g->ascent = flt_font_ft->font->ascent << 6;
            g->descent = flt_font_ft->font->descent << 6;
          }