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
};
*/
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;
+ }
}
}
// 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;
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;
*
* \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.