From 5c7e811cce10489d8762ee51eb3d390dfc33cbef Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Thu, 6 Aug 2015 04:35:56 +0200 Subject: fontconfig: implement substitutions Signed-off-by: wm4 --- libass/ass_fontconfig.c | 39 ++++++++++++++++++++++++++++++++++++++- libass/ass_fontselect.c | 43 ++++++++++++++++++++++++++----------------- libass/ass_types.h | 6 +++--- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c index 02ffb56..50ce6c5 100644 --- a/libass/ass_fontconfig.c +++ b/libass/ass_fontconfig.c @@ -204,13 +204,50 @@ static char *get_fallback(void *priv, ASS_FontProviderMetaData *meta, return NULL; } +static void get_substitutions(void *priv, const char *name, + ASS_FontProviderMetaData *meta) +{ + ProviderPrivate *fc = (ProviderPrivate *)priv; + + FcPattern *pat = FcPatternCreate(); + if (!pat) + return; + + FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)name); + FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)"__libass_delimiter"); + FcPatternAddBool(pat, FC_OUTLINE, FcTrue); + if (!FcConfigSubstitute(fc->config, pat, FcMatchPattern)) + goto cleanup; + + // read and strdup fullnames + meta->n_fullname = 0; + meta->fullnames = calloc(MAX_NAME, sizeof(char *)); + if (!meta->fullnames) + goto cleanup; + + char *alias = NULL; + while (FcPatternGetString(pat, FC_FAMILY, meta->n_fullname, + (FcChar8 **)&alias) == FcResultMatch + && meta->n_fullname < MAX_NAME + && strcmp(alias, "__libass_delimiter") != 0) { + alias = strdup(alias); + if (!alias) + goto cleanup; + meta->fullnames[meta->n_fullname] = alias; + meta->n_fullname++; + } + +cleanup: + FcPatternDestroy(pat); +} + static ASS_FontProviderFuncs fontconfig_callbacks = { NULL, check_glyph, NULL, destroy, NULL, - NULL, + get_substitutions, get_fallback }; diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c index a15d0de..384054d 100644 --- a/libass/ass_fontselect.c +++ b/libass/ass_fontselect.c @@ -390,16 +390,18 @@ void ass_font_provider_free(ASS_FontProvider *provider) */ static unsigned font_info_similarity(ASS_FontInfo *a, ASS_FontInfo *req) { - int i; + int i, j; int family_match = 0; // Compare family name first; sometimes family name equals fullname, // but we want to be able to match against the different variants // in case a family name match occurs. - for (i = 0; i < a->n_family; i++) { - if (strcasecmp(a->families[i], req->fullnames[0]) == 0) { - family_match = 1; - break; + for (j = 0; j < req->n_fullname; j++) { + for (i = 0; i < a->n_family; i++) { + if (strcasecmp(a->families[i], req->fullnames[j]) == 0) { + family_match = 1; + break; + } } } @@ -417,9 +419,11 @@ static unsigned font_info_similarity(ASS_FontInfo *a, ASS_FontInfo *req) // If we don't have any match, compare fullnames against request // if there is a match now, assign lowest score possible. This means // the font should be chosen instantly, without further search. - for (i = 0; i < a->n_fullname; i++) { - if (strcasecmp(a->fullnames[i], req->fullnames[0]) == 0) - return 0; + for (j = 0; j < req->n_fullname; j++) { + for (i = 0; i < a->n_fullname; i++) { + if (strcasecmp(a->fullnames[i], req->fullnames[j]) == 0) + return 0; + } } return UINT_MAX; @@ -466,31 +470,36 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, ASS_FontStream *stream, uint32_t code) { int idx = -1; - ASS_FontInfo req; - char *req_fullname; + ASS_FontInfo req = {0}; char *family_trim = strdup_trimmed(family); + ASS_FontProvider *default_provider = priv->default_provider; + ASS_FontInfo *font_infos = priv->font_infos; + ASS_FontProviderMetaData meta; if (family_trim == NULL) return NULL; - ASS_FontProvider *default_provider = priv->default_provider; if (default_provider && default_provider->funcs.match_fonts) default_provider->funcs.match_fonts(library, default_provider, family_trim); - ASS_FontInfo *font_infos = priv->font_infos; - // do we actually have any fonts? if (!priv->n_font) return NULL; + // get a list of substitutes if applicable, and use it for matching + if (default_provider && default_provider->funcs.subst_font) { + default_provider->funcs.subst_font(default_provider->priv, family_trim, &meta); + req.n_fullname = meta.n_fullname; + req.fullnames = meta.fullnames; + } else { + req.n_fullname = 1; + req.fullnames = &family_trim; + } + // fill font request - memset(&req, 0, sizeof(ASS_FontInfo)); req.slant = italic; req.weight = bold; req.width = 100; - req.n_fullname = 1; - req.fullnames = &req_fullname; - req.fullnames[0] = family_trim; // Match font family name against font list unsigned score_min = UINT_MAX; diff --git a/libass/ass_types.h b/libass/ass_types.h index bc0efd8..f56a754 100644 --- a/libass/ass_types.h +++ b/libass/ass_types.h @@ -119,10 +119,10 @@ typedef void (*MatchFontsFunc)(ASS_Library *lib, * * \param priv font provider private data * \param name input string for substitution, as specified in the script - * \return output string for substitution, allocated with malloc(), must be - * freed by caller, can be NULL if no substitution was done. + * \param meta metadata (fullnames and n_fullname) to be filled in */ -typedef char *(*SubstituteFontFunc)(void *priv, const char *name); +typedef void (*SubstituteFontFunc)(void *priv, const char *name, + ASS_FontProviderMetaData *meta); /** * Get an appropriate fallback font for a given codepoint. -- cgit v1.2.3