changeset 90464:4702b592db4c

(Qmonospace, Qsans_serif, Qserif, Qmono, Qsans) (Qsans__serif): New variables. (ftfont_generic_family_list): New variable. (syms_of_ftfont): Initialize the above variables. (ftfont_pattern_entity): Argument NAME deleted. (ftfont_list_generic_family): New function. (ftfont_parse_name): Delete this function. (ftfont_list): Try generic family only when FcFontList found no font. (ftfont_list_family): Fix args to FcObjectSetBuild.
author Kenichi Handa <handa@m17n.org>
date Fri, 16 Jun 2006 12:24:58 +0000
parents 1d40cee6b4dc
children 9430e7e49983
files src/ftfont.c
diffstat 1 files changed, 159 insertions(+), 131 deletions(-) [+]
line wrap: on
line diff
--- a/src/ftfont.c	Fri Jun 16 12:19:38 2006 +0000
+++ b/src/ftfont.c	Fri Jun 16 12:24:58 2006 +0000
@@ -43,6 +43,9 @@
 /* Symbolic type of this font-driver.  */
 Lisp_Object Qfreetype;
 
+/* Fontconfig's generic families and their aliases.  */
+static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
+
 /* Flag to tell if FcInit is areadly called or not.  */
 static int fc_initialized;
 
@@ -65,6 +68,14 @@
   FT_Size ft_size;
 };
 
+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));
+
+#define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
+
 static int
 ftfont_build_basic_charsets ()
 {
@@ -82,10 +93,10 @@
   return 0;
 }
 
-Lisp_Object
-ftfont_pattern_entity (p, frame, registry, name)
+static Lisp_Object
+ftfont_pattern_entity (p, frame, registry)
      FcPattern *p;
-     Lisp_Object frame, registry, name;
+     Lisp_Object frame, registry;
 {
   Lisp_Object entity;
   FcChar8 *file;
@@ -133,10 +144,7 @@
 
   if (FcPatternAddString (p, FC_FILE, file) == FcFalse
       || (charset && FcPatternAddCharSet (p, FC_CHARSET, charset) == FcFalse)
-      || FcPatternAddInteger (p, FC_SPACING, numeric) == FcFalse
-      || (! NILP (name)
-	  && (FcPatternAddString (p, FC_FILE, (FcChar8 *) SDATA (name))
-	      == FcFalse)))
+      || FcPatternAddInteger (p, FC_SPACING, numeric) == FcFalse)
     {
       FcPatternDestroy (p);
       return Qnil;
@@ -145,9 +153,92 @@
   return entity;
 }
 
+static Lisp_Object ftfont_generic_family_list;
+
+static Lisp_Object
+ftfont_list_generic_family (spec, frame, registry)
+     Lisp_Object spec, frame, registry;
+{
+  Lisp_Object family = AREF (spec, FONT_FAMILY_INDEX);
+  Lisp_Object slot, list, val;
+
+  if (EQ (family, Qmono))
+    family = Qmonospace;
+  else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
+    family = Qsans_serif;
+  slot = assq_no_quit (family, ftfont_generic_family_list);
+  if (! CONSP (slot))
+    return null_vector;
+  list = XCDR (slot);
+  if (EQ (list, Qt))
+    {
+      /* 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, 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, 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;
+    }
+  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);
+}
+
 
 static Lisp_Object ftfont_get_cache P_ ((Lisp_Object));
-static int ftfont_parse_name P_ ((FRAME_PTR, char *, Lisp_Object));
 static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
 static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
 static void ftfont_free_entity P_ ((Lisp_Object));
@@ -166,7 +257,6 @@
   {
     (Lisp_Object) NULL,		/* Qfreetype */
     ftfont_get_cache,
-    ftfont_parse_name,    
     ftfont_list,
     ftfont_list_family,
     ftfont_free_entity,
@@ -196,8 +286,6 @@
 #endif	/* HAVE_LIBOTF */
   };
 
-#define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
-
 extern Lisp_Object QCname;
 
 static Lisp_Object
@@ -207,47 +295,11 @@
   return freetype_font_cache;
 }
 
-static int
-ftfont_parse_name (f, name, spec)
-     FRAME_PTR f;
-     char *name;
-     Lisp_Object spec;
-{
-  FcPattern *p;
-  FcChar8 *str;
-  int numeric;
-  double dbl;
-
-  if (name[0] == '-' || strchr (name, '*'))
-    /* It seems that NAME is XLFD.  */
-    return -1;
-  p = FcNameParse ((FcChar8 *) name);
-  if (! p)
-    return -1;
-  if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
-    ASET (spec, FONT_FOUNDRY_INDEX,
-	  intern_downcase ((char *) str, strlen ((char *) str)));
-  if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
-    ASET (spec, FONT_FAMILY_INDEX,
-	  intern_downcase ((char *) str, strlen ((char *) str)));
-  if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
-    ASET (spec, FONT_WEIGHT_INDEX, make_number (numeric));
-  if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
-    ASET (spec, FONT_SLANT_INDEX, make_number (numeric + 100));
-  if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
-    ASET (spec, FONT_WIDTH_INDEX, make_number (numeric));
-  if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
-    ASET (spec, FONT_SIZE_INDEX, make_number (dbl));
-  else if (FcPatternGetDouble (p, FC_SIZE, 0, &dbl) == FcResultMatch)
-    ASET (spec, FONT_SIZE_INDEX, make_float (dbl));
-  return 0;
-}
-
 static Lisp_Object
 ftfont_list (frame, spec)
      Lisp_Object frame, spec;
 {
-  Lisp_Object val, tmp, extra, font_name, file_name;
+  Lisp_Object val, tmp, extra, font_name;
   int i;
   FcPattern *pattern = NULL;
   FcCharSet *charset = NULL;
@@ -273,15 +325,15 @@
 	{
 	  if (! cs_iso8859_1
 	      && ftfont_build_basic_charsets () < 0)
-	    goto err;
+	    return Qnil;
 	  charset = cs_iso8859_1;
 	}
       else if (! EQ (registry, Qiso10646_1) && ! EQ (registry, Qunicode_bmp))
-	goto finish;
+	return val;
     }
 
   extra = AREF (spec, FONT_EXTRA_INDEX);
-  font_name = file_name = Qnil;
+  font_name = Qnil;
   if (CONSP (extra))
     {
       tmp = Fassq (QCotf, extra);
@@ -310,11 +362,7 @@
 	}
       tmp = Fassq (QCname, extra);
       if (CONSP (tmp))
-	{
-	  font_name = XCDR (tmp);
-	  if (SDATA (font_name)[0] == ':')
-	    file_name = font_name, font_name = Qnil;
-	}
+	font_name = XCDR (tmp);
       tmp = Fassq (QCscript, extra);
       if (CONSP (tmp) && ! charset)
 	{
@@ -336,49 +384,35 @@
     }
 
   if (STRINGP (font_name))
-    {
-      if (SDATA (font_name)[0] == '-')
-	goto finish;
-      pattern = FcNameParse (SDATA (font_name));
-      if (! pattern)
-	goto err;
-    }
+    pattern = FcNameParse (SDATA (font_name));
   else
-    {
-      if (! NILP (file_name))
-	{
-	  pattern = FcNameParse (SDATA (file_name));
-	  FcPatternDel (pattern, FC_PIXEL_SIZE);
-	}
-      else
-	pattern = FcPatternCreate ();
-      if (! pattern)
-	goto err;
+    pattern = FcPatternCreate ();
+  if (! pattern)
+    goto err;
 
-      tmp = AREF (spec, FONT_FOUNDRY_INDEX);
-      if (SYMBOLP (tmp) && ! 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;
-      tmp = AREF (spec, FONT_WEIGHT_INDEX);
-      if (INTEGERP (tmp)
-	  && ! FcPatternAddInteger (pattern, FC_WEIGHT, XINT (tmp)))
-	goto err;
-      tmp = AREF (spec, FONT_SLANT_INDEX);
-      if (INTEGERP (tmp)
-	  && XINT (tmp) >= 100
-	  && ! 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 (! FcPatternAddBool (pattern, FC_SCALABLE, FcTrue))
-	goto err;
-    }
+  tmp = AREF (spec, FONT_FOUNDRY_INDEX);
+  if (SYMBOLP (tmp) && ! 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;
+  tmp = AREF (spec, FONT_WEIGHT_INDEX);
+  if (INTEGERP (tmp)
+      && ! FcPatternAddInteger (pattern, FC_WEIGHT, XINT (tmp)))
+    goto err;
+  tmp = AREF (spec, FONT_SLANT_INDEX);
+  if (INTEGERP (tmp)
+      && XINT (tmp) >= 100
+      && ! 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 (! FcPatternAddBool (pattern, FC_SCALABLE, FcTrue))
+    goto err;
 
   if (charset
       && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
@@ -387,51 +421,33 @@
       && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
     goto err;
 
-  if (STRINGP (font_name))
-    {
-      FcPattern *pat;
-      FcResult result;
-      FcValue v;
-      Lisp_Object entity;
+  objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
+			     FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
+			     FC_CHARSET, FC_FILE, NULL);
+  if (! objset)
+    goto err;
+  fontset = FcFontList (NULL, pattern, objset);
+  if (! fontset)
+    goto err;
 
-      if (FcPatternGet (pattern, FC_LANG, 0, &v) == FcResultNoMatch)
-	/* If no language is specified in PATTERN, fontconfig will use
-	   that of the current locale.  This cancel that effect.  */
-	FcPatternAddString (pattern, FC_LANG, (FcChar8 *) "en");
-      FcConfigSubstitute (NULL, pattern, FcMatchPattern);
-      FcDefaultSubstitute (pattern);
-      pat = FcFontMatch (NULL, pattern, &result);
-      entity = ftfont_pattern_entity (pat, frame, registry, font_name);
-      FcPatternDestroy (pat);
-      if (! NILP (entity))
-	val = Fmake_vector (make_number (1), entity);
-    }      
-  else
+  if (fontset->nfont > 0)
     {
-      objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
-				 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
-				 FC_CHARSET, FC_FILE, NULL);
-      if (! objset)
-	goto err;
-
-      fontset = FcFontList (NULL, pattern, objset);
-      if (! fontset)
-	goto err;
-      val = Qnil;
-      for (i = 0; i < fontset->nfont; i++)
+      for (i = 0, val = Qnil; i < fontset->nfont; i++)
 	{
 	  Lisp_Object entity = ftfont_pattern_entity (fontset->fonts[i],
-						      frame, registry, Qnil);
+						      frame, registry);
 	  if (! NILP (entity))
 	    val = Fcons (entity, val);
 	}
       val = Fvconcat (1, &val);
     }
+  else if (! NILP (AREF (spec, FONT_FAMILY_INDEX)))
+    val = ftfont_list_generic_family (spec, frame, registry);
   goto finish;
 
  err:
   /* We come here because of unexpected error in fontconfig API call
-     (usually insufficiency memory).  */
+     (usually insufficient memory).  */
   val = Qnil;
 
  finish:
@@ -463,7 +479,7 @@
   pattern = FcPatternCreate ();
   if (! pattern)
     goto finish;
-  objset = FcObjectSetBuild (FC_FAMILY);
+  objset = FcObjectSetBuild (FC_FAMILY, NULL);
   if (! objset)
     goto finish;
   fontset = FcFontList (NULL, pattern, objset);
@@ -772,10 +788,22 @@
 void
 syms_of_ftfont ()
 {
+  DEFSYM (Qfreetype, "freetype");
+  DEFSYM (Qmonospace, "monospace");
+  DEFSYM (Qsans_serif, "sans-serif");
+  DEFSYM (Qserif, "serif");
+  DEFSYM (Qmono, "mono");
+  DEFSYM (Qsans, "sans");
+  DEFSYM (Qsans__serif, "sans serif");
+
   staticpro (&freetype_font_cache);
   freetype_font_cache = Fcons (Qt, Qnil);
 
-  DEFSYM (Qfreetype, "freetype");
+  staticpro (&ftfont_generic_family_list);
+  ftfont_generic_family_list
+    = Fcons (Fcons (Qmonospace, Qt),
+	     Fcons (Fcons (Qsans_serif, Qt),
+		    Fcons (Fcons (Qsans, Qt), Qnil)));
 
   ftfont_driver.type = Qfreetype;
   register_font_driver (&ftfont_driver, NULL);