summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrigori Goronzy <greg@chown.ath.cx>2015-08-06 04:35:56 +0200
committerwm4 <wm4@nowhere>2015-08-28 14:06:52 +0200
commit5c7e811cce10489d8762ee51eb3d390dfc33cbef (patch)
treec77d4ab16946286048f94b175a493e5442f8a7ef
parent038250b6bf4bb9a2b6d545f5f0a74b327302ca8b (diff)
downloadlibass-5c7e811cce10489d8762ee51eb3d390dfc33cbef.tar.bz2
libass-5c7e811cce10489d8762ee51eb3d390dfc33cbef.tar.xz
fontconfig: implement substitutions
Signed-off-by: wm4 <wm4@nowhere>
-rw-r--r--libass/ass_fontconfig.c39
-rw-r--r--libass/ass_fontselect.c43
-rw-r--r--libass/ass_types.h6
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.