From 33f5954eb6849ac228491b729bcc11e922f62060 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Sun, 4 Sep 2011 15:54:38 +0200 Subject: Support multiple font family names Some fonts use localized family names, especially CJK fonts, which often have English and Japanese or Chinese names. Handle these cases just like full names. --- libass/ass_fontconfig.c | 21 ++++++------ libass/ass_fontselect.c | 85 ++++++++++++++++++++++++++++++------------------- libass/ass_types.h | 3 +- 3 files changed, 67 insertions(+), 42 deletions(-) (limited to 'libass') diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c index 4fbf824..6080359 100644 --- a/libass/ass_fontconfig.c +++ b/libass/ass_fontconfig.c @@ -31,7 +31,7 @@ #include "ass_fontselect.h" #include "ass_utils.h" -#define MAX_FULLNAME 100 +#define MAX_NAME 100 static int check_glyph(void *priv, uint32_t code) { @@ -73,7 +73,8 @@ static void scan_fonts(FcConfig *config, ASS_FontProvider *provider) FcBool outline; int index, weight; char *path; - char *fullnames[MAX_FULLNAME]; + char *fullnames[MAX_NAME]; + char *families[MAX_NAME]; // skip non-outline fonts FcResult result = FcPatternGetBool(pat, FC_OUTLINE, 0, &outline); @@ -98,22 +99,24 @@ static void scan_fonts(FcConfig *config, ASS_FontProvider *provider) else meta.weight = FONT_WEIGHT_BOLD; - // family name - result = FcPatternGetString(pat, FC_FAMILY, 0, - (FcChar8 **)&meta.family); - if (result != FcResultMatch) - continue; - // path result = FcPatternGetString(pat, FC_FILE, 0, (FcChar8 **)&path); if (result != FcResultMatch) continue; + // read and strdup fullnames + meta.n_family = 0; + while (FcPatternGetString(pat, FC_FAMILY, meta.n_family, + (FcChar8 **)&families[meta.n_family]) == FcResultMatch + && meta.n_family < MAX_NAME) + meta.n_family++; + meta.families = families; + // read and strdup fullnames meta.n_fullname = 0; while (FcPatternGetString(pat, FC_FULLNAME, meta.n_fullname, (FcChar8 **)&fullnames[meta.n_fullname]) == FcResultMatch - && meta.n_fullname < MAX_FULLNAME) + && meta.n_fullname < MAX_NAME) meta.n_fullname++; meta.fullnames = fullnames; diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c index 099b63d..ed4b35f 100644 --- a/libass/ass_fontselect.c +++ b/libass/ass_fontselect.c @@ -57,8 +57,9 @@ static const char *fallback_fonts[] = { struct font_info { int uid; // unique font face id - char *family; // family name + char **families; // family name char **fullnames; // list of localized fullnames (e.g. Arial Bold Italic) + int n_family; int n_fullname; int slant; @@ -259,9 +260,13 @@ ass_font_provider_add_font(ASS_FontProvider *provider, info->slant = slant; info->weight = weight; info->width = width; - info->family = strdup(meta->family); info->n_fullname = meta->n_fullname; + info->n_family = meta->n_family; info->fullnames = calloc(meta->n_fullname, sizeof(char *)); + info->families = calloc(meta->n_family, sizeof(char *)); + + for (i = 0; i < info->n_family; i++) + info->families[i] = strdup(meta->families[i]); for (i = 0; i < info->n_fullname; i++) info->fullnames[i] = strdup(meta->fullnames[i]); @@ -316,9 +321,11 @@ void ass_font_provider_free(ASS_FontProvider *provider) if (info->provider == provider) { for (j = 0; j < info->n_fullname; j++) free(info->fullnames[j]); + for (j = 0; j < info->n_family; j++) + free(info->families[j]); free(info->fullnames); - free(info->family); + free(info->families); if (info->path) free(info->path); @@ -368,20 +375,21 @@ static unsigned font_info_similarity(ASS_FontInfo *a, ASS_FontInfo *req) // if we don't have any match, compare fullnames against family // sometimes the family name is used similarly if (similarity > 0) { - for (i = 0; i < req->n_fullname; i++) { - if (strcasecmp(a->family, req->fullnames[i]) == 0) - similarity = 0; - } + for (i = 0; i < a->n_family; i++) + for (j = 0; j < req->n_fullname; j++) { + if (strcasecmp(a->families[i], req->fullnames[j]) == 0) + similarity = 0; + } } - // compare shortened family, if no fullname matches - if (similarity > 0 && strcasecmp(a->family, req->family) == 0) - similarity = 2000; - // nothing found? Try fallback fonts - while (similarity > 2000 && *fallback) - if (strcmp(a->family, *fallback++) == 0) - similarity = 5000; + while (similarity > 0 && *fallback) { + for (i = 0; i < a->n_family; i++) { + if (strcmp(a->families[i], *fallback) == 0) + similarity = 5000; + } + fallback++; + } // compare slant similarity += ABS(a->slant - req->slant); @@ -414,7 +422,9 @@ static void font_info_dump(ASS_FontInfo *font_infos, size_t len) // dump font infos for (i = 0; i < len; i++) { printf("font %d\n", i); - printf(" family: '%s'\n", font_infos[i].family); + printf(" families: "); + for (j = 0; j < font_infos[i].n_family; j++) + printf("'%s' ", font_infos[i].families[j]); printf(" fullnames: "); for (j = 0; j < font_infos[i].n_fullname; j++) printf("'%s' ", font_infos[i].fullnames[j]); @@ -461,9 +471,6 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, req.n_fullname = 1; req.fullnames = &req_fullname; req.fullnames[0] = trim_space(strdup(family)); - req.family = trim_space(strdup(family)); - char *p = strchr(req.family, ' '); - if (p) *p = 0; // calculate similarities font_info_req_similarity(font_infos, num_fonts, &req); @@ -485,7 +492,6 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, } free(req.fullnames[0]); - free(req.family); *index = font_infos[idx].index; *uid = font_infos[idx].uid; @@ -499,7 +505,7 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, ASS_FontProvider *provider = font_infos[idx].provider; stream->func = provider->funcs.get_data; stream->priv = font_infos[idx].priv; - return strdup(font_infos[idx].family); + return strdup(font_infos[idx].families[0]); } else return strdup(font_infos[idx].path); } @@ -577,10 +583,11 @@ get_font_info(FT_Library lib, FT_Face face, ASS_FontProviderMetaData *info) { int i; int num_fullname = 0; + int num_family = 0; int num_names = FT_Get_Sfnt_Name_Count(face); int slant, weight; char *fullnames[MAX_FULLNAME]; - char *family = NULL; + char *families[MAX_FULLNAME]; iconv_t utf16to8; // we're only interested in outlines @@ -589,41 +596,53 @@ get_font_info(FT_Library lib, FT_Face face, ASS_FontProviderMetaData *info) // scan font names utf16to8 = iconv_open("UTF-8", "UTF-16BE"); - for (i = 0; i < num_names && num_fullname < MAX_FULLNAME; i++) { + for (i = 0; i < num_names; i++) { FT_SfntName name; + FT_Get_Sfnt_Name(face, i, &name); + if (name.platform_id == 3 && (name.name_id == 4 || name.name_id == 1)) { char buf[1024]; char *bufptr = buf; size_t inbytes = name.string_len; size_t outbytes = 1024; + iconv(utf16to8, (char**)&name.string, &inbytes, &bufptr, &outbytes); *bufptr = '\0'; - // no primary family name yet - just use the first we encounter as a best guess - if (family == NULL && name.name_id == 1) { - family = strdup(buf); - continue; + + if (name.name_id == 4) { + fullnames[num_fullname] = strdup(buf); + num_fullname++; + } + + if (name.name_id == 1) { + families[num_family] = strdup(buf); + num_family++; } - fullnames[num_fullname] = strdup(buf); - num_fullname++; } + } iconv_close(utf16to8); // check if we got a valid family - if not use whatever FreeType gives us - if (family == NULL) - family = strdup(face->family_name); + if (num_family == 0) { + families[0] = strdup(face->family_name); + num_family++; + } // calculate sensible slant and weight from style attributes slant = 110 * !!(face->style_flags & FT_STYLE_FLAG_ITALIC); weight = 300 * !!(face->style_flags & FT_STYLE_FLAG_BOLD) + 400; // fill our struct - info->family = family; info->slant = slant; info->weight = weight; + info->width = 100; // FIXME, should probably query the OS/2 table + info->families = calloc(sizeof(char *), num_family); info->fullnames = calloc(sizeof(char *), num_fullname); + memcpy(info->families, &families, sizeof(char *) * num_family); memcpy(info->fullnames, &fullnames, sizeof(char *) * num_fullname); + info->n_family = num_family; info->n_fullname = num_fullname; return 1; @@ -638,11 +657,13 @@ static void free_font_info(ASS_FontProviderMetaData *meta) { int i; - free(meta->family); + for (i = 0; i < meta->n_family; i++) + free(meta->families[i]); for (i = 0; i < meta->n_fullname; i++) free(meta->fullnames[i]); + free(meta->families); free(meta->fullnames); } diff --git a/libass/ass_types.h b/libass/ass_types.h index 8411348..7d1e498 100644 --- a/libass/ass_types.h +++ b/libass/ass_types.h @@ -66,8 +66,9 @@ typedef struct font_provider_funcs { * At minimum `family' is required. */ typedef struct font_provider_meta_data { - char *family; // English font family, e.g. "Arial" + char **families; // list of family names, e.g. "Arial" char **fullnames; // list of localized full names, e.g. "Arial Bold" + int n_family; // list of family names int n_fullname; // number of localized full names int slant; // uses the above scale (NONE/ITALIC/OBLIQUE) int weight; // TrueType scale, 100-900 -- cgit v1.2.3