X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Ffont-ft.c;h=a1b24a68b5ab71f59ff0a3eedc4110329106d5a5;hb=38c091dbfa19be7db173231b0b5101577de2098e;hp=54d2d83ca02d67cacf84f781cbf5cf245cdc958a;hpb=5c40ee79cd9c203e23a9b72313caf9a2e3e8a97d;p=m17n%2Fm17n-lib.git diff --git a/src/font-ft.c b/src/font-ft.c index 54d2d83..a1b24a6 100644 --- a/src/font-ft.c +++ b/src/font-ft.c @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with the m17n library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 02111-1307, USA. */ #include "config.h" @@ -44,12 +44,14 @@ #ifdef HAVE_FREETYPE #ifdef HAVE_FTBDF_H -#include +#include FT_BDF_H #endif static int mdebug_mask = MDEBUG_FONT; #ifdef HAVE_FONTCONFIG +#include + static FcConfig *fc_config; static MSymbol Mgeneric_family; #endif /* HAVE_FONTCONFIG */ @@ -57,7 +59,7 @@ static MSymbol Mgeneric_family; /* Font properties; Mnormal is already defined in face.c. */ static MSymbol Mmedium, Mr, Mnull; -static MSymbol M0_3, M3_1, M1_0; +static MSymbol M0[5], M3_1, M1_0; static FT_Library ft_library; @@ -68,7 +70,6 @@ static OTF *invalid_otf = (OTF *) ""; typedef struct { MFont font; - MPlist *lang; #ifdef HAVE_OTF /* NULL if not yet opened. invalid_otf if not OTF. */ OTF *otf; @@ -82,8 +83,9 @@ typedef struct typedef struct { M17NObject control; - FT_Face ft_face; + FT_Face ft_face; /* This must be the 2nd member. */ MPlist *charmap_list; + int face_encapsulated; } MRealizedFontFT; typedef struct @@ -135,29 +137,38 @@ static int all_fonts_scaned; (s1) = alloca (len), (size) = len; \ for (p1 = (s1), p2 = (s2); *p2; p1++, p2++) \ *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \ - while (p1 > (s1) && p1[-1] == ' ') p1--; \ *p1 = '\0'; \ } while (0) +static MPlist *ft_list_family (MSymbol, int); + static void free_ft_rfont (void *object) { MRealizedFontFT *ft_rfont = object; - M17N_OBJECT_UNREF (ft_rfont->charmap_list); - FT_Done_Face (ft_rfont->ft_face); + if (! ft_rfont->face_encapsulated) + { + M17N_OBJECT_UNREF (ft_rfont->charmap_list); + FT_Done_Face (ft_rfont->ft_face); + } free (ft_rfont); } static void free_ft_info (MFontFT *ft_info) { - M17N_OBJECT_UNREF (ft_info->lang); #ifdef HAVE_OTF if (ft_info->otf && ft_info->otf != invalid_otf) OTF_close (ft_info->otf); #endif /* HAVE_OTF */ +#ifdef HAVE_FONTCONFIG + if (ft_info->langset) + FcLangSetDestroy (ft_info->langset); + if (ft_info->charset) + FcCharSetDestroy (ft_info->charset); +#endif /* HAVE_FONTCONFIG */ free (ft_info); } @@ -175,9 +186,9 @@ ft_get_charmaps (FT_Face ft_face) if (ft_face->charmaps[i]->platform_id == 0) { - if (ft_face->charmaps[i]->encoding_id == 3) - registry = M0_3, unicode_bmp = i; - else if (ft_face->charmaps[i]->encoding_id == 4) + if (ft_face->charmaps[i]->encoding_id <= 4) + registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i; + if (ft_face->charmaps[i]->encoding_id == 4) unicode_bmp = unicode_full = i; } else if (ft_face->charmaps[i]->platform_id == 3) @@ -224,6 +235,74 @@ ft_get_charmaps (FT_Face ft_face) return plist; } +static MFontFT * +ft_gen_font (FT_Face ft_face) +{ + MFontFT *ft_info; + MFont *font; + char *buf; + int bufsize = 0; + char *stylename; + MSymbol family; + int size; + + if (FT_IS_SCALABLE (ft_face)) + size = ft_face->size->metrics.y_ppem; + else if (ft_face->num_fixed_sizes == 0) + return NULL; + else + size = ft_face->available_sizes[0].height; + + MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT); + font = &ft_info->font; + STRDUP_LOWER (buf, bufsize, ft_face->family_name); + family = msymbol (buf); + mfont__set_property (font, MFONT_FAMILY, family); + mfont__set_property (font, MFONT_WEIGHT, Mmedium); + mfont__set_property (font, MFONT_STYLE, Mr); + mfont__set_property (font, MFONT_STRETCH, Mnormal); + mfont__set_property (font, MFONT_ADSTYLE, Mnull); + mfont__set_property (font, MFONT_REGISTRY, Municode_bmp); + font->size = size * 10; + font->type = MFONT_TYPE_OBJECT; + font->source = MFONT_SOURCE_FT; + font->file = NULL; + + stylename = ft_face->style_name; + while (*stylename) + { + int i; + + for (i = 0; i < ft_to_prop_size; i++) + if (! strncasecmp (ft_to_prop[i].ft_style, stylename, + ft_to_prop[i].len)) + { + mfont__set_property (font, ft_to_prop[i].prop, + msymbol (ft_to_prop[i].val)); + stylename += ft_to_prop[i].len; + break; + } + if (i == ft_to_prop_size) + { + char *p1 = stylename + 1; + MSymbol sym; + + while (*p1 >= 'a' && *p1 <= 'z') p1++; + sym = msymbol__with_len (stylename, p1 - stylename); + for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++) + if (msymbol_get (sym, mfont__property_table[i].property)) + { + mfont__set_property (font, i, sym); + break; + } + stylename = p1; + } + while (*stylename && ! isalpha (*stylename)) + stylename++; + } + return ft_info; +} + #ifdef HAVE_FONTCONFIG typedef struct @@ -344,7 +423,7 @@ fc_get_pattern (MFont *font) } static void -fc_parse_pattern (FcPattern *pat, char *family, MFont *font) +fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info) { FcChar8 *str; int val; @@ -353,6 +432,8 @@ fc_parse_pattern (FcPattern *pat, char *family, MFont *font) int bufsize = 0; MSymbol sym; FcLangSet *ls; + FcCharSet *cs; + MFont *font = &ft_info->font; MFONT_INIT (font); if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch) @@ -384,13 +465,14 @@ fc_parse_pattern (FcPattern *pat, char *family, MFont *font) } if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch) { - if (FcLangSetHasLang (ls, (FcChar8 *) "ja") == FcLangEqual - || FcLangSetHasLang (ls, (FcChar8 *) "zh-cn") == FcLangEqual - || FcLangSetHasLang (ls, (FcChar8 *) "zh-hk") == FcLangEqual - || FcLangSetHasLang (ls, (FcChar8 *) "zh-tw") == FcLangEqual - || FcLangSetHasLang (ls, (FcChar8 *) "ko") == FcLangEqual) + if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang + || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang + || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang) font->for_full_width = 1; + ft_info->langset = FcLangSetCopy (ls); } + if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch) + ft_info->charset = FcCharSetCopy (cs); mfont__set_property (font, MFONT_REGISTRY, Municode_bmp); font->type = MFONT_TYPE_SPEC; @@ -408,11 +490,131 @@ fc_gen_font (FcPattern *pat, char *family) MFontFT *ft_info; MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT); - fc_parse_pattern (pat, family, &ft_info->font); + fc_parse_pattern (pat, family, ft_info); ft_info->font.type = MFONT_TYPE_OBJECT; return ft_info; } +static void +fc_init_font_list (void) +{ + FcPattern *pattern = FcPatternCreate (); + FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL); + FcFontSet *fs = FcFontList (fc_config, pattern, os); + MPlist *plist = mplist (); + char *buf; + int bufsize = 0; + int i; + + ft_font_list = plist; + for (i = 0; i < fs->nfont; i++) + { + char *fam; + + if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, + (FcChar8 **) &fam) != FcResultMatch) + continue; + STRDUP_LOWER (buf, bufsize, fam); + plist = mplist_add (plist, msymbol (buf), NULL); + } + FcFontSetDestroy (fs); + FcObjectSetDestroy (os); + FcPatternDestroy (pattern); +} + +static MPlist * +fc_list_pattern (FcPattern *pattern) +{ + FcObjectSet *os = NULL; + FcFontSet *fs = NULL; + MSymbol last_family = Mnil; + MPlist *plist = NULL, *pl = NULL; + char *buf; + int bufsize = 0; + int i; + + if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL))) + goto err; + if (! (fs = FcFontList (fc_config, pattern, os))) + goto err; + + for (i = 0; i < fs->nfont; i++) + { + MSymbol family, file; + char *fam, *filename; + 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); + if (family != last_family) + { + pl = MPLIST_PLIST (ft_list_family (family, 0)); + last_family = family; + } + ft_info = mplist_get (pl, file); + if (ft_info) + { + if (! plist) + plist = mplist (); + mplist_add (plist, family, ft_info); + } + } + + err: + if (fs) FcFontSetDestroy (fs); + if (os) FcObjectSetDestroy (os); + return plist; +} + +/* Return FcCharSet object built from CHAR_LIST or MT. In the latter + case, it is assured that the M-text contains at least one + character. */ + +static FcCharSet * +fc_build_charset (MPlist *char_list, MText *mt) +{ + FcCharSet *cs = FcCharSetCreate (); + + if (! cs) + return NULL; + if (char_list) + { + for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list)) + if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list))) + { + FcCharSetDestroy (cs); + return NULL; + } + } + else + { + int i; + + for (i = mtext_nchars (mt) - 1; i >= 0; i--) + if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i))) + { + FcCharSetDestroy (cs); + return NULL; + } + if (mtext_nchars (mt) > 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))) + { + FcCharSetDestroy (cs); + return NULL; + } + } + return cs; +} + #else /* not HAVE_FONTCONFIG */ static MPlist * @@ -431,72 +633,14 @@ ft_add_font (char *filename) if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0) return NULL; - if (! FT_IS_SCALABLE (ft_face)) - { - int reject; -#ifdef HAVE_FTBDF_H - BDF_PropertyRec prop; - - reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0; - size = prop.u.integer * 10; -#else /* not HAVE_FTBDF_H */ - reject = 1; -#endif /* not HAVE_FTBDF_H */ - if (reject) - { - FT_Done_Face (ft_face); - return NULL; - } - } + ft_info = ft_gen_font (ft_face); + FT_Done_Face (ft_face); + if (! ft_info) + return NULL; - MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT); font = &ft_info->font; - STRDUP_LOWER (buf, bufsize, ft_face->family_name); - family = msymbol (buf); - mfont__set_property (font, MFONT_FAMILY, family); - mfont__set_property (font, MFONT_WEIGHT, Mmedium); - mfont__set_property (font, MFONT_STYLE, Mr); - mfont__set_property (font, MFONT_STRETCH, Mnormal); - mfont__set_property (font, MFONT_ADSTYLE, Mnull); - mfont__set_property (font, MFONT_REGISTRY, Municode_bmp); - font->type = MFONT_TYPE_OBJECT; - font->source = MFONT_SOURCE_FT; - font->size = size; font->file = msymbol (filename); - stylename = ft_face->style_name; - while (*stylename) - { - for (i = 0; i < ft_to_prop_size; i++) - if (! strncasecmp (ft_to_prop[i].ft_style, stylename, - ft_to_prop[i].len)) - { - mfont__set_property (font, ft_to_prop[i].prop, - msymbol (ft_to_prop[i].val)); - stylename += ft_to_prop[i].len; - break; - } - if (i == ft_to_prop_size) - { - char *p1 = stylename + 1; - MSymbol sym; - - while (*p1 >= 'a' && *p1 <= 'z') p1++; - sym = msymbol__with_len (stylename, p1 - stylename); - for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++) - if (msymbol_get (sym, mfont__property_table[i].property)) - { - mfont__set_property (font, i, sym); - break; - } - stylename = p1; - } - while (*stylename && ! isalpha (*stylename)) - stylename++; - } - - FT_Done_Face (ft_face); - plist = mplist_find_by_key (ft_font_list, family); if (plist) mplist_push (MPLIST_PLIST (plist), font->file, ft_info); @@ -509,6 +653,115 @@ ft_add_font (char *filename) return plist; } +static void +ft_init_font_list (void) +{ + MPlist *plist; + struct stat buf; + char *pathname; + char *path; + USE_SAFE_ALLOCA; + + ft_font_list = mplist (); + MPLIST_DO (plist, mfont_freetype_path) + if (MPLIST_STRING_P (plist) + && (pathname = MPLIST_STRING (plist)) + && stat (pathname, &buf) == 0) + { + if (S_ISREG (buf.st_mode)) + ft_add_font (pathname); + else if (S_ISDIR (buf.st_mode)) + { + DIR *dir = opendir (pathname); + + if (dir) + { + int len = strlen (pathname); + struct dirent *dp; + + while ((dp = readdir (dir)) != NULL) + { + SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2); + strcpy (path, pathname); + path[len] = '/'; + strcpy (path + len + 1, dp->d_name); + ft_add_font (path); + } + closedir (dir); + } + } + } + SAFE_FREE (path); +} + +/* Return 1 iff the font pointed by FT_INFO has all characters in + CHAR_LIST. */ + +static int +ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list) +{ + FT_Face ft_face; + MPlist *cl; + + if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face)) + return 0; + MPLIST_DO (cl, char_list) + if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0) + break; + FT_Done_Face (ft_face); + return MPLIST_TAIL_P (cl); +} + +/* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT + that supports characters in CHAR_LIST or MT. One of CHAR_LIST or + MT must be NULL. */ + +static MPlist * +ft_list_char_list (MPlist *char_list, MText *mt) +{ + MPlist *plist = NULL, *pl, *p; + + if (! ft_font_list) + ft_list_family (Mnil, 0); + + if (mt) + { + int len = mtext_nchars (mt); + MText *extra = mtext_get_prop (mt, 0, Mtext); + int total_len = len + (extra ? mtext_nchars (extra) : 0); + int i; + + char_list = mplist (); + for (i = 0; i < total_len; i++) + { + int c = (i < len ? mtext_ref_char (mt, i) + : mtext_ref_char (extra, i - len)); + + if (! mplist_find_by_value (char_list, (void *) c)) + mplist_push (char_list, Minteger, (void *) c); + } + } + + MPLIST_DO (pl, ft_font_list) + { + MPLIST_DO (p, MPLIST_PLIST (pl)) + { + MFontFT *ft_info = MPLIST_VAL (p); + + if (ft_has_char_list_p (ft_info, char_list)) + { + MSymbol family = mfont_get_prop (&ft_info->font, Mfamily); + + if (! plist) + plist = mplist (); + mplist_push (plist, family, ft_info); + } + } + } + if (mt) + M17N_OBJECT_UNREF (char_list); + return plist; +} #endif /* not HAVE_FONTCONFIG */ @@ -576,7 +829,8 @@ ft_list_family (MSymbol family, int check_generic) pattern = FcPatternCreate (); FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam); os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH, - FC_PIXEL_SIZE, FC_LANG, FC_FILE, NULL); + FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE, + NULL); fs = FcFontList (fc_config, pattern, os); p = pl = mplist (); for (i = 0; i < fs->nfont; i++) @@ -671,42 +925,7 @@ ft_list_family (MSymbol family, int check_generic) if (! all_fonts_scaned) { - MPlist *plist; - struct stat buf; - char *pathname; - char *path; - USE_SAFE_ALLOCA; - - ft_font_list = mplist (); - MPLIST_DO (plist, mfont_freetype_path) - if (MPLIST_STRING_P (plist) - && (pathname = MPLIST_STRING (plist)) - && stat (pathname, &buf) == 0) - { - if (S_ISREG (buf.st_mode)) - ft_add_font (pathname); - else if (S_ISDIR (buf.st_mode)) - { - DIR *dir = opendir (pathname); - - if (dir) - { - int len = strlen (pathname); - struct dirent *dp; - - while ((dp = readdir (dir)) != NULL) - { - SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2); - strcpy (path, pathname); - path[len] = '/'; - strcpy (path + len + 1, dp->d_name); - ft_add_font (path); - } - closedir (dir); - } - } - } - SAFE_FREE (path); + ft_init_font_list (); all_fonts_scaned = 1; } if (family == Mnil) @@ -727,185 +946,105 @@ ft_list_language (MSymbol language) { MPlist *plist = NULL; MText *mt; - int step; 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) - { - 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; + mt = mlanguage_text (language); - 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; +#ifdef HAVE_FONTCONFIG + { + FcPattern *pattern = NULL; + FcCharSet *cs = NULL; + FcLangSet *ls = NULL; - err: - if (os) - FcObjectSetDestroy (os); - if (pattern) - FcPatternDestroy (pattern); - MEMORY_FULL (MERROR_FONT_FT); - return NULL; - } + if (! (pattern = FcPatternCreate ())) + goto err; - mplist_push (ft_language_list, language, plist); - return plist; + if (mt && mtext_nchars (mt) > 0) + { + cs = fc_build_charset (NULL, mt); + if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs)) + goto err; + } + else + { + if (! (ls = FcLangSetCreate ())) + goto err; + if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language)) + || ! FcPatternAddLangSet (pattern, FC_LANG, ls)) + goto err; + } + plist = fc_list_pattern (pattern); + err: + if (cs) FcCharSetDestroy (cs); + if (ls) FcLangSetDestroy (ls); + if (pattern) FcPatternDestroy (pattern); + } #else /* not HAVE_FONTCONFIG */ - - if ((mt = msymbol_get (language, Mtext))) - { - MPlist *pl, *p; - int len = mtext_nchars (mt); - 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 (mt && mtext_nchars (mt) > 0) + plist = ft_list_char_list (NULL, mt); +#endif /* not HAVE_FONTCONFIG */ - if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), - 0, &ft_face) != 0) - continue; - for (i = 0; i < len; i++) - if (FT_Get_Char_Index (ft_face, - (FT_ULong) mtext_ref_char (mt, i)) == 0) - break; - FT_Done_Face (ft_face); - if (i < len) - continue; - if (! plist) - plist = mplist (); - family = mfont_get_prop (&ft_info->font, Mfamily); - mplist_push (plist, family, ft_info); - } - } - } + mplist_push (ft_language_list, language, plist); return plist; -#endif /* not HAVE_FONTCONFIG */ } static MPlist * ft_list_script (MSymbol script) { MPlist *plist = NULL; - MPlist *language_list, *pl; + MPlist *char_list; if (! ft_script_list) ft_script_list = mplist (); else if ((plist = mplist_find_by_key (ft_script_list, script))) return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL); - language_list = mlanguage__list (script); - MPLIST_DO (pl, language_list) + char_list = mscript__char_list (script); + +#ifdef HAVE_FONTCONFIG + if (char_list) { - MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl); - MPlist *p = ft_list_language (language); - MSymbol family; + FcPattern *pattern = NULL; + FcCharSet *cs; - if (! p) - continue; - if (! plist) - plist = mplist (); - MPLIST_DO (p, p) - { - family = MPLIST_KEY (p); - if (! mplist_find_by_value (plist, MPLIST_VAL (p))) - mplist_add (plist, family, MPLIST_VAL (p)); - } + if (! (pattern = FcPatternCreate ())) + goto err; + cs = fc_build_charset (char_list, NULL); + if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs)) + goto err; + plist = fc_list_pattern (pattern); + err: + if (cs) FcCharSetDestroy (cs); + if (pattern) FcPatternDestroy (pattern); } +#else /* not HAVE_FONTCONFIG */ + if (char_list) + plist = ft_list_char_list (char_list, NULL); +#endif /* not HAVE_FONTCONFIG */ + mplist_push (ft_script_list, script, plist); - M17N_OBJECT_UNREF (language_list); return (plist); } static int -ft_check_otf (MFontFT *ft_info, MFontCapability *cap) +ft_check_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face) { +#ifdef HAVE_OTF if (ft_info->otf == invalid_otf) return -1; if (! ft_info->otf) { - ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file)); +#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4) + if (ft_face) + ft_info->otf = OTF_open_ft_face (ft_face); + else +#endif + ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file)); if (! ft_info->otf) { ft_info->otf = invalid_otf; @@ -929,73 +1068,103 @@ ft_check_otf (MFontFT *ft_info, MFontCapability *cap) cap->features[MFONT_OTT_GPOS].nfeatures) != 1)) return -1; return 0; +#else /* not HAVE_OTF */ + return -1; +#endif /* not HAVE_OTF */ } static int -ft_check_lang (MFontFT *ft_info, MFontCapability *cap) +ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face) { -#ifdef HAVE_FONTCONFIG - MPlist *plist; MText *mt; - int i, j; + MText *extra; + int ft_face_allocaed = 0; + int len, total_len; + int i; + +#ifdef HAVE_FONTCONFIG + if (ft_info->langset + && (FcLangSetHasLang (ft_info->langset, + (FcChar8 *) MSYMBOL_NAME (language)) + != FcLangDifferentLang)) + return 0; +#endif /* HAVE_FONTCONFIG */ + + mt = mlanguage_text (language); + if (! mt || mtext_nchars (mt) == 0) + return -1; - for (i = 0; cap->lang[i] != Mnil; i++) + if (! ft_face) { - if (ft_info->lang - && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i]))) - { - if (MPLIST_VAL (plist)) - return 0; - continue; - } + char *filename = MSYMBOL_NAME (ft_info->font.file); - if (! ft_info->langset) - { - FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString, - MSYMBOL_NAME (ft_info->font.file), - NULL); - FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL); - FcFontSet *fs = FcFontList (fc_config, pat, os); + if (FT_New_Face (ft_library, filename, 0, &ft_face)) + return -1; + ft_face_allocaed = 1; + } - if (fs->nfont == 0) - return -1; - if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset) - == FcResultMatch) - ft_info->langset = FcLangSetCopy (ft_info->langset); - else - ft_info->langset = FcLangSetCreate (); - FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset); - FcFontSetDestroy (fs); - FcObjectSetDestroy (os); - FcPatternDestroy (pat); - } - if (! ft_info->lang) - ft_info->lang = mplist (); - if (FcLangSetHasLang (ft_info->langset, - (FcChar8 *) MSYMBOL_NAME (cap->lang[i])) - == FcLangEqual) - { - mplist_push (ft_info->lang, cap->lang[i], Mt); - return 0; - } + len = mtext_nchars (mt); + extra = mtext_get_prop (mt, 0, Mtext); + total_len = len + (extra ? mtext_nchars (extra) : 0); + + for (i = 0; i < total_len; i++) + { + int c = (i < len ? mtext_ref_char (mt, i) + : mtext_ref_char (extra, i - len)); + +#ifdef HAVE_FONTCONFIG + if (ft_info->charset + && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse) + break; +#endif /* HAVE_FONTCONFIG */ + if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0) + break; + } + + if (ft_face_allocaed) + FT_Done_Face (ft_face); - mt = msymbol_get (cap->lang[i], Mtext); - if (! mt) + return (i == total_len ? 0 : -1); +} + +static int +ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face) +{ + 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) { - mplist_push (ft_info->lang, cap->lang[i], Mnil); - continue; + char *filename = MSYMBOL_NAME (ft_info->font.file); + + if (FT_New_Face (ft_library, filename, 0, &ft_face)) + return -1; + ft_face_allocaed = 1; } - for (j = mtext_nchars (mt) - 1; j >= 0; j--) - if (! FcCharSetAddChar (ft_info->charset, - (FcChar32) mtext_ref_char (mt, j))) + MPLIST_DO (char_list, char_list) + if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list)) + == 0) break; - mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil)); - if (j < 0) - return 0; + if (ft_face_allocaed) + FT_Done_Face (ft_face); } -#endif /* HAVE_FONTCONFIG */ - return -1; + + return (MPLIST_TAIL_P (char_list) ? 0 : -1); } static MPlist *ft_default_list; @@ -1049,60 +1218,65 @@ ft_list_default () static MPlist *ft_capability_list; static MPlist * -ft_list_capability (MSymbol sym) +ft_list_capability (MSymbol capability) { - MPlist *plist, *pl, *p; - MFontCapability *cap = mfont__get_capability (sym); + MFontCapability *cap; + MPlist *plist = NULL, *pl; - if (! cap) - return NULL; - if (ft_capability_list) - { - plist = mplist_find_by_key (ft_capability_list, sym); - if (plist) - return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL); - } - else - { - plist = NULL; - ft_capability_list = mplist (); - } + 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); - if (cap->script != Mnil) + cap = mfont__get_capability (capability); + + if (cap && cap->language != Mnil) { - pl = ft_list_script (cap->script); - if (pl) - MPLIST_DO (pl, pl) - { - if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0) - continue; - if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0) - continue; - if (! plist) - plist = mplist (); - mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl)); - } - mplist_push (ft_capability_list, sym, plist); - return plist; + plist = ft_list_language (cap->language); + if (! plist) + return NULL; + plist = mplist_copy (plist); } - if (cap->lang) + if (cap && cap->script != Mnil) { - int i; + 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); + } + } - for (i = 0; cap->lang[i] != Mnil; i++) + if (cap->script_tag) { - p = ft_list_language (cap->lang[i]); - if (p) + for (pl = plist; ! MPLIST_TAIL_P (pl);) { - if (! plist) - plist = mplist (); - MPLIST_DO (p, p) - mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p)); + 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, sym, plist); + + mplist_push (ft_capability_list, capability, plist); return plist; } @@ -1220,8 +1394,13 @@ ft_select (MFrame *frame, MFont *font, int limited_size) for (pl = plist; ! MPLIST_TAIL_P (pl);) { - if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0) - || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)) + 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); @@ -1272,7 +1451,7 @@ ft_select (MFrame *frame, MFont *font, int limited_size) } } M17N_OBJECT_UNREF (plist); -#endif +#endif /* HAVE_FONTCONFIG */ return found; } @@ -1287,7 +1466,19 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont) FT_Face ft_face; MPlist *plist, *charmap_list = NULL; int charmap_index; - int size = font->size ? font->size : spec->size; + 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) { @@ -1301,13 +1492,13 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont) return rfont; } - MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (spec)); + 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\n"); + MDEBUG_PRINT (" no (FT_New_Face)\n"); return NULL; } if (charmap_list) @@ -1321,7 +1512,7 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont) { FT_Done_Face (ft_face); M17N_OBJECT_UNREF (charmap_list); - MDEBUG_PRINT (" no\n"); + MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry)); return NULL; } charmap_index = (int) MPLIST_VAL (plist); @@ -1332,7 +1523,7 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont) FT_Done_Face (ft_face); M17N_OBJECT_UNREF (charmap_list); font->type = MFONT_TYPE_FAILURE; - MDEBUG_PRINT (" no\n"); + MDEBUG_PRINT1 (" no (size %d)\n", size); return NULL; } @@ -1365,8 +1556,11 @@ ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont) rfont->descent -= prop.u.integer; } } -#endif - +#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"); @@ -1401,7 +1595,7 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring, { #ifdef HAVE_FTBDF_H BDF_PropertyRec prop; -#endif +#endif /* HAVE_FTBDF_H */ g->lbearing = 0; g->rbearing = g->width = ft_face->available_sizes->width; @@ -1419,7 +1613,7 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring, } } else -#endif +#endif /* HAVE_FTBDF_H */ { g->ascent = ft_face->available_sizes->height; g->descent = 0; @@ -1698,10 +1892,6 @@ ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum) if (! capability_list || MPLIST_TAIL_P (capability_list)) goto done; } - else if (family == Mnil) - { - capability_list = ft_list_default (); - } } if (! file_list && ! family_list && ! capability_list) @@ -1800,12 +1990,152 @@ ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum) return num; } +static void +ft_list_family_names (MFrame *frame, MPlist *plist) +{ + MPlist *pl; + + if (! ft_font_list) + { +#ifdef HAVE_FONTCONFIG + fc_init_font_list (); +#else /* not HAVE_FONTCONFIG */ + ft_init_font_list (); +#endif /* not HAVE_FONTCONFIG */ + } + + MPLIST_DO (pl, ft_font_list) + { + MSymbol family = MPLIST_KEY (pl); + MPlist *p; + +#ifdef HAVE_FONTCONFIG + if (msymbol_get (family, Mgeneric_family) != Mnil) + continue; +#endif /* HAVE_FONTCONFIG */ + MPLIST_DO (p, plist) + { + MSymbol sym = MPLIST_SYMBOL (p); + + if (sym == family) + break; + if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0) + { + mplist_push (p, Msymbol, family); + break; + } + } + if (MPLIST_TAIL_P (p)) + mplist_push (p, Msymbol, family); + } +} + +static int +ft_check_capability (MRealizedFont *rfont, MSymbol capability) +{ + MFontFT *ft_info = (MFontFT *) rfont->font; + MRealizedFontFT *ft_rfont = rfont->info; + MFontCapability *cap = mfont__get_capability (capability); + + if (cap->script != Mnil + && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0) + return -1; + if (cap->language != Mnil + && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0) + return -1; + if (cap->script_tag && ft_check_otf (ft_info, cap, ft_rfont->ft_face) < 0) + return -1; + return 0; +} + +static MRealizedFont * +ft_encapsulate (MFrame *frame, MSymbol data_type, void *data) +{ + MFontFT *ft_info; + MRealizedFont *rfont; + MRealizedFontFT *ft_rfont; + FT_Face ft_face; + + if (data_type == Mfontconfig) + { +#ifdef HAVE_FONTCONFIG + FcPattern *pattern = data; + + if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face) + != FcResultMatch) + return NULL; + ft_info = fc_gen_font (pattern, NULL); +#else /* not HAVE_FONTCONFIG */ + return NULL; +#endif /* not HAVE_FONTCONFIG */ + } + else if (data_type == Mfreetype) + { + ft_face = data; + ft_info = ft_gen_font (ft_face); + } + else + return NULL; + + M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT); + ft_rfont->ft_face = ft_face; + ft_rfont->face_encapsulated = 1; + + MDEBUG_DUMP (" [FONT-FT] encapsulating ", (char *) ft_face->family_name,); + + MSTRUCT_CALLOC (rfont, MERROR_FONT_FT); + rfont->font = (MFont *) ft_info; + rfont->info = ft_rfont; + rfont->fontp = ft_face; + rfont->driver = &mfont__ft_driver; + rfont->spec = ft_info->font; + rfont->spec.type = MFONT_TYPE_REALIZED; + rfont->frame = frame; + 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; + + return rfont; +} + +static void +ft_close (MRealizedFont *rfont) +{ + if (! rfont->encapsulating) + return; + free (rfont->font); + M17N_OBJECT_UNREF (rfont->info); + free (rfont); +} + + /* Internal API */ MFontDriver mfont__ft_driver = { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char, - ft_render, ft_list }; + ft_render, ft_list, ft_list_family_names, ft_check_capability, + ft_encapsulate, ft_close }; int mfont__ft_init () @@ -1822,7 +2152,11 @@ mfont__ft_init () Mr = msymbol ("r"); Mnull = msymbol (""); - M0_3 = msymbol ("0-3"); + M0[0] = msymbol ("0-0"); + M0[1] = msymbol ("0-1"); + M0[2] = msymbol ("0-2"); + M0[3] = msymbol ("0-3"); + M0[4] = msymbol ("0-4"); M3_1 = msymbol ("3-1"); M1_0 = msymbol ("1-0"); @@ -1883,6 +2217,12 @@ mfont__ft_fini () { MPlist *plist, *p; + if (ft_default_list) + { + M17N_OBJECT_UNREF (ft_default_list); + ft_default_list = NULL; + } + if (ft_font_list) { MPLIST_DO (plist, ft_font_list) @@ -1896,12 +2236,14 @@ mfont__ft_fini () M17N_OBJECT_UNREF (MPLIST_VAL (plist)); } M17N_OBJECT_UNREF (ft_font_list); + ft_font_list = NULL; if (ft_language_list) { MPLIST_DO (plist, ft_language_list) M17N_OBJECT_UNREF (MPLIST_VAL (plist)); M17N_OBJECT_UNREF (ft_language_list); + ft_language_list = NULL; } if (ft_script_list) @@ -1909,6 +2251,7 @@ mfont__ft_fini () MPLIST_DO (plist, ft_script_list) M17N_OBJECT_UNREF (MPLIST_VAL (plist)); M17N_OBJECT_UNREF (ft_script_list); + ft_script_list = NULL; } if (ft_capability_list) @@ -1916,6 +2259,7 @@ mfont__ft_fini () MPLIST_DO (plist, ft_capability_list) M17N_OBJECT_UNREF (MPLIST_VAL (plist)); M17N_OBJECT_UNREF (ft_capability_list); + ft_capability_list = NULL; } if (ft_file_list) @@ -1923,8 +2267,8 @@ mfont__ft_fini () MPLIST_DO (plist, ft_file_list) M17N_OBJECT_UNREF (MPLIST_VAL (plist)); M17N_OBJECT_UNREF (ft_file_list); + ft_file_list = NULL; } - } FT_Done_FreeType (ft_library); #ifdef HAVE_FONTCONFIG @@ -2000,7 +2344,7 @@ mfont__ft_unparse_name (MFont *font) #define DEVICE_DELTA(table, size) \ (((size) >= (table).StartSize && (size) <= (table).EndSize) \ - ? (table).DeltaValue[(size) >= (table).StartSize] \ + ? (table).DeltaValue[(size) - (table).StartSize] \ : 0) void @@ -2056,7 +2400,13 @@ mfont__ft_drive_otf (MGlyphString *gstring, int from, int to, otf = ft_info->otf; if (! otf) { + MRealizedFontFT *ft_rfont = rfont->info; + +#if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4) + otf = OTF_open_ft_face (ft_rfont->ft_face); +#else otf = OTF_open (MSYMBOL_NAME (ft_info->font.file)); +#endif if (! otf) { ft_info->otf = invalid_otf; @@ -2247,7 +2597,19 @@ mfont__ft_drive_otf (MGlyphString *gstring, int from, int to, return to; simple_copy: - ft_find_metric (rfont, gstring, from, to); + for (i = 0; i < len; i++) + { + MGlyph *g = MGLYPH (from + i); + + if (! g->otf_encoded) + { + g->code = rfont->driver->encode_char (gstring->frame, (MFont *) rfont, + NULL, g->code); + g->otf_encoded = 1; + } + } + + rfont->driver->find_metric (rfont, gstring, from, to); for (i = 0; i < len; i++) { MGlyph temp = gstring->glyphs[from + i];