diff src/ftfont.c @ 91187:96e18e1645a1

(struct OpenTypeSpec): New struct. (OTF_SYM_TAG, OTF_TAG_STR): New macros. (ftfont_get_open_type_spec): New function. (ftfont_list) [HAVE_LIBOTF]: Check otf-spec property.
author Kenichi Handa <handa@m17n.org>
date Wed, 05 Dec 2007 12:02:27 +0000
parents 2b263ef46651
children ffc66d7b1d98
line wrap: on
line diff
--- a/src/ftfont.c	Wed Dec 05 05:08:12 2007 +0000
+++ b/src/ftfont.c	Wed Dec 05 12:02:27 2007 +0000
@@ -322,6 +322,84 @@
   return freetype_font_cache;
 }
 
+struct OpenTypeSpec
+{
+  unsigned int script, langsys;
+  int nfeatures[2];
+  unsigned int *features[2];
+};
+
+#define OTF_SYM_TAG(sym, tag)					\
+  do {								\
+    unsigned char *p = SDATA (SYMBOL_NAME (val));		\
+    tag = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];	\
+  } while (0)
+
+#define OTF_TAG_STR(tag, str)			\
+  do {						\
+    (str)[0] = (char) (tag >> 24);		\
+    (str)[1] = (char) ((tag >> 16) & 0xFF);	\
+    (str)[2] = (char) ((tag >> 8) & 0xFF);	\
+    (str)[3] = (char) (tag & 0xFF);		\
+  } while (0)
+
+static struct OpenTypeSpec *
+ftfont_get_open_type_spec (Lisp_Object otf_spec)
+{
+  struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
+  Lisp_Object val;
+  int i, j, negative;
+
+  if (! spec)
+    return NULL;
+  val = XCAR (otf_spec);
+  if (! NILP (val))
+    OTF_SYM_TAG (val, spec->script);
+  else
+    spec->script = 0x44464C54; 	/* "DFLT" */
+  otf_spec = XCDR (otf_spec);
+  val = XCAR (otf_spec);
+  if (! NILP (val))
+    OTF_SYM_TAG (val, spec->langsys);
+  else
+    spec->langsys = 0;
+  spec->nfeatures[0] = spec->nfeatures[1] = 0;
+  for (i = 0; i < 2; i++)
+    {
+      Lisp_Object len;
+
+      otf_spec = XCDR (otf_spec);    
+      if (NILP (otf_spec))
+	break;
+      val = XCAR (otf_spec);
+      if (NILP (val))
+	continue;
+      len = Flength (val);
+      spec->features[i] = malloc (sizeof (int) * XINT (len));
+      if (! spec->features[i])
+	{
+	  if (i > 0 && spec->features[0])
+	    free (spec->features[0]);
+	  free (spec);
+	  return NULL;
+	}
+      for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
+	{
+	  if (NILP (XCAR (val)))
+	    negative = 1;
+	  else
+	    {
+	      unsigned int tag;
+
+	      OTF_SYM_TAG (XCAR (val), tag);
+	      spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
+	    }
+	}
+      spec->nfeatures[i] = j;
+    }
+  return spec;
+}
+
 static Lisp_Object
 ftfont_list (frame, spec)
      Lisp_Object frame, spec;
@@ -335,11 +413,12 @@
   FcObjectSet *objset = NULL;
   Lisp_Object script;
   Lisp_Object registry = Qunicode_bmp;
+  struct OpenTypeSpec *otspec= NULL;
   int weight = 0;
   double dpi = -1;
   int spacing = -1;
   int scalable = -1;
-  char otf_script[15];		/* For "otlayout\:XXXX" */
+  char otlayout[15];		/* For "otlayout:XXXX" */
   
   val = null_vector;
 
@@ -373,7 +452,7 @@
 	return val;
     }
 
-  otf_script[0] = '\0';
+  otlayout[0] = '\0';
   script = Qnil;
   for (extra = AREF (spec, FONT_EXTRA_INDEX);
        CONSP (extra); extra = XCDR (extra))
@@ -384,19 +463,11 @@
       key = XCAR (tmp), val = XCDR (tmp);
       if (EQ (key, QCotf))
 	{
-	  tmp = XCAR (val);
-	  if (NILP (tmp))
-	    strcpy (otf_script, "otlayout:DFLT");
-	  else
-	    {
-	      val = assq_no_quit (tmp, Votf_script_alist);
-	      if (CONSP (val) && SYMBOLP (XCDR (val)))
-		{
-		  sprintf (otf_script, "otlayout:%s",
-			   (char *) SDATA (SYMBOL_NAME (tmp)));
-		  script = XCDR (val);
-		}
-	    }
+	  otspec = ftfont_get_open_type_spec (val);
+	  if (otspec)
+	    return null_vector;
+	  strcat (otlayout, "otlayout:");
+	  OTF_TAG_STR (otspec->script, otlayout + 9);
 	}
       else if (EQ (key, QClanguage))
 	{
@@ -491,13 +562,13 @@
 			     NULL);
   if (! objset)
     goto err;
-  if (otf_script[0])
+  if (otlayout[0])
     {
-#ifndef FC_CAPABILITY
-      goto finish;
-#else  /* not FC_CAPABILITY */
+#ifdef FC_CAPABILITY
       if (! FcObjectSetAdd (objset, FC_CAPABILITY))
 	goto err;
+#else  /* not FC_CAPABILITY */
+      goto finish;
 #endif	/* not FC_CAPABILITY */
     }
 
@@ -541,16 +612,39 @@
 		continue;
 	    }
 #ifdef FC_CAPABILITY
-	  if (otf_script[0])
+	  if (otlayout[0])
 	    {
 	      FcChar8 *this;
 
 	      if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0,
 				      &this) != FcResultMatch
-		  || ! strstr ((char *) this, otf_script))
+		  || ! strstr ((char *) this, otlayout))
 		continue;
 	    }
 #endif	/* FC_CAPABILITY */
+#ifdef HAVE_LIBOTF
+	  if (otspec)
+	    {
+	      FcChar8 *file;
+	      OTF *otf;
+
+	      if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
+		  != FcResultMatch)
+		continue;
+	      otf = OTF_open ((char *) file);
+	      if (! otf)
+		continue;
+	      if (OTF_check_features (otf, 0,
+				      otspec->script, otspec->langsys,
+				      otspec->features[0],
+				      otspec->nfeatures[0]) != 1
+		  || OTF_check_features (otf, 1,
+					 otspec->script, otspec->langsys,
+					 otspec->features[1],
+					 otspec->nfeatures[1]) != 1)
+		continue;
+	    }
+#endif	/* HAVE_LIBOTF */
 	  entity = ftfont_pattern_entity (fontset->fonts[i], frame, registry);
 	  if (! NILP (entity))
 	    val = Fcons (entity, val);
@@ -572,7 +666,14 @@
   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;
 }