+ MPlist *char_list = mscript__char_list (script);
+
+ if (! char_list)
+ return -1;
+#ifdef HAVE_FONTCONFIG
+ if (ft_info->charset)
+ {
+ MPLIST_DO (char_list, char_list)
+ if (FcCharSetHasChar (ft_info->charset,
+ (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
+ break;
+ }
+ else
+#endif /* HAVE_FONTCONFIG */
+ {
+ int ft_face_allocaed = 0;
+
+ if (! ft_face)
+ {
+ char *filename = MSYMBOL_NAME (ft_info->font.file);
+
+ if (FT_New_Face (ft_library, filename, 0, &ft_face))
+ return -1;
+ ft_face_allocaed = 1;
+ }
+
+ MPLIST_DO (char_list, char_list)
+ if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
+ == 0)
+ break;
+ if (ft_face_allocaed)
+ FT_Done_Face (ft_face);
+ }
+
+ return (MPLIST_TAIL_P (char_list) ? 0 : -1);
+}
+
+static MPlist *ft_default_list;
+
+static MPlist *
+ft_list_default ()
+{
+ if (ft_default_list)
+ return ft_default_list;
+ ft_default_list = mplist ();
+#ifdef HAVE_FONTCONFIG
+ {
+ FcPattern *pat = FcPatternCreate ();
+ FcChar8 *fam;
+ char *buf;
+ int bufsize = 0;
+ int i;
+
+ FcConfigSubstitute (fc_config, pat, FcMatchPattern);
+ for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
+ i++)
+ {
+ MSymbol family;
+ MPlist *plist;
+
+ STRDUP_LOWER (buf, bufsize, (char *) fam);
+ family = msymbol (buf);
+ if (msymbol_get (family, Mgeneric_family))
+ continue;
+ plist = MPLIST_PLIST (ft_list_family (family, 0));
+ MPLIST_DO (plist, plist)
+ mplist_add (ft_default_list, family, MPLIST_VAL (plist));
+ }
+ }
+#else /* not HAVE_FONTCONFIG */
+ {
+ MPlist *plist, *pl;
+
+ MPLIST_DO (plist, ft_list_family (Mnil, 0))
+ {
+ pl = MPLIST_PLIST (plist);
+ if (! MPLIST_TAIL_P (pl))
+ mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
+ }
+ }
+#endif /* not HAVE_FONTCONFIG */
+ return ft_default_list;
+}
+
+
+static MPlist *ft_capability_list;
+
+static MPlist *
+ft_list_capability (MSymbol capability)
+{
+ MFontCapability *cap;
+ MPlist *plist = NULL, *pl;
+
+ if (! ft_capability_list)
+ ft_capability_list = mplist ();
+ else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
+ return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
+
+ cap = mfont__get_capability (capability);
+
+ if (cap && cap->language != Mnil)
+ {
+ plist = ft_list_language (cap->language);
+ if (! plist)
+ return NULL;
+ plist = mplist_copy (plist);
+ }
+
+ if (cap && cap->script != Mnil)
+ {
+ if (! plist)
+ {
+ plist = ft_list_script (cap->script);
+ if (! plist)
+ return NULL;
+ plist = mplist_copy (plist);
+ }
+ else
+ {
+ for (pl = plist; ! MPLIST_TAIL_P (pl);)
+ {
+ if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
+ mplist_pop (pl);
+ else
+ pl = MPLIST_NEXT (pl);
+ }
+ }
+
+ if (cap->script_tag)
+ {
+ for (pl = plist; ! MPLIST_TAIL_P (pl);)
+ {
+ if (ft_check_otf (MPLIST_VAL (pl), cap, NULL) < 0)
+ mplist_pop (pl);
+ else
+ pl = MPLIST_NEXT (pl);
+ }
+ }
+
+ if (MPLIST_TAIL_P (plist))
+ {
+ M17N_OBJECT_UNREF (plist);
+ plist = NULL;
+ }
+ }
+
+ mplist_push (ft_capability_list, capability, plist);
+ return plist;
+}
+
+
+static MPlist *
+ft_list_file (MSymbol filename)
+{
+ MPlist *plist = NULL;
+
+ if (! ft_file_list)
+ ft_file_list = mplist ();
+ else if ((plist = mplist_find_by_key (ft_file_list, filename)))
+ return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
+
+#ifdef HAVE_FONTCONFIG
+ {
+ FcPattern *pattern = FcPatternCreate ();
+ FcObjectSet *os;
+ FcFontSet *fs;
+
+ FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
+ os = FcObjectSetBuild (FC_FAMILY, NULL);
+ fs = FcFontList (fc_config, pattern, os);
+ if (fs->nfont > 0)
+ {
+ char *fam;
+ char *buf;
+ int bufsize = 0;
+
+ if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
+ (FcChar8 **) &fam) == FcResultMatch)
+ {
+ MSymbol family;
+ MPlist *pl;
+
+ STRDUP_LOWER (buf, bufsize, fam);
+ family = msymbol (buf);
+ pl = ft_list_family (family, 0);
+ MPLIST_DO (pl, MPLIST_PLIST (pl))
+ {
+ MFontFT *ft_info = MPLIST_VAL (pl);
+
+ if (ft_info->font.file == filename)
+ {
+ plist = mplist ();
+ mplist_add (plist, family, ft_info);
+ break;
+ }
+ }
+ }
+ }
+ }
+#else /* not HAVE_FONTCONFIG */
+ {
+ MPlist *pl, *p;
+
+ MPLIST_DO (pl, ft_list_family (Mnil, 0))
+ {
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ {
+ MFontFT *ft_info = MPLIST_VAL (pl);
+
+ if (ft_info->font.file == filename)
+ {
+ plist = mplist ();
+ mplist_add (plist, MPLIST_KEY (pl), ft_info);
+ break;
+ }
+ }
+ if (plist)
+ break;
+ }
+ }
+#endif /* not HAVE_FONTCONFIG */
+
+ mplist_push (ft_file_list, filename, plist);
+ return plist;
+}
+
+/* The FreeType font driver function SELECT. */
+
+static MFont *
+ft_select (MFrame *frame, MFont *font, int limited_size)
+{
+ MFont *found = NULL;
+#ifdef HAVE_FONTCONFIG
+ MPlist *plist, *pl;
+ MFontFT *ft_info;
+ int check_font_property = 1;
+
+ if (font->file != Mnil)
+ {
+ plist = ft_list_file (font->file);
+ if (! plist)
+ return NULL;
+ check_font_property = 0;
+ }
+ else
+ {
+ MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
+
+ if (family)
+ plist = MPLIST_PLIST (ft_list_family (family, 1));
+ else
+ plist = ft_list_default ();
+ if (MPLIST_TAIL_P (plist))
+ return NULL;
+ }
+
+ plist = mplist_copy (plist);
+
+ if (font->capability != Mnil)
+ {
+ MFontCapability *cap = mfont__get_capability (font->capability);
+
+ for (pl = plist; ! MPLIST_TAIL_P (pl);)
+ {
+ if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap, NULL) < 0)
+ {
+ mplist_pop (pl);
+ continue;
+ }
+ if (cap->language
+ && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
+ mplist_pop (pl);
+ else
+ pl = MPLIST_NEXT (pl);
+ }
+ }
+
+ if (check_font_property)
+ {
+ MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
+ MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
+ MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
+ MSymbol alternate_weight = Mnil;
+
+ if (weight == Mnormal)
+ alternate_weight = Mmedium;
+ else if (weight == Mmedium)
+ alternate_weight = Mnormal;
+ if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
+ for (pl = plist; ! MPLIST_TAIL_P (pl); )
+ {
+ ft_info = MPLIST_VAL (pl);
+ if ((weight != Mnil
+ && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
+ && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
+ || (style != Mnil
+ && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
+ || (stretch != Mnil
+ && stretch != FONT_PROPERTY (&ft_info->font,
+ MFONT_STRETCH))
+ || (font->size > 0
+ && ft_info->font.size > 0
+ && ft_info->font.size != font->size))
+ mplist_pop (pl);
+ else
+ pl = MPLIST_NEXT (pl);
+ }
+ }
+
+ MPLIST_DO (pl, plist)
+ {
+ font = MPLIST_VAL (plist);
+ if (limited_size == 0
+ || font->size == 0
+ || font->size <= limited_size)
+ {
+ found = font;
+ break;
+ }
+ }
+ M17N_OBJECT_UNREF (plist);
+#endif /* HAVE_FONTCONFIG */
+ return found;
+}
+
+
+static MRealizedFont *
+ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
+{
+ MFontFT *ft_info = (MFontFT *) font;
+ int reg = spec->property[MFONT_REGISTRY];
+ MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
+ MRealizedFontFT *ft_rfont;
+ FT_Face ft_face;
+ MPlist *plist, *charmap_list = NULL;
+ int charmap_index;
+ int size;
+
+ if (font->size)
+ /* non-scalable font */
+ size = font->size;
+ else if (spec->size)
+ {
+ int ratio = mfont_resize_ratio (font);
+
+ size = ratio == 100 ? spec->size : spec->size * ratio / 100;
+ }
+ else
+ size = 120;
+
+ if (rfont)
+ {
+ charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
+ for (; rfont; rfont = rfont->next)
+ if (rfont->font == font
+ && (rfont->font->size ? rfont->font->size == size
+ : rfont->spec.size == size)
+ && rfont->spec.property[MFONT_REGISTRY] == reg
+ && rfont->driver == &mfont__ft_driver)
+ return rfont;
+ }
+
+ MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
+
+ if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
+ &ft_face))
+ {
+ font->type = MFONT_TYPE_FAILURE;
+ MDEBUG_PRINT (" no (FT_New_Face)\n");
+ return NULL;
+ }
+ if (charmap_list)
+ M17N_OBJECT_REF (charmap_list);
+ else
+ charmap_list = ft_get_charmaps (ft_face);
+ if (registry == Mnil)
+ registry = Municode_bmp;
+ plist = mplist_find_by_key (charmap_list, registry);
+ if (! plist)
+ {
+ FT_Done_Face (ft_face);
+ M17N_OBJECT_UNREF (charmap_list);
+ MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
+ return NULL;
+ }
+ charmap_index = (int) MPLIST_VAL (plist);
+ if ((charmap_index >= 0
+ && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
+ || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
+ {
+ FT_Done_Face (ft_face);
+ M17N_OBJECT_UNREF (charmap_list);
+ font->type = MFONT_TYPE_FAILURE;
+ MDEBUG_PRINT1 (" no (size %d)\n", size);
+ return NULL;
+ }
+
+ M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
+ ft_rfont->ft_face = ft_face;
+ ft_rfont->charmap_list = charmap_list;
+ MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
+ rfont->spec = *font;
+ rfont->spec.type = MFONT_TYPE_REALIZED;
+ rfont->spec.property[MFONT_REGISTRY] = reg;
+ rfont->spec.size = size;
+ rfont->frame = frame;
+ rfont->font = font;
+ rfont->driver = &mfont__ft_driver;
+ rfont->info = ft_rfont;
+ rfont->fontp = ft_face;
+ rfont->ascent = ft_face->size->metrics.ascender >> 6;
+ rfont->descent = - ft_face->size->metrics.descender >> 6;
+ rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
+ rfont->baseline_offset = 0;
+#ifdef HAVE_FTBDF_H
+ {
+ BDF_PropertyRec prop;
+
+ if (! FT_IS_SCALABLE (ft_face)
+ && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
+ {
+ rfont->baseline_offset = prop.u.integer;
+ rfont->ascent += prop.u.integer;
+ rfont->descent -= prop.u.integer;
+ }
+ }
+#endif /* HAVE_FTBDF_H */
+ if (FT_IS_SCALABLE (ft_face))
+ rfont->average_width = 0;
+ else
+ rfont->average_width = ft_face->available_sizes->width;
+ rfont->next = MPLIST_VAL (frame->realized_font_list);
+ MPLIST_VAL (frame->realized_font_list) = rfont;
+ MDEBUG_PRINT (" ok\n");
+ return rfont;