diff src/ftfont.c @ 102944:44a517fa4d12

(Qja, Qko): New variables. (fc_charset_table): Delete uniquifier data for iso8859-1. (ftfont_get_latin1_charset): New function. (get_adstyle_property): New function. (ftfont_pattern_entity): Set FONT_ADSTYLE_INDEX of entity for bitmap fonts. (ftfont_lookup_cache): Handle the case that KEY is a font-entity. Delete iso-8859-1 range from the charset of fonts whose adstyle is `ko' or `ja'. (ftfont_get_fc_charset): Call ftfont_lookup_cache with ENTITY. (ftfont_get_charset): For iso8859-1, call ftfont_get_latin1_charset. (ftfont_list): Don't refuse a font spec with non-nil `adstyle' property. (ftfont_open): Call ftfont_lookup_cache with ENTITY. (syms_of_ftfont): DEFSYM Qja and Qko.
author Kenichi Handa <handa@m17n.org>
date Mon, 13 Apr 2009 12:33:13 +0000
parents 3f976a2deab1
children f623dc25d37e
line wrap: on
line diff
--- a/src/ftfont.c	Mon Apr 13 12:33:02 2009 +0000
+++ b/src/ftfont.c	Mon Apr 13 12:33:13 2009 +0000
@@ -43,6 +43,9 @@
 /* Fontconfig's generic families and their aliases.  */
 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
 
+/* Special ADSTYLE properties to avoid fonts used for Latin characters.  */
+static Lisp_Object Qja, Qko;
+
 /* Flag to tell if FcInit is already called or not.  */
 static int fc_initialized;
 
@@ -92,7 +95,7 @@
   /* set on demand */
   FcCharSet *fc_charset;
 } fc_charset_table[] =
-  { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
+  { { "iso8859-1", { } },	/* ftfont_get_latin1_charset handles it. */
     { "iso8859-2", { 0x00A0, 0x010E }},
     { "iso8859-3", { 0x00A0, 0x0108 }},
     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
@@ -132,8 +135,71 @@
     { NULL }
   };
 
+/* Return a FcCharSet for iso8859-1 from fc_charset_table[0].  If the
+   charset is not yet ready, create it. */
+static FcCharSet *
+ftfont_get_latin1_charset ()
+{
+  FcCharSet *cs;
+  FcChar32 c;
+
+  if (fc_charset_table[0].fc_charset)
+    return fc_charset_table[0].fc_charset;
+  cs = FcCharSetCreate ();
+  if (! cs)
+    return NULL;
+  for (c = 33; c <= 0xFF; c++)
+    {
+      FcCharSetAddChar (cs, c);
+      if (c == 0x7E)
+	c = 0xA0;
+    }
+  fc_charset_table[0].fc_charset = cs;
+  return cs;
+}
+
 extern Lisp_Object Qc, Qm, Qp, Qd;
 
+/* Dirty hack for handing ADSTYLE property.
+
+   Fontconfig (actually the underlying FreeType) gives such ADSTYLE
+   font property of PCF/BDF fonts in FC_STYLE.  And, "Bold",
+   "Oblique", "Italic", or any non-normal SWIDTH property names
+   (e.g. SemiCondensed) are appended.  In addition, if there's no
+   ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
+   "Regular" is used for FC_STYLE (see the function
+   pcf_interpret_style in src/pcf/pcfread.c of FreeType).
+
+   Unfortunately this behavior is not documented, so the following
+   code may fail if FreeType changes the behavior in the future.  */
+
+static Lisp_Object
+get_adstyle_property (FcPattern *p)
+{
+  char *str, *end;
+  Lisp_Object adstyle;
+
+  if (FcPatternGetString (p, FC_STYLE, 0, (FcChar8 **) &str) != FcResultMatch)
+    return Qnil;
+  for (end = str; *end && *end != ' '; end++);
+  if (*end)
+    {
+      char *p = alloca (end - str + 1);
+      memcpy (p, str, end - str);
+      p[end - str] = '\0';
+      str = p;
+    }
+  if (xstrcasecmp (str, "Regular") == 0
+      || xstrcasecmp (str, "Bold") == 0
+      || xstrcasecmp (str, "Oblique") == 0
+      || xstrcasecmp (str, "Italic") == 0)
+    return Qnil;
+  adstyle = font_intern_prop (str, end - str, 0);
+  if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
+    return Qnil;
+  return adstyle;
+}
+
 static Lisp_Object
 ftfont_pattern_entity (p, extra)
      FcPattern *p;
@@ -176,7 +242,14 @@
       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));
+    {
+      Lisp_Object adstyle;
+
+      ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
+      /* As this font has PIXEL_SIZE property, parhaps this is a BDF
+	 or PCF font. */ 
+      ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
+    }
   else
     ASET (entity, FONT_SIZE_INDEX, make_number (0));
   if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
@@ -265,9 +338,19 @@
      Lisp_Object key;
      int for_face;
 {
-  Lisp_Object cache, val;
+  Lisp_Object cache, val, entity;
   struct ftfont_cache_data *cache_data;
 
+  if (FONT_ENTITY_P (key))
+    {
+      entity = key;
+      val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+      xassert (CONSP (val));
+      key = XCDR (val);
+    }
+  else
+    entity = Qnil;
+
   cache = assoc_no_quit (key, ft_face_cache);
   if (NILP (cache))
     {
@@ -301,25 +384,56 @@
 	}
       else
 	{
-	  FcPattern *pat;
-	  FcFontSet *fontset;
-	  FcObjectSet *objset;
-	  FcCharSet *charset;
+	  FcPattern *pat = NULL;
+	  FcFontSet *fontset = NULL;
+	  FcObjectSet *objset = NULL;
+	  FcCharSet *charset = NULL;
 
 	  pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
 				FC_INDEX, FcTypeInteger, index, NULL);
-	  objset = FcObjectSetBuild (FC_CHARSET, NULL);
+	  if (! pat)
+	    goto finish;
+	  objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
+	  if (! objset)
+	    goto finish;
 	  fontset = FcFontList (NULL, pat, objset);
-	  if (fontset && fontset->nfont > 0
-	      && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
+	  if (! fontset)
+	    goto finish;
+	  if (fontset && fontset->nfont > 0)
+	    {
+	      if (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
 				       &charset)
-		  == FcResultMatch))
-	    cache_data->fc_charset = FcCharSetCopy (charset);
+		  == FcResultMatch)
+		{
+		  /* Dirty hack.  Fonts of "ja" and "ko" adstyle are
+		     not suitable for Latin characters.  */
+		  if (! NILP (entity)
+		      && (EQ (AREF (entity, FONT_ADSTYLE_INDEX), Qja)
+			  || EQ (AREF (entity, FONT_ADSTYLE_INDEX), Qko)))
+		    {
+		      FcCharSet *latin1 = ftfont_get_latin1_charset ();
+
+		      if (! latin1)
+			goto finish;
+		      cache_data->fc_charset = FcCharSetSubtract (charset,
+								  latin1);
+		    }
+		  else
+		    cache_data->fc_charset = FcCharSetCopy (charset);
+		}
+	      else
+		cache_data->fc_charset = FcCharSetCreate ();
+	    }
 	  else
 	    cache_data->fc_charset = FcCharSetCreate ();
-	  FcFontSetDestroy (fontset);
-	  FcObjectSetDestroy (objset);
-	  FcPatternDestroy (pat);
+
+	finish:
+	  if (fontset)
+	    FcFontSetDestroy (fontset);
+	  if (objset)
+	    FcObjectSetDestroy (objset);
+	  if (pat)
+	    FcPatternDestroy (pat);
 	}
     }
   return cache;
@@ -332,10 +446,7 @@
   Lisp_Object val, cache;
   struct ftfont_cache_data *cache_data;
 
-  val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
-  xassert (CONSP (val));
-  val = XCDR (val);
-  cache = ftfont_lookup_cache (val, 0);
+  cache = ftfont_lookup_cache (entity, 0);
   val = XCDR (cache);
   cache_data = XSAVE_VALUE (val)->pointer;
   return cache_data->fc_charset;
@@ -470,18 +581,23 @@
     return -1;
   if (! fc_charset_table[i].fc_charset)
     {
-      FcCharSet *charset = FcCharSetCreate ();
-      int *uniquifier = fc_charset_table[i].uniquifier;
+      if (i == 0)
+	ftfont_get_latin1_charset ();
+      else
+	{
+	  FcCharSet *charset = FcCharSetCreate ();
+	  int *uniquifier = fc_charset_table[i].uniquifier;
 
-      if (! charset)
-	return -1;
-      for (j = 0; uniquifier[j]; j++)
-	if (! FcCharSetAddChar (charset, uniquifier[j]))
-	  {
-	    FcCharSetDestroy (charset);
+	  if (! charset)
 	    return -1;
-	  }
-      fc_charset_table[i].fc_charset = charset;
+	  for (j = 0; uniquifier[j]; j++)
+	    if (! FcCharSetAddChar (charset, uniquifier[j]))
+	      {
+		FcCharSetDestroy (charset);
+		return -1;
+	      }
+	  fc_charset_table[i].fc_charset = charset;
+	}
     }
   return i;
 }
@@ -602,10 +718,6 @@
   Lisp_Object registry;
   int fc_charset_idx;
 
-  if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX))
-      && 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.  */
@@ -752,7 +864,7 @@
 ftfont_list (frame, spec)
      Lisp_Object frame, spec;
 {
-  Lisp_Object val = Qnil, family;
+  Lisp_Object val = Qnil, family, adstyle;
   int i;
   FcPattern *pattern;
   FcFontSet *fontset = NULL;
@@ -800,10 +912,12 @@
 	    goto err;
 	}
     }
-
+  adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
+  if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
+    adstyle = Qnil;
   objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
 			     FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
-			     FC_FILE, FC_INDEX,
+			     FC_STYLE, FC_FILE, FC_INDEX,
 #ifdef FC_CAPABILITY
 			     FC_CAPABILITY,
 #endif	/* FC_CAPABILITY */
@@ -908,6 +1022,15 @@
 	  if (j == ASIZE (chars))
 	    continue;
 	}
+      if (! NILP (adstyle))
+	{
+	  Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
+
+	  if (NILP (this_adstyle)
+	      || xstrcasecmp (SDATA (SYMBOL_NAME (adstyle)),
+			      SDATA (SYMBOL_NAME (this_adstyle))) != 0)
+	    continue;
+	}
       entity = ftfont_pattern_entity (fontset->fonts[i],
 				      AREF (spec, FONT_EXTRA_INDEX));
       if (! NILP (entity))
@@ -1046,7 +1169,7 @@
   if (! CONSP (val))
     return Qnil;
   val = XCDR (val);
-  cache = ftfont_lookup_cache (val, 1);
+  cache = ftfont_lookup_cache (entity, 1);
   if (NILP (cache))
     return Qnil;
   filename = XCAR (val);
@@ -2091,6 +2214,8 @@
   DEFSYM (Qmono, "mono");
   DEFSYM (Qsans, "sans");
   DEFSYM (Qsans__serif, "sans serif");
+  DEFSYM (Qja, "ja");
+  DEFSYM (Qko, "ko");
 
   staticpro (&freetype_font_cache);
   freetype_font_cache = Fcons (Qt, Qnil);