+ if (! ft_language_list)
+ ft_language_list = mplist ();
+ else if ((plist = mplist_find_by_key (ft_language_list, language)))
+ return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
+
+#ifdef HAVE_FONTCONFIG
+ for (step = 0; step < 2; step++)
+ {
+ FcPattern *pattern = NULL;
+ FcObjectSet *os = NULL;
+ FcFontSet *fs = NULL;
+ char *buf;
+ int bufsize = 0;
+ int i;
+
+ if (! (pattern = FcPatternCreate ())
+ || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
+ goto err;
+ if (step == 0)
+ {
+ FcLangSet *ls = FcLangSetCreate ();
+
+ if (! ls)
+ goto err;
+ if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
+ && FcPatternAddLangSet (pattern, FC_LANG, ls))
+ fs = FcFontList (fc_config, pattern, os);
+ FcLangSetDestroy (ls);
+ if (! fs)
+ goto err;
+ }
+ else
+ {
+ FcCharSet *cs;
+
+ if (! (mt = msymbol_get (language, Mtext)))
+ break;
+ if (! (cs = FcCharSetCreate ()))
+ goto err;
+ for (i = mtext_nchars (mt) - 1; i >= 0; i--)
+ if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
+ break;
+ if (i < 0
+ && (mt = mtext_get_prop (mt, 0, Mtext)))
+ for (i = mtext_nchars (mt) - 1; i >= 0; i--)
+ if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
+ break;
+ if (i < 0)
+ {
+ if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
+ fs = FcFontList (fc_config, pattern, os);
+ }
+ FcCharSetDestroy (cs);
+ if (! fs)
+ goto err;
+ }
+
+ for (i = 0; i < fs->nfont; i++)
+ {
+ MSymbol family, file;
+ char *fam, *filename;
+ MPlist *pl;
+ MFontFT *ft_info;
+
+ if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
+ (FcChar8 **) &fam) != FcResultMatch)
+ continue;
+ if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
+ (FcChar8 **) &filename) != FcResultMatch)
+ continue;
+ STRDUP_LOWER (buf, bufsize, fam);
+ family = msymbol (buf);
+ file = msymbol (filename);
+ pl = MPLIST_PLIST (ft_list_family (family, 0));
+ ft_info = mplist_get (pl, file);
+ if (ft_info)
+ {
+ if (! plist)
+ plist = mplist ();
+ mplist_add (plist, family, ft_info);
+ }
+ }
+ FcFontSetDestroy (fs);
+ FcObjectSetDestroy (os);
+ FcPatternDestroy (pattern);
+ if (language == msymbol ("en"))
+ break;
+ continue;
+
+ err:
+ if (os)
+ FcObjectSetDestroy (os);
+ if (pattern)
+ FcPatternDestroy (pattern);
+ MEMORY_FULL (MERROR_FONT_FT);
+ return NULL;
+ }
+
+ mplist_push (ft_language_list, language, plist);
+ return plist;
+
+#else /* not HAVE_FONTCONFIG */
+
+ if ((mt = msymbol_get (language, Mtext)))
+ {
+ MText *extra = mtext_get_prop (mt, 0, Mtext);
+ MPlist *pl, *p;
+ int len = mtext_nchars (mt);
+ int extra_len = extra ? mtext_nchars (extra) : 0;
+ int i;
+
+ if (! ft_font_list)
+ ft_list_family (Mnil, 0);
+ MPLIST_DO (pl, ft_font_list)
+ {
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ {
+ MFontFT *ft_info = MPLIST_VAL (p);
+ MSymbol family;
+ FT_Face ft_face;
+
+ if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
+ 0, &ft_face) != 0)
+ continue;
+ for (i = len - 1; i >= 0; i--)
+ if (FT_Get_Char_Index (ft_face,
+ (FT_ULong) mtext_ref_char (mt, i)) == 0)
+ break;
+ if (i < 0 && extra_len > 0)
+ for (i = extra_len - 1; i >= 0; i--)
+ if (FT_Get_Char_Index (ft_face,
+ (FT_ULong) mtext_ref_char (extra, i)) == 0)
+ break;
+ FT_Done_Face (ft_face);
+ if (i >= 0)
+ continue;
+ if (! plist)
+ plist = mplist ();
+ family = mfont_get_prop (&ft_info->font, Mfamily);
+ mplist_push (plist, family, ft_info);
+ }
+ }
+ }
+ return plist;
+#endif /* not HAVE_FONTCONFIG */
+}
+
+static MPlist *
+ft_list_script (MSymbol script)