X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Ffont-ft.c;h=ee3f5a203467fc854a5364b73315ed7b1f9a795d;hb=819616dacfef49aad64a7a6f7460ab26c0bfbf2b;hp=b1e092bf54c531a96028acdc37ba1eeb95e9d78e;hpb=915c58451431de16b55c0818da1dfec3d4604dba;p=m17n%2Fm17n-lib.git diff --git a/src/font-ft.c b/src/font-ft.c index b1e092b..ee3f5a2 100644 --- a/src/font-ft.c +++ b/src/font-ft.c @@ -35,56 +35,80 @@ #include "m17n-misc.h" #include "internal.h" #include "plist.h" +#include "symbol.h" #include "internal-gui.h" #include "font.h" #include "face.h" #ifdef HAVE_FREETYPE -#ifdef HAVE_OTF -#include -#endif /* HAVE_OTF */ +#ifdef HAVE_FTBDF_H +#include +#endif -#ifdef HAVE_XFT2 -/* Having Xft2 means having fontconfig. */ -#include +#ifdef HAVE_FONTCONFIG +static FcConfig *fc_config; +#endif /* HAVE_FONTCONFIG */ -int fontconfig_initialized = 0; -FcConfig *fc_config; -#endif /* not HAVE_XFT2 */ +/* Registries. */ +static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1; + +/* Font properties; Mnormal is already defined in face.c. */ +static MSymbol Mmedium, Mr, Mnull; static FT_Library ft_library; typedef struct { - MSymbol ft_style; - MSymbol weight, style, stretch; + char *ft_style; + int len; + enum MFontProperty prop; + char *val; } MFTtoProp; -static int ft_to_prop_size; -static MFTtoProp *ft_to_prop; +static MFTtoProp ft_to_prop[] = + { { "italic", 0, MFONT_STYLE, "i" }, + { "roman", 0, MFONT_STYLE, "r" }, + { "oblique", 0, MFONT_STYLE, "o" }, + { "regular", 0, MFONT_WEIGHT, "medium" }, + { "normal", 0, MFONT_WEIGHT, "medium" }, + /* We need this entry even if "bold" is in commone_weight[] to + handle such style names as "bolditalic" and "boldoblique". */ + { "bold", 0, MFONT_WEIGHT, "bold" }, + { "demi bold", 0, MFONT_WEIGHT, "demibold" }, + { "demi", 0, MFONT_WEIGHT, "demibold" } }; +static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0]; + +/** List of FreeType fonts. Keys are family names, values are plists + containing fonts of the corresponding family. In the deeper + plist, keys are Mt, values are (MFTInfo *). */ +static MPlist *ft_font_list; + +/** List of FreeType base fonts. Keys are family names, values are + (MFTInfo *). */ +static MPlist *ft_family_list; + +static int all_fonts_scaned; + +static MSymbol M_generic_family_info; + +enum GenericFamilyType { + GENERIC_FAMILY_SERIF, + GENERIC_FAMILY_SANS_SERIF, + GENERIC_FAMILY_MONOSPACE, + GENERIC_FAMILY_MAX +}; + +/** Table for each generic family. */ typedef struct { - M17NObject control; - MFont font; - char *filename; - int otf_flag; /* This font 1: is OTF, 0: may be OTF, -1: is not OTF. */ - MPlist *charmap_list; - int charmap_index; - FT_Face ft_face; -#ifdef HAVE_OTF - OTF *otf; -#endif /* HAVE_OTF */ -#ifdef HAVE_XFT2 - void *xft_info; -#endif /* not HAVE_XFT2 */ -} MFTInfo; - -/* List of FreeType fonts. Keys are family names, values are plists - contains fonts of the corresponding family. In the deeper plist, - keys are Mt, values are (MFTInfo *). */ -static MPlist *ft_font_list; + char *name; + MPlist *list; +} GenericFamilyInfo; + +static GenericFamilyInfo generic_family_table[GENERIC_FAMILY_MAX] = + { { "serif" }, { "sans-serif" }, { "monospace" } }; /** Return 0 if NAME implies TrueType or OpenType fonts. Othersize return -1. */ @@ -104,74 +128,89 @@ check_otf_filename (const char *name) return 0; } -/** Setup members of FT_INFO from FT_FACE. Return the family name. */ +#define STRDUP_LOWER(s1, size, s2) \ + do { \ + int len = strlen (s2) + 1; \ + char *p1, *p2; \ + \ + if (size < len) \ + s1 = alloca (len), size = len; \ + for (p1 = s1, p2 = s2; *p2; p1++, p2++) \ + *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \ + *p1 = *p2; \ + } while (0) + +/** Setup members of FT_INFO from FT_FACE. If the font is a base one + (i.e. medium-r-normal), set BASEP to 1. Otherwise set BASEP to 0. + Return the family name. */ static MSymbol -set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family) +set_font_info (FT_Face ft_face, MFTInfo *ft_info, + MSymbol family, MSymbol style, int *basep) { MFont *font = &ft_info->font; - MSymbol style; - int len; - char *buf, *p; MPlist *charmap_list; - int unicode_bmp = -1, unicode_full = -1; + int unicode_bmp = -1, unicode_full = -1, unicode = -1; int i; MFONT_INIT (font); - if (family == Mt) - { - len = strlen (ft_face->family_name) + 1; - buf = (char *) alloca (len); - memcpy (buf, ft_face->family_name, len); - for (p = buf; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p += 'a' - 'A'; - 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); + *basep = 1; - if (ft_face->style_name) - { - len = strlen (ft_face->style_name) + 1; - buf = (char *) alloca (len); - memcpy (buf, ft_face->style_name, len); - for (p = buf; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p += 'a' - 'A'; - style = msymbol (buf); - for (i = 0; i < ft_to_prop_size; i++) - if (ft_to_prop[i].ft_style == style) - { - mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight); - mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style); - mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch); - break; - } - } - else - i = ft_to_prop_size; - - if (i == ft_to_prop_size) + if (style != Mnull) { - mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium")); - mfont__set_property (font, MFONT_STYLE, msymbol ("r")); - mfont__set_property (font, MFONT_STRETCH, msymbol ("normal")); - } + char *p = MSYMBOL_NAME (style); - font->property[MFONT_TYPE] = MFONT_TYPE_FT + 1; - mfont__set_property (font, MFONT_ADSTYLE, msymbol ("")); + while (*p) + { + for (i = 0; i < ft_to_prop_size; i++) + if (! strncmp (ft_to_prop[i].ft_style, p, ft_to_prop[i].len)) + { + mfont__set_property (font, ft_to_prop[i].prop, + msymbol (ft_to_prop[i].val)); + p += ft_to_prop[i].len; + break; + } + if (i == ft_to_prop_size) + { + char *p1 = p + 1; + MSymbol sym; + + while (*p1 >= 'a' && *p1 <= 'z') p1++; + sym = msymbol__with_len (p, p1 - p); + for (i = MFONT_WEIGHT; i <= MFONT_STYLE; i++) + if (msymbol_get (sym, mfont__property_table[i].property)) + { + mfont__set_property (font, i, sym); + break; + } + p = p1; + } + while (*p && (*p < 'a' || *p > 'z')) p++; + } + *basep = (FONT_PROPERTY (font, MFONT_WEIGHT) == Mmedium + && FONT_PROPERTY (font, MFONT_STYLE) == Mr + && FONT_PROPERTY (font, MFONT_STRETCH) == Mnormal); + } charmap_list = mplist (); mplist_add (charmap_list, Mt, (void *) -1); for (i = 0; i < ft_face->num_charmaps; i++) { char registry_buf[16]; + MSymbol registry; sprintf (registry_buf, "%d-%d", ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id); - mplist_add (charmap_list, msymbol (registry_buf), (void *) i); + registry = msymbol (registry_buf); + mplist_add (charmap_list, registry, (void *) i); + if (ft_face->charmaps[i]->platform_id == 0) { if (ft_face->charmaps[i]->encoding_id == 3) @@ -190,218 +229,387 @@ set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family) && ft_face->charmaps[i]->encoding_id == 0) mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i); } - if (unicode_bmp >= 0) - mplist_add (charmap_list, msymbol ("unicode-bmp"), (void *) unicode_bmp); if (unicode_full >= 0) - mplist_add (charmap_list, msymbol ("unicode-full"), (void *) unicode_full); + { + mplist_add (charmap_list, Municode_full, (void *) unicode_full); + mplist_add (charmap_list, Municode_bmp, (void *) unicode_full); + mplist_add (charmap_list, Miso10646_1, (void *) unicode_full); + unicode = unicode_full; + } + else if (unicode_bmp >= 0) + { + mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp); + mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp); + unicode = unicode_bmp; + } + if (unicode >= 0) + { + FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]); + for (i = 255; i >= 32; i--) + { + if (i == 192) + i = 126; + if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0) + break; + } + if (i == 31) + mplist_add (charmap_list, Miso8859_1, (void *) unicode); + } ft_info->charmap_list = charmap_list; +#ifdef HAVE_FTBDF_H + if (! FT_IS_SCALABLE (ft_face)) + { + BDF_PropertyRec prop; + + FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop); + font->property[MFONT_SIZE] = prop.u.integer * 10; + FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop); + font->property[MFONT_RESY] = prop.u.integer; + } +#endif + return family; } static void -add_font_list (MPlist *font_list) +close_ft (void *object) +{ + MFTInfo *ft_info = object; + + if (ft_info->ft_face) + { + if (ft_info->extra_info) + M17N_OBJECT_UNREF (ft_info->extra_info); + FT_Done_Face (ft_info->ft_face); +#ifdef HAVE_OTF + if (ft_info->otf) + OTF_close (ft_info->otf); +#endif /* HAVE_OTF */ + } + free (ft_info->filename); + if (ft_info->languages) + free (ft_info->languages); + M17N_OBJECT_UNREF (ft_info->charmap_list); + free (ft_info); +} + +static void +add_font_info (char *filename, MSymbol family, void *langset, MPlist *plist) { - MPlist *plist; + FT_Face ft_face; +#ifdef HAVE_FTBDF_H + BDF_PropertyRec prop; +#endif - MPLIST_DO (plist, font_list) + if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0) { - char *filename = MPLIST_VAL (plist); - FT_Face ft_face; + char *buf; + int bufsize = 0; + MSymbol style; - if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0) + if (family == Mnil) { - if (ft_face->family_name && ((char *) ft_face->family_name)[0]) + if (ft_face->family_name) { - MSymbol family = MPLIST_KEY (plist); - MFTInfo *ft_info; - MPlist *p; - - MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT); - ft_info->filename = filename; - ft_info->otf_flag = check_otf_filename (filename); - family = set_font_info (ft_face, ft_info, family); - p = mplist_get (ft_font_list, family); - if (! p) - { - p = mplist (); - mplist_add (ft_font_list, family, p); - } - mplist_add (p, family, ft_info); + STRDUP_LOWER (buf, bufsize, ft_face->family_name); + family = msymbol (buf); + } + else + family = Mnull; + if (! (plist = mplist_get (ft_font_list, family))) + { + plist = mplist (); + mplist_add (ft_font_list, family, plist); } - FT_Done_Face (ft_face); + } + if (ft_face->style_name) + { + STRDUP_LOWER (buf, bufsize, ft_face->style_name); + style = msymbol (buf); } else - free (filename); + style = Mnull; + + if (! mplist_get (plist, style) + && (FT_IS_SCALABLE (ft_face) +#ifdef HAVE_FTBDF_H + || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0 +#endif + )) + { + int basep; + MFTInfo *ft_info; + + M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT); + ft_info->filename = strdup (filename); + ft_info->otf_flag = check_otf_filename (filename); +#ifdef HAVE_FONTCONFIG + if (langset) + ft_info->langset = FcLangSetCopy (langset); +#endif + set_font_info (ft_face, ft_info, family, style, &basep); + mplist_add (plist, style, ft_info); + + if (basep) + mplist_put (ft_family_list, family, ft_info); + else if (! mplist_get (ft_family_list, family)) + mplist_add (ft_family_list, family, ft_info); + } + FT_Done_Face (ft_face); } - M17N_OBJECT_UNREF (font_list); } -#ifdef HAVE_XFT2 +/* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil, + scan all fonts and return ft_font_list. */ static MPlist * -xft_list (MSymbol family) +ft_list_family (MSymbol family) { - FcPattern *pattern; - FcObjectSet *os; - FcFontSet *fs; - MPlist *plist; - int i; + MPlist *plist, *head; - if (! fc_config) + if (! ft_font_list) { - char *pathname; - struct stat buf; + ft_font_list = mplist (); + ft_family_list = mplist (); + } - FcInit (); - fc_config = FcConfigGetCurrent (); - MPLIST_DO (plist, mfont_freetype_path) - if (MPLIST_STRING_P (plist) - && (pathname = MPLIST_STRING (plist)) - && stat (pathname, &buf) == 0) - FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname); + if (family == Mnil) + head = ft_font_list; + else + { + head = mplist_find_by_key (ft_font_list, family); + if (head) + return head; + head = mplist_add (ft_font_list, family, mplist ()); } - pattern = FcPatternCreate (); - FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) (msymbol_name (family))); - os = FcObjectSetBuild (FC_FILE, NULL); - fs = FcFontList (fc_config, pattern, os); - plist = mplist (); - if (fs) +#ifdef HAVE_FONTCONFIG + if (! all_fonts_scaned) { + FcPattern *pattern; + FcObjectSet *os; + FcFontSet *fs; + char *buf; + int bufsize = 0; + int i; + + pattern = FcPatternCreate (); + if (family != Mnil) + { + FcPatternAddString (pattern, FC_FAMILY, + (FcChar8 *) (msymbol_name (family))); + plist = head; + os = FcObjectSetBuild (FC_FILE, FC_LANG, NULL); + } + else + { + plist = NULL; + os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL); + } + fs = FcFontList (fc_config, pattern, os); for (i = 0; i < fs->nfont; i++) { - FcChar8 *filename; + char *filename; + FcLangSet *langset; + + if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, + (FcChar8 **) &filename) != FcResultMatch) + continue; + if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0, + &langset) != FcResultMatch) + langset = NULL; + if (family == Mnil) + { + MSymbol fam; + char *fname; - FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename); - mplist_add (plist, family, strdup ((char *) filename)); + if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, + (FcChar8 **) &fname) == FcResultMatch) + { + STRDUP_LOWER (buf, bufsize, fname); + fam = msymbol (buf); + if (! plist || MPLIST_KEY (plist) != fam) + { + plist = mplist_find_by_key (ft_font_list, fam); + if (! plist) + plist = mplist_add (ft_font_list, fam, mplist ()); + } + add_font_info (filename, fam, langset, MPLIST_PLIST (plist)); + } + } + else + add_font_info (filename, family, langset, MPLIST_PLIST (plist)); } + FcFontSetDestroy (fs); + FcObjectSetDestroy (os); + FcPatternDestroy (pattern); + all_fonts_scaned = family == Mnil; } - FcObjectSetDestroy (os); - FcPatternDestroy (pattern); - return plist; -} -#else /* not HAVE_XFT2 */ -static MPlist * -ft_list () -{ - MPlist *font_list = mplist (), *plist; - struct stat buf; - char *pathname; - - 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)) - mplist_add (font_list, Mt, strdup (pathname)); - else if (S_ISDIR (buf.st_mode)) - { - int len = strlen (pathname); - char path[PATH_MAX]; - DIR *dir = opendir (pathname); - struct dirent *dp; +#else /* not HAVE_FONTCONFIG */ + + if (! all_fonts_scaned) + { + struct stat buf; + char *pathname; - if (dir) + 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)) + add_font_info (pathname, Mnil, NULL, NULL); + else if (S_ISDIR (buf.st_mode)) { - strcpy (path, pathname); - strcpy (path + len, "/"); - len++; - while ((dp = readdir (dir)) != NULL) + int len = strlen (pathname); + char path[PATH_MAX]; + DIR *dir = opendir (pathname); + struct dirent *dp; + + if (dir) { - strcpy (path + len, dp->d_name); - mplist_add (font_list, Mt, strdup (path)); + strcpy (path, pathname); + strcpy (path + len, "/"); + len++; + while ((dp = readdir (dir)) != NULL) + { + strcpy (path + len, dp->d_name); + add_font_info (path, Mnil, NULL, NULL); + } + closedir (dir); } - closedir (dir); } } - } - return font_list; + all_fonts_scaned = 1; + } + +#endif /* not HAVE_FONTCONFIG */ + + return head; } -#endif +static MPlist * +ft_list_generic (MSymbol generic) +{ +#ifdef HAVE_FONTCONFIG + GenericFamilyInfo *info = msymbol_get (generic, M_generic_family_info); + FcPattern *pattern; -static MRealizedFont *ft_select (MFrame *, MFont *, MFont *, int); -static int ft_open (MRealizedFont *); -static void ft_close (MRealizedFont *); -static void ft_find_metric (MRealizedFont *, MGlyphString *, int, int); -static unsigned ft_encode_char (MRealizedFont *, int, unsigned); -static void ft_render (MDrawWindow, int, int, MGlyphString *, - MGlyph *, MGlyph *, int, MDrawRegion); + if (! info) + return NULL; + if (info->list) + return info->list; -MFontDriver ft_driver = - { ft_select, ft_open, ft_close, - ft_find_metric, ft_encode_char, ft_render }; + info->list = mplist (); + pattern = FcPatternCreate (); + FcPatternAddString (pattern, FC_FAMILY, + (FcChar8 *) info->name); + if (FcConfigSubstitute (fc_config, pattern, FcMatchPattern) == FcTrue) + { + int i = 0; + char *family, *buf; + int bufsize = 0; + + while (FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &family) + == FcResultMatch) + { + MPlist *plist; -/* The FreeType font driver function LIST. */ + STRDUP_LOWER (buf, bufsize, family); + plist = ft_list_family (msymbol (buf)); + mplist_add (info->list, MPLIST_KEY (plist), MPLIST_VAL (plist)); + i++; + } + } + return info->list; +#else /* not HAVE_FONTCONFIG */ + return NULL; +#endif /* not HAVE_FONTCONFIG */ +} + + +/* The FreeType font driver function SELECT. */ static MRealizedFont * ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size) { - MPlist *plist; + MPlist *plist, *pl, *p; MFTInfo *best_font; int best_score; MRealizedFont *rfont; - MSymbol family, registry; + MSymbol registry, family; + unsigned short spec_family_id, request_family_id; - best_font = NULL; - best_score = 0; - family = FONT_PROPERTY (spec, MFONT_FAMILY); - if (family == Mnil) - family = FONT_PROPERTY (request, MFONT_FAMILY); - if (family == Mnil) - return NULL; registry = FONT_PROPERTY (spec, MFONT_REGISTRY); if (registry == Mnil) registry = Mt; + family = FONT_PROPERTY (spec, MFONT_FAMILY); + spec_family_id = spec->property[MFONT_FAMILY]; + request_family_id = request->property[MFONT_FAMILY]; -#ifdef HAVE_XFT2 - if (! ft_font_list) - ft_font_list = mplist (); - plist = mplist_get (ft_font_list, family); - if (! plist) + if (spec_family_id) { - add_font_list (xft_list (family)); - plist = mplist_get (ft_font_list, family); - if (! plist) - mplist_add (ft_font_list, family, plist = mplist ()); + plist = ft_list_generic (family); + if (plist) + { + family = Mnil; + spec->property[MFONT_FAMILY] = 0; + if (spec_family_id == request_family_id) + request->property[MFONT_FAMILY] = 0; + } + else + { + if (request_family_id + && (plist + = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY))) + && mplist_get (plist, family)) + request->property[MFONT_FAMILY] = 0; + plist = ft_list_family (family); + } } -#else /* not HAVE_XFT2 */ - if (! ft_font_list) + else { - ft_font_list = mplist (); - add_font_list (ft_list ()); + if (request_family_id + && (plist = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY)))) + request->property[MFONT_FAMILY] = 0; + else + plist = ft_list_family (FONT_PROPERTY (request, MFONT_FAMILY)); } - plist = mplist_get (ft_font_list, family); - if (! plist) - return NULL; -#endif /* not HAVE_XFT2 */ - - MPLIST_DO (plist, plist) - { - MFTInfo *ft_info = MPLIST_VAL (plist); - MPlist *p = mplist_find_by_key (ft_info->charmap_list, registry); - int score; - - if (! p) - continue; - /* We always ignore FOUNDRY. */ - ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY]; - score = mfont__score (&ft_info->font, spec, request, limited_size); - if (score >= 0 - && (! best_font - || best_score > score)) + + best_font = NULL; + best_score = -1; + MPLIST_DO (pl, plist) + { + MPLIST_DO (p, MPLIST_VAL (pl)) { - best_font = ft_info; - best_score = score; - if (score == 0) - break; + MFTInfo *ft_info = MPLIST_VAL (p); + int score; + + if (! mplist_find_by_key (ft_info->charmap_list, registry)) + continue; + + /* Always ignore FOUNDRY. */ + ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY]; + score = mfont__score (&ft_info->font, spec, request, limited_size); + if (score >= 0 + && (! best_font + || best_score > score)) + { + best_font = ft_info; + best_score = score; + if (best_score == 0) + break; + } } + if (best_score == 0 || family != Mnil) + break; } + spec->property[MFONT_FAMILY] = spec_family_id; + request->property[MFONT_FAMILY] = request_family_id; if (! best_font) return NULL; @@ -414,43 +622,28 @@ ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size) rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY]; rfont->score = best_score; rfont->info = best_font; - rfont->driver = &ft_driver; + M17N_OBJECT_REF (best_font); return rfont; } -static void -close_ft (void *object) -{ - MFTInfo *ft_info = (MFTInfo *) object; - - if (ft_info->ft_face) - FT_Done_Face (ft_info->ft_face); -#ifdef HAVE_XFT2 - if (ft_info->xft_info) - mwin__xft_close (ft_info->xft_info); -#endif /* HAVE_XFT2 */ -#ifdef HAVE_OTF - if (ft_info->otf) - OTF_close (ft_info->otf); -#endif /* HAVE_OTF */ - free (object); -} /* The FreeType font driver function OPEN. */ static int ft_open (MRealizedFont *rfont) { - MFTInfo *ft_info; + MFTInfo *base = rfont->info, *ft_info; MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY); int mdebug_mask = MDEBUG_FONT; int size; M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT); - ft_info->font = ((MFTInfo *) rfont->info)->font; - ft_info->otf_flag = ((MFTInfo *) rfont->info)->otf_flag; - ft_info->filename = ((MFTInfo *) rfont->info)->filename; - ft_info->charmap_list = ((MFTInfo *) rfont->info)->charmap_list; + ft_info->font = base->font; + ft_info->filename = strdup (base->filename); + ft_info->otf_flag = base->otf_flag; + ft_info->charmap_list = base->charmap_list; + M17N_OBJECT_REF (ft_info->charmap_list); + M17N_OBJECT_UNREF (base); rfont->info = ft_info; rfont->status = -1; @@ -466,34 +659,28 @@ ft_open (MRealizedFont *rfont) ft_info->ft_face->charmaps[ft_info->charmap_index])) goto err; size = rfont->font.property[MFONT_SIZE] / 10; -#ifdef HAVE_XFT2 - ft_info->xft_info = mwin__xft_open (rfont->frame, ft_info->filename, size); - if (! ft_info->xft_info) - goto err; -#else /* not HAVE_XFT2 */ if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size)) goto err; -#endif /* not HAVE_XFT2 */ MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename); rfont->status = 1; - rfont->ascent = ft_info->ft_face->ascender >> 6; - rfont->descent = ft_info->ft_face->descender >> 6; + rfont->ascent = ft_info->ft_face->size->metrics.ascender >> 6; + rfont->descent = - (ft_info->ft_face->size->metrics.descender >> 6); + rfont->type = Mfreetype; + rfont->fontp = ft_info->ft_face; return 0; err: MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename); + if (ft_info->ft_face) + FT_Done_Face (ft_info->ft_face); + M17N_OBJECT_UNREF (ft_info->charmap_list); + free (ft_info->filename); + free (ft_info); + rfont->info = NULL; return -1; } -/* The FreeType font driver function CLOSE. */ - -static void -ft_close (MRealizedFont *rfont) -{ - M17N_OBJECT_UNREF (rfont->info); -} - /* The FreeType font driver function FIND_METRIC. */ static void @@ -503,51 +690,56 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring, MFTInfo *ft_info = (MFTInfo *) rfont->info; FT_Face ft_face = ft_info->ft_face; MGlyph *g = MGLYPH (from), *gend = MGLYPH (to); - FT_Int32 load_flags = FT_LOAD_RENDER; - - if (! gstring->anti_alias) - { -#ifdef FT_LOAD_TARGET_MONO - load_flags |= FT_LOAD_TARGET_MONO; -#else - load_flags |= FT_LOAD_MONOCHROME; -#endif - } for (; g != gend; g++) { if (g->code == MCHAR_INVALID_CODE) { - unsigned unitsPerEm = ft_face->units_per_EM; - int size = rfont->font.property[MFONT_SIZE] / 10; - - g->lbearing = 0; - g->rbearing = ft_face->max_advance_width * size / unitsPerEm; - g->width = ft_face->max_advance_width * size / unitsPerEm; - g->ascent = ft_face->ascender * size / unitsPerEm; - g->descent = (- ft_face->descender) * size / unitsPerEm; + if (FT_IS_SCALABLE (ft_face)) + { + unsigned unitsPerEm = ft_face->units_per_EM; + int size = rfont->font.property[MFONT_SIZE] / 10; + + g->lbearing = 0; + g->rbearing = ft_face->max_advance_width * size / unitsPerEm; + g->width = ft_face->max_advance_width * size / unitsPerEm; + g->ascent = ft_face->ascender * size / unitsPerEm; + g->descent = (- ft_face->descender) * size / unitsPerEm; + } + else + { +#ifdef HAVE_FTBDF_H + BDF_PropertyRec prop; +#endif + + g->lbearing = 0; + g->rbearing = g->width = ft_face->available_sizes->width; +#ifdef HAVE_FTBDF_H + if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0) + { + g->ascent = prop.u.integer; + FT_Get_BDF_Property (ft_face, "DESCENT", &prop); + g->descent = prop.u.integer; + } + else +#endif + { + g->ascent = ft_face->available_sizes->height; + g->descent = 0; + } + } } else { -#ifdef HAVE_XFT2 - mwin__xft_get_metric (ft_info->xft_info, ft_info->ft_face, g); -#else /* not HAVE_XFT2 */ FT_Glyph_Metrics *metrics; - FT_UInt code; - if (g->otf_encoded) - code = g->code; - else - code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code); - - FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER); + FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT); metrics = &ft_face->glyph->metrics; g->lbearing = (metrics->horiBearingX >> 6); g->rbearing = (metrics->horiBearingX + metrics->width) >> 6; g->width = metrics->horiAdvance >> 6; g->ascent = metrics->horiBearingY >> 6; g->descent = (metrics->height - metrics->horiBearingY) >> 6; -#endif /* not HAVE_XFT2 */ } } } @@ -555,21 +747,20 @@ ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring, /* The FreeType font driver function ENCODE_CHAR. */ static unsigned -ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored) +ft_encode_char (MRealizedFont *rfont, unsigned code) { MFTInfo *ft_info; - FT_UInt code; if (rfont->status == 0) { - if (ft_open (rfont) < 0) + if ((rfont->driver->open) (rfont) < 0) return -1; } ft_info = (MFTInfo *) rfont->info; - code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c); + code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code); if (! code) return MCHAR_INVALID_CODE; - return ((unsigned) c); + return (code); } @@ -590,13 +781,11 @@ ft_render (MDrawWindow win, int x, int y, MFTInfo *ft_info; FT_Face ft_face; MRealizedFace *rface = from->rface; -#ifndef HAVE_XFT2 MFrame *frame = rface->frame; FT_Int32 load_flags = FT_LOAD_RENDER; MGlyph *g; int i, j; MPointTable point_table[8]; -#endif /* not HAVE_XFT2 */ if (from == to) return; @@ -606,10 +795,6 @@ ft_render (MDrawWindow win, int x, int y, ft_info = (MFTInfo *) rface->rfont->info; ft_face = ft_info->ft_face; -#ifdef HAVE_XFT2 - mwin__xft_render (win, x, y, gstring, from, to, reverse, region, - ft_info->xft_info, ft_face); -#else /* not HAVE_XFT2 */ if (! gstring->anti_alias) { #ifdef FT_LOAD_TARGET_MONO @@ -624,23 +809,21 @@ ft_render (MDrawWindow win, int x, int y, for (g = from; g < to; x += g++->width) { - FT_UInt code; unsigned char *bmp; int intensity; MPointTable *ptable; int xoff, yoff; - int width; + int width, pitch; - if (g->otf_encoded) - code = g->code; - else - code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code); - FT_Load_Glyph (ft_face, code, load_flags); + FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags); yoff = y - ft_face->glyph->bitmap_top + g->yoff; bmp = ft_face->glyph->bitmap.buffer; width = ft_face->glyph->bitmap.width; - if (ft_face->glyph->bitmap.pitch < ft_face->glyph->bitmap.width) - width = ft_face->glyph->bitmap.pitch; + pitch = ft_face->glyph->bitmap.pitch; + if (! gstring->anti_alias) + pitch *= 8; + if (width > pitch) + width = pitch; if (gstring->anti_alias) for (i = 0; i < ft_face->glyph->bitmap.rows; @@ -658,9 +841,10 @@ ft_render (MDrawWindow win, int x, int y, ptable->p++; if (ptable->p - ptable->points == NUM_POINTS) { - mwin__draw_points (frame, win, rface, - reverse ? 7 - intensity : intensity, - ptable->points, NUM_POINTS, region); + (*frame->driver->draw_points) + (frame, win, rface, + reverse ? 7 - intensity : intensity, + ptable->points, NUM_POINTS, region); ptable->p = ptable->points; } } @@ -682,7 +866,7 @@ ft_render (MDrawWindow win, int x, int y, ptable->p++; if (ptable->p - ptable->points == NUM_POINTS) { - mwin__draw_points (frame, win, rface, + (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7, ptable->points, NUM_POINTS, region); ptable->p = ptable->points; @@ -696,57 +880,149 @@ ft_render (MDrawWindow win, int x, int y, { for (i = 1; i < 8; i++) if (point_table[i].p != point_table[i].points) - mwin__draw_points (frame, win, rface, reverse ? 7 - i : i, + (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i, point_table[i].points, point_table[i].p - point_table[i].points, region); } else { if (point_table[0].p != point_table[0].points) - mwin__draw_points (frame, win, rface, reverse ? 0 : 7, + (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7, point_table[0].points, point_table[0].p - point_table[0].points, region); } -#endif /* not HAVE_XFT2 */ +} + +static int +ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language, + int maxnum) +{ + MPlist *pl, *p; +#ifdef HAVE_FONTCONFIG + FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language) + : NULL); +#endif + int num = 0; + + if (font) + { + MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY); + pl = ft_list_generic (family); + if (pl) + family = Mnil; + else + pl = ft_list_family (family); + MPLIST_DO (pl, pl) + { + MPLIST_DO (p, MPLIST_PLIST (pl)) + { + MFTInfo *ft_info = MPLIST_VAL (p); + +#ifdef HAVE_FONTCONFIG + if (lang && ft_info->langset + && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual) + continue; +#endif + mplist_add (plist, MPLIST_KEY (pl), &ft_info->font); + num++; + if (num == maxnum) + return num; + } + if (family != Mnil) + break; + } + } + else + { + ft_list_family (Mnil); + MPLIST_DO (p, ft_family_list) + { + MFTInfo *ft_info = MPLIST_VAL (p); + +#ifdef HAVE_FONTCONFIG + if (lang && ft_info->langset + && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual) + continue; +#endif + mplist_add (plist, MPLIST_KEY (p), &ft_info->font); + num++; + if (num == maxnum) + break; + } + } + return num; } +/* Internal API */ + +MFontDriver mfont__ft_driver = + { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list }; int mfont__ft_init () { - struct { - char *ft_style; - char *weight, *style, *stretch; - } ft_to_prop_name[] = - { { "regular", "medium", "r", "normal" }, - { "italic", "medium", "i", "normal" }, - { "bold", "bold", "r", "normal" }, - { "bold italic", "bold", "i", "normal" }, - { "narrow", "medium", "r", "condensed" }, - { "narrow italic", "medium", "i", "condensed" }, - { "narrow bold", "bold", "r", "condensed" }, - { "narrow bold italic", "bold", "i", "condensed" }, - { "black", "black", "r", "normal" }, - { "black italic", "black", "i", "normal" }, - { "oblique", "medium", "o", "normal" }, - { "boldoblique", "bold", "o", "normal" } }; int i; if (FT_Init_FreeType (&ft_library) != 0) MERROR (MERROR_FONT_FT, -1); - ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]); - MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT); for (i = 0; i < ft_to_prop_size; i++) + ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style); + + Municode_bmp = msymbol ("unicode-bmp"); + Municode_full = msymbol ("unicode-full"); + Miso10646_1 = msymbol ("iso10646-1"); + Miso8859_1 = msymbol ("iso8859-1"); + + Mmedium = msymbol ("medium"); + Mr = msymbol ("r"); + Mnull = msymbol (""); + + for (i = 0; i < GENERIC_FAMILY_MAX; i++) + generic_family_table[i].list = NULL; + M_generic_family_info = msymbol (" generic_family_info"); + msymbol_put (msymbol ("serif"), M_generic_family_info, + generic_family_table + GENERIC_FAMILY_SERIF); + msymbol_put (msymbol ("sans-serif"), M_generic_family_info, + generic_family_table + GENERIC_FAMILY_SANS_SERIF); + msymbol_put (msymbol ("sans"), M_generic_family_info, + generic_family_table + GENERIC_FAMILY_SANS_SERIF); + msymbol_put (msymbol ("sans serif"), M_generic_family_info, + generic_family_table + GENERIC_FAMILY_SANS_SERIF); + msymbol_put (msymbol ("monospace"), M_generic_family_info, + generic_family_table + GENERIC_FAMILY_MONOSPACE); + msymbol_put (msymbol ("mono"), M_generic_family_info, + generic_family_table + GENERIC_FAMILY_MONOSPACE); + msymbol_put (msymbol ("m"), M_generic_family_info, + generic_family_table + GENERIC_FAMILY_MONOSPACE); + +#ifdef HAVE_FONTCONFIG + if (! fc_config) { - ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style); - ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight); - ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style); - ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch); - } + char *pathname; + struct stat buf; + MPlist *plist; - mfont__driver_list[MFONT_TYPE_FT] = &ft_driver; + FcInit (); + fc_config = FcConfigGetCurrent (); + MPLIST_DO (plist, mfont_freetype_path) + if (MPLIST_STRING_P (plist) + && (pathname = MPLIST_STRING (plist)) + && stat (pathname, &buf) == 0) + { + FcStrList *strlist = FcConfigGetFontDirs (fc_config); + FcChar8 *dir; + + while ((dir = FcStrListNext (strlist))) + if (strcmp ((char *) dir, pathname) == 0) + break; + if (! dir) + FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname); + FcStrListDone (strlist); + } + } +#endif return 0; } @@ -755,95 +1031,239 @@ void mfont__ft_fini () { MPlist *plist, *p; + int i; + for (i = 0; i < GENERIC_FAMILY_MAX; i++) + if (generic_family_table[i].list) + M17N_OBJECT_UNREF (generic_family_table[i].list); if (ft_font_list) { MPLIST_DO (plist, ft_font_list) { MPLIST_DO (p, MPLIST_VAL (plist)) { - MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (p); - free (ft_info->filename); - M17N_OBJECT_UNREF (ft_info->charmap_list); - free (ft_info); + MFTInfo *ft_info = MPLIST_VAL (p); + + M17N_OBJECT_UNREF (ft_info); } M17N_OBJECT_UNREF (MPLIST_VAL (plist)); } M17N_OBJECT_UNREF (ft_font_list); ft_font_list = NULL; + + M17N_OBJECT_UNREF (ft_family_list); + ft_family_list = NULL; } - free (ft_to_prop); FT_Done_FreeType (ft_library); + all_fonts_scaned = 0; +} + + +#ifdef HAVE_FONTCONFIG +typedef struct +{ + int fc_value; + char *m17n_value; +} FC_vs_M17N_font_prop; + +static FC_vs_M17N_font_prop fc_weight_table[] = + { { FC_WEIGHT_ULTRALIGHT, "extralight" }, + { FC_WEIGHT_LIGHT, "light" }, + { FC_WEIGHT_NORMAL, "normal" }, + { FC_WEIGHT_MEDIUM, "medium" }, + { FC_WEIGHT_DEMIBOLD, "demibold" }, + { FC_WEIGHT_EXTRABOLD, "extrabold" }, + { FC_WEIGHT_BLACK, "black" }, + { FC_WEIGHT_MEDIUM, NULL } }; + +static FC_vs_M17N_font_prop fc_slant_table[] = + { { FC_SLANT_ROMAN, "r" }, + { FC_SLANT_ITALIC, "i" }, + { FC_SLANT_OBLIQUE, "o" }, + { FC_SLANT_ROMAN, NULL } }; + +static FC_vs_M17N_font_prop fc_width_table[] = + { { FC_WIDTH_CONDENSED, "condensed" }, + { FC_WIDTH_SEMIEXPANDED, "semicondensed" }, + { FC_WIDTH_NORMAL, "normal" }, + { FC_WIDTH_SEMIEXPANDED, "semiexpanded" }, + { FC_WIDTH_EXPANDED, "expanded" }, + { FC_WIDTH_NORMAL, NULL } }; + + +static MSymbol +fc_decode_prop (int val, FC_vs_M17N_font_prop *table) +{ + int i; + + for (i = 0; table[i].m17n_value; i++) + if (val <= table[i].fc_value) + return msymbol (table[i].m17n_value); + return msymbol (table[i - 1].m17n_value); } +static int +fc_encode_prop (char *name, FC_vs_M17N_font_prop *table) +{ + int i; + + for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++); + return table[i].fc_value; +} + +int +mfont__ft_parse_name (char *name, MFont *font) +{ + FcPattern *pat = FcNameParse ((FcChar8 *) name); + FcChar8 *str; + int val; + double size; + + if (! pat) + return -1; + if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch) + mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str)); + if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch) + mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str)); + if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch) + mfont__set_property (font, MFONT_WEIGHT, + fc_decode_prop (val, fc_weight_table)); + if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch) + mfont__set_property (font, MFONT_STYLE, + fc_decode_prop (val, fc_slant_table)); + if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch) + mfont__set_property (font, MFONT_STRETCH, + fc_decode_prop (val, fc_width_table)); + if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch) + font->property[MFONT_SIZE] = size * 10; + FcPatternDestroy (pat); + return 0; +} + +char * +mfont__ft_unparse_name (MFont *font) +{ + FcPattern *pat = FcPatternCreate (); + MSymbol sym, weight, style, stretch; + char *name; + + if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil) + FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym)); + if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil) + FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym)); + if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil) + FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight), + fc_weight_table)); + if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil) + FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style), + fc_slant_table)); + if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil) + FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch), + fc_width_table)); + name = (char *) FcNameUnparse (pat); + FcPatternDestroy (pat); + return name; +} +#endif /* HAVE_FONTCONFIG */ + + +#ifdef HAVE_OTF + +#define DEVICE_DELTA(table, size) \ + (((size) >= (table).StartSize && (size) <= (table).EndSize) \ + ? (table).DeltaValue[(size) >= (table).StartSize] \ + : 0) + +void +adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face, + unsigned code, int size, int *x, int *y) +{ + if (anchor->AnchorFormat == 2) + { + FT_Outline *outline; + int ap = anchor->f.f1.AnchorPoint; + + FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME); + outline = &ft_face->glyph->outline; + if (ap < outline->n_points) + { + *x = outline->points[ap].x; + *y = outline->points[ap].y; + } + } + else if (anchor->AnchorFormat == 3) + { + *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size); + *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size); + } +} int mfont__ft_drive_otf (MGlyphString *gstring, int from, int to, - MRealizedFont *rfont, - MSymbol script, MSymbol langsys, + MSymbol script, MSymbol langsys, MSymbol gsub_features, MSymbol gpos_features) { int len = to - from; - MGlyph g; - int i; -#ifdef HAVE_OTF + MGlyph *g = MGLYPH (from); + int i, gidx; + MRealizedFont *rfont; MFTInfo *ft_info; OTF *otf; OTF_GlyphString otf_gstring; OTF_Glyph *otfg; char *script_name, *language_name; char *gsub_feature_names, *gpos_feature_names; - int from_pos, to_pos; - int unitsPerEm; + int need_cmap; if (len == 0) return from; - ft_info = (MFTInfo *) rfont->info; + rfont = g->rface->rfont; + ft_info = rfont->info; if (ft_info->otf_flag < 0) goto simple_copy; otf = ft_info->otf; - if (! otf && (otf = OTF_open (ft_info->filename))) + if (! otf) { - if (OTF_get_table (otf, "head") < 0 - || (OTF_check_table (otf, "GSUB") < 0 - && OTF_check_table (otf, "GPOS") < 0)) + otf = OTF_open (ft_info->filename); + if (otf && OTF_get_table (otf, "head") < 0) { OTF_close (otf); + otf = NULL; + } + if (! otf) + { ft_info->otf_flag = -1; - ft_info->otf = NULL; goto simple_copy; } ft_info->otf = otf; } - script_name = msymbol_name (script); - language_name = langsys != Mnil ? msymbol_name (langsys) : NULL; + if (script != Mnil) + script_name = msymbol_name (script); + else + script_name = NULL; + if (langsys != Mnil) + language_name = msymbol_name (langsys); + else + language_name = NULL; gsub_feature_names = (gsub_features == Mt ? "*" : gsub_features == Mnil ? NULL : msymbol_name (gsub_features)); + if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0) + gsub_feature_names = NULL; gpos_feature_names = (gpos_features == Mt ? "*" : gpos_features == Mnil ? NULL : msymbol_name (gpos_features)); + if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0) + gpos_feature_names = NULL; - g = gstring->glyphs[from]; - from_pos = g.pos; - to_pos = g.to; - for (i = from + 1; i < to; i++) - { - if (from_pos > gstring->glyphs[i].pos) - from_pos = gstring->glyphs[i].pos; - if (to_pos < gstring->glyphs[i].to) - to_pos = gstring->glyphs[i].to; - } - - unitsPerEm = otf->head->unitsPerEm; otf_gstring.size = otf_gstring.used = len; - otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len); + otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len); memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len); - for (i = 0; i < len; i++) + for (i = 0, need_cmap = 0; i < len; i++) { if (gstring->glyphs[from + i].otf_encoded) { @@ -853,109 +1273,164 @@ mfont__ft_drive_otf (MGlyphString *gstring, int from, int to, else { otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code; + need_cmap++; } } - - if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name, - gsub_feature_names, gpos_feature_names) < 0) + if (need_cmap + && OTF_drive_cmap (otf, &otf_gstring) < 0) goto simple_copy; - g.pos = from_pos; - g.to = to_pos; - for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++) + + OTF_drive_gdef (otf, &otf_gstring); + gidx = gstring->used; + + if (gsub_feature_names) + { + if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name, + gsub_feature_names) < 0) + goto simple_copy; + for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++) + { + MGlyph temp = *(MGLYPH (from + otfg->f.index.from)); + + temp.c = otfg->c; + temp.combining_code = 0; + if (otfg->glyph_id) + { + temp.code = otfg->glyph_id; + temp.otf_encoded = 1; + } + else + { + temp.code = temp.c; + temp.otf_encoded = 0; + } + temp.to = MGLYPH (from + otfg->f.index.to)->to; + MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF); + } + } + else + for (i = 0; i < len; i++) + { + MGlyph temp = gstring->glyphs[from + i]; + + if (otf_gstring.glyphs[i].glyph_id) + { + temp.code = otf_gstring.glyphs[i].glyph_id; + temp.otf_encoded = 1; + } + MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF); + } + + ft_find_metric (rfont, gstring, gidx, gstring->used); + + if (gpos_feature_names) { - g.combining_code = 0; - g.c = otfg->c; - if (otfg->glyph_id) + int u; + int size10, size; + MGlyph *base = NULL, *mark = NULL; + + if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name, + gpos_feature_names) < 0) + return to; + + u = otf->head->unitsPerEm; + size10 = rfont->font.property[MFONT_SIZE]; + size = size10 / 10; + + for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx); + i < otf_gstring.used; i++, otfg++, g++) { - g.code = otfg->glyph_id; + MGlyph *prev; + + if (! otfg->glyph_id) + continue; switch (otfg->positioning_type) { + case 0: + break; case 1: case 2: { - int off_x = 128, off_y = 128; - - if (otfg->f.f1.format & OTF_XPlacement) - off_x = ((double) (otfg->f.f1.value->XPlacement) - * 100 / unitsPerEm + 128); - if (otfg->f.f1.format & OTF_YPlacement) - off_y = ((double) (otfg->f.f1.value->YPlacement) - * 100 / unitsPerEm + 128); - g.combining_code - = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x); - if ((otfg->f.f1.format & OTF_XAdvance) - || (otfg->f.f1.format & OTF_YAdvance)) - off_y--; + int format = otfg->f.f1.format; + + if (format & OTF_XPlacement) + g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10; + if (format & OTF_XPlaDevice) + g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size); + if (format & OTF_YPlacement) + g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10); + if (format & OTF_YPlaDevice) + g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size); + if (format & OTF_XAdvance) + g->width += otfg->f.f1.value->XAdvance * size10 / u / 10; + if (format & OTF_XAdvDevice) + g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size); } break; case 3: /* Not yet supported. */ break; - case 4: + case 4: case 5: + if (! base) + break; + prev = base; + goto label_adjust_anchor; + default: /* i.e. case 6 */ + if (! mark) + break; + prev = mark; + + label_adjust_anchor: { - int off_x, off_y; - - off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate - - otfg->f.f4.mark_anchor->XCoordinate) - * 100 / unitsPerEm + 128); - off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate - - otfg->f.f4.mark_anchor->YCoordinate) - * 100 / unitsPerEm + 128); - g.combining_code - = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x); + int base_x, base_y, mark_x, mark_y; + + base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10; + base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10; + mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10; + mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10; + + if (otfg->f.f4.base_anchor->AnchorFormat != 1) + adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face, + prev->code, size, &base_x, &base_y); + if (otfg->f.f4.mark_anchor->AnchorFormat != 1) + adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face, + g->code, size, &mark_x, &mark_y); + g->xoff = prev->xoff + (base_x - prev->width) - mark_x; + g->yoff = prev->yoff + mark_y - base_y; + g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE (); } - break; - case 5: - /* Not yet supported. */ - break; - default: /* i.e case 6 */ - /* Not yet supported. */ - break; } - g.otf_encoded = 1; - } - else - { - g.code = otfg->c; - g.otf_encoded = 0; + if (otfg->GlyphClass == OTF_GlyphClass0) + base = mark = g; + else if (otfg->GlyphClass == OTF_GlyphClassMark) + mark = g; + else + base = g; } - MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF); } + free (otf_gstring.glyphs); return to; simple_copy: -#endif /* HAVE_OTF */ + ft_find_metric (rfont, gstring, from, to); for (i = 0; i < len; i++) { - g = gstring->glyphs[from + i]; - MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF); + MGlyph temp = gstring->glyphs[from + i]; + MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF); } + free (otf_gstring.glyphs); return to; } + int mfont__ft_decode_otf (MGlyph *g) { -#ifdef HAVE_OTF MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info; int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code); return (c ? c : -1); -#else /* not HAVE_OTF */ - return -1; -#endif /* not HAVE_OTF */ -} - -#else /* not HAVE_FREETYPE */ - -int -mfont__ft_init () -{ - return 0; } -void -mfont__ft_fini () -{ -} +#endif /* HAVE_OTF */ #endif /* HAVE_FREETYPE */