]> granicus.if.org Git - libass/commitdiff
fontconfig: implement substitutions
authorGrigori Goronzy <greg@chown.ath.cx>
Thu, 6 Aug 2015 02:35:56 +0000 (04:35 +0200)
committerwm4 <wm4@nowhere>
Fri, 28 Aug 2015 12:06:52 +0000 (14:06 +0200)
Signed-off-by: wm4 <wm4@nowhere>
libass/ass_fontconfig.c
libass/ass_fontselect.c
libass/ass_types.h

index 02ffb562e5e38f409442f6a297d0676a8b60c036..50ce6c5bc70f768776153b959cf6c615febd8d58 100644 (file)
@@ -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
 };
 
index a15d0ded79a77a8bf208a279e0f1d63e1fdc2dbd..384054d9ff7144225fc574aa79691875f23d3781 100644 (file)
@@ -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;
index bc0efd8a34c074bc6bf74a1275092b9d485aca37..f56a754cb7b1bc1d629d2064ef75419af5ef87ad 100644 (file)
@@ -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.