diff options
author | Grigori Goronzy <greg@kinoho.net> | 2015-09-07 11:32:49 +0200 |
---|---|---|
committer | Grigori Goronzy <greg@kinoho.net> | 2015-09-07 11:32:49 +0200 |
commit | 0268c64b8ec7bef9287a212759152bf7d15e64d8 (patch) | |
tree | f421fa82ffeec2c8a4fd10a3a17f6d87fd6977a6 | |
parent | fda28f6106caf7d450847444a363adc042b325b9 (diff) | |
parent | d6bb9af645526a810512eaf2c65252ac0e0e6b36 (diff) | |
download | libass-0268c64b8ec7bef9287a212759152bf7d15e64d8.tar.bz2 libass-0268c64b8ec7bef9287a212759152bf7d15e64d8.tar.xz |
Merge pull request #190 from grigorig/fonts
Substitutions and some fixes
-rw-r--r-- | libass/ass_coretext.c | 14 | ||||
-rw-r--r-- | libass/ass_directwrite.c | 14 | ||||
-rw-r--r-- | libass/ass_font.c | 5 | ||||
-rw-r--r-- | libass/ass_fontconfig.c | 19 | ||||
-rw-r--r-- | libass/ass_fontselect.c | 103 | ||||
-rw-r--r-- | libass/ass_fontselect.h | 31 | ||||
-rw-r--r-- | test/test.c | 2 |
7 files changed, 144 insertions, 44 deletions
diff --git a/libass/ass_coretext.c b/libass/ass_coretext.c index 3553324..877018d 100644 --- a/libass/ass_coretext.c +++ b/libass/ass_coretext.c @@ -25,6 +25,12 @@ #define SAFE_CFRelease(x) do { if (x) CFRelease(x); } while(0) +static const ASS_FontMapping font_substitutions[] = { + {"sans-serif", "Helvetica"}, + {"serif", "Times"}, + {"monospace", "Courier"} +}; + static char *cfstr2buf(CFStringRef string) { const int encoding = kCFStringEncodingUTF8; @@ -266,10 +272,18 @@ static char *get_fallback(void *priv, const char *family, uint32_t codepoint) return res_family; } +static void get_substitutions(void *priv, const char *name, + ASS_FontProviderMetaData *meta) +{ + const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]); + ass_map_font(font_substitutions, n, name, meta); +} + static ASS_FontProviderFuncs coretext_callbacks = { .check_glyph = check_glyph, .destroy_font = destroy_font, .match_fonts = match_fonts, + .get_substitutions = get_substitutions, .get_fallback = get_fallback, }; diff --git a/libass/ass_directwrite.c b/libass/ass_directwrite.c index 86b0b4b..f11deb6 100644 --- a/libass/ass_directwrite.c +++ b/libass/ass_directwrite.c @@ -31,6 +31,12 @@ #define NAME_MAX_LENGTH 256 #define FALLBACK_DEFAULT_FONT L"Arial" +static const ASS_FontMapping font_substitutions[] = { + {"sans-serif", "Arial"}, + {"serif", "Times New Roman"}, + {"monospace", "Courier New"} +}; + /* * The private data stored for every font, detected by this backend. */ @@ -624,6 +630,13 @@ static void scan_fonts(IDWriteFactory *factory, } } +static void get_substitutions(void *priv, const char *name, + ASS_FontProviderMetaData *meta) +{ + const int n = sizeof(font_substitutions) / sizeof(font_substitutions[0]); + ass_map_font(font_substitutions, n, name, meta); +} + /* * Called by libass when the provider should perform the * specified task @@ -633,6 +646,7 @@ static ASS_FontProviderFuncs directwrite_callbacks = { .check_glyph = check_glyph, .destroy_font = destroy_font, .destroy_provider = destroy_provider, + .get_substitutions = get_substitutions, .get_fallback = get_fallback, }; diff --git a/libass/ass_font.c b/libass/ass_font.c index 0164b67..b3c639d 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -153,7 +153,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) if (font->faces_uid[i] == uid) { ass_msg(font->library, MSGL_INFO, "Got a font face that already is available! Skipping."); - free(path); return i; } } @@ -178,7 +177,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) if (error) { ass_msg(font->library, MSGL_WARN, "Error opening memory font: '%s'", path); - free(path); return -1; } @@ -187,7 +185,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) if (error) { ass_msg(font->library, MSGL_WARN, "Error opening font: '%s', %d", path, index); - free(path); return -1; } @@ -201,7 +198,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) if (error) { ass_msg(font->library, MSGL_WARN, "Error opening font: '%s', %d", path, i); - free(path); return -1; } @@ -217,7 +213,6 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) font->faces[font->n_faces] = face; font->faces_uid[font->n_faces++] = uid; ass_face_set_size(face, font->size); - free(path); return font->n_faces - 1; } diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c index e97102b..184f090 100644 --- a/libass/ass_fontconfig.c +++ b/libass/ass_fontconfig.c @@ -177,6 +177,17 @@ static char *get_fallback(void *priv, const char *family, uint32_t codepoint) if (!fc->fallbacks || fc->fallbacks->nfont == 0) return NULL; + if (codepoint == 0) { + char *family = NULL; + result = FcPatternGetString(fc->fallbacks->fonts[0], FC_FAMILY, 0, + (FcChar8 **)&family); + if (result == FcResultMatch) { + return strdup(family); + } else { + return NULL; + } + } + // fallback_chars is the union of all available charsets, so // if we can't find the glyph in there, the system does not // have any font to render this glyph. @@ -194,8 +205,11 @@ static char *get_fallback(void *priv, const char *family, uint32_t codepoint) char *family = NULL; result = FcPatternGetString(pattern, FC_FAMILY, 0, (FcChar8 **)&family); - family = strdup(family); - return family; + if (result == FcResultMatch) { + return strdup(family); + } else { + return NULL; + } } } @@ -275,6 +289,7 @@ ass_fontconfig_add_provider(ASS_Library *lib, ASS_FontSelector *selector, ass_msg(lib, MSGL_FATAL, "No valid fontconfig configuration found!"); FcConfigDestroy(fc->config); + free(fc); return NULL; } diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c index 95d8c95..d48b170 100644 --- a/libass/ass_fontselect.c +++ b/libass/ass_fontselect.c @@ -477,41 +477,19 @@ static int check_glyph(ASS_FontInfo *fi, uint32_t code) return provider->funcs.check_glyph(fi->priv, code); } -static char *select_font(ASS_FontSelector *priv, ASS_Library *library, - const char *family, unsigned bold, unsigned italic, - int *index, char **postscript_name, int *uid, - ASS_FontStream *stream, uint32_t code) +static char * +find_font(ASS_FontSelector *priv, ASS_Library *library, + ASS_FontProviderMetaData meta, unsigned bold, unsigned italic, + int *index, char **postscript_name, int *uid, ASS_FontStream *stream, + uint32_t code, bool *name_match) { ASS_FontInfo req = {0}; - char *family_trim = strdup_trimmed(family); - ASS_FontProvider *default_provider = priv->default_provider; - ASS_FontProviderMetaData meta = {0}; ASS_FontInfo *selected = NULL; - if (family_trim == NULL) - return NULL; - - if (default_provider && default_provider->funcs.match_fonts) - default_provider->funcs.match_fonts(library, default_provider, family_trim); - // do we actually have any fonts? if (!priv->n_font) return NULL; - ASS_FontProviderMetaData default_meta = { - .n_fullname = 1, - .fullnames = &family_trim, - }; - - // get a list of substitutes if applicable, and use it for matching - if (default_provider && default_provider->funcs.get_substitutions) { - default_provider->funcs.get_substitutions(default_provider->priv, - family_trim, &meta); - } - if (!meta.n_fullname) { - meta = default_meta; - } - // fill font request req.slant = italic; req.weight = bold; @@ -530,11 +508,13 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, // If there's a family match, compare font attributes // to determine best match in that particular family score = font_attributes_similarity(font, &req); + *name_match = true; } else if (matches_fullname(font, fullname)) { // 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. score = 0; + *name_match = true; } // Consider updating idx if score is better than current minimum @@ -580,13 +560,68 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, ASS_FontProvider *provider = selected->provider; stream->func = provider->funcs.get_data; stream->priv = selected->priv; - // FIXME: we should define a default family name in some way, - // possibly the first (or last) English name - result = strdup(selected->families[0]); + // Prefer PostScript name because it is unique. This is only + // used for display purposes so it doesn't matter that much, + // though. + if (selected->postscript_name) + result = selected->postscript_name; + else + result = selected->families[0]; } else - result = strdup(selected->path); + result = selected->path; + } + + return result; +} + +static char *select_font(ASS_FontSelector *priv, ASS_Library *library, + const char *family, unsigned bold, unsigned italic, + int *index, char **postscript_name, int *uid, + ASS_FontStream *stream, uint32_t code) +{ + ASS_FontProvider *default_provider = priv->default_provider; + ASS_FontProviderMetaData meta = {0}; + char *family_trim = strdup_trimmed(family); + char *result = NULL; + bool name_match = false; + + if (family_trim == NULL) + return NULL; + + ASS_FontProviderMetaData default_meta = { + .n_fullname = 1, + .fullnames = &family_trim, + }; + + // Get a list of substitutes if applicable, and use it for matching. + if (default_provider && default_provider->funcs.get_substitutions) { + default_provider->funcs.get_substitutions(default_provider->priv, + family_trim, &meta); + } + + if (!meta.n_fullname) { + meta = default_meta; } + result = find_font(priv, library, meta, bold, italic, index, + postscript_name, uid, stream, code, &name_match); + + // If no matching font was found, it might not exist in the font list + // yet. Call the match_fonts callback to fill in the missing fonts + // on demand, and retry the search for a match. + if (result == NULL && name_match == false && default_provider && + default_provider->funcs.match_fonts) { + // TODO: consider changing the API to make more efficient + // implementations possible. + for (int i = 0; i < meta.n_fullname; i++) { + default_provider->funcs.match_fonts(library, default_provider, + meta.fullnames[i]); + } + result = find_font(priv, library, meta, bold, italic, index, + postscript_name, uid, stream, code, &name_match); + } + + // cleanup free(family_trim); if (meta.fullnames != default_meta.fullnames) { for (int i = 0; i < meta.n_fullname; i++) @@ -637,7 +672,7 @@ char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, if (!search_family || !*search_family) search_family = "Arial"; char *fallback_family = default_provider->funcs.get_fallback( - default_provider->priv, family, code); + default_provider->priv, search_family, code); if (fallback_family) { res = select_font(priv, library, fallback_family, bold, italic, @@ -1000,10 +1035,6 @@ void ass_fontselect_free(ASS_FontSelector *priv) if (priv->embedded_provider) ass_font_provider_free(priv->embedded_provider); - // XXX: not quite sure, maybe we should track all registered - // providers and free them right here. or should that be the - // responsibility of the library user? - free(priv->font_infos); free(priv->path_default); free(priv->family_default); diff --git a/libass/ass_fontselect.h b/libass/ass_fontselect.h index c989e1a..1e0959e 100644 --- a/libass/ass_fontselect.h +++ b/libass/ass_fontselect.h @@ -177,6 +177,37 @@ struct ass_font_stream { void *priv; }; + +typedef struct ass_font_mapping ASS_FontMapping; + +struct ass_font_mapping { + const char *from; + const char *to; +}; + +/** + * Simple font substitution helper. This can be used to implement basic + * mappings from one name to another. This is useful for supporting + * generic font families in font providers. + * + * \param map list of mappings + * \param len length of list of mappings + * \param name font name to map from + * \param meta metadata struct, mapped fonts will be stored into this + */ +inline void ass_map_font(const ASS_FontMapping *map, int len, const char *name, + ASS_FontProviderMetaData *meta) +{ + for (int i = 0; i < len; i++) { + if (strcasecmp(map[i].from, name) == 0) { + meta->n_fullname = 1; + meta->fullnames = calloc(1, sizeof(char *)); + meta->fullnames[0] = strdup(map[i].to); + return; + } + } +} + ASS_FontSelector * ass_fontselect_init(ASS_Library *library, FT_Library ftlibrary, const char *family, diff --git a/test/test.c b/test/test.c index 175e8be..4884b28 100644 --- a/test/test.c +++ b/test/test.c @@ -107,7 +107,7 @@ static void init(int frame_w, int frame_h) } ass_set_frame_size(ass_renderer, frame_w, frame_h); - ass_set_fonts(ass_renderer, NULL, "Sans", + ass_set_fonts(ass_renderer, NULL, "sans-serif", ASS_FONTPROVIDER_AUTODETECT, NULL, 1); } |