From 887e6cc50bfbe8fc354993682edc03c51203e2fc Mon Sep 17 00:00:00 2001 From: Oleg Oshmyan Date: Thu, 17 Jun 2021 19:42:25 +0300 Subject: fontselect: automatically read metadata from font file if needed --- libass/ass_coretext.c | 40 ++++++----------------- libass/ass_font.c | 9 ++++-- libass/ass_fontselect.c | 85 +++++++++++++++++++++++++++++++++---------------- libass/ass_fontselect.h | 19 ++--------- 4 files changed, 76 insertions(+), 77 deletions(-) diff --git a/libass/ass_coretext.c b/libass/ass_coretext.c index 42259bb..8002d8b 100644 --- a/libass/ass_coretext.c +++ b/libass/ass_coretext.c @@ -126,8 +126,7 @@ static char *get_name(CTFontDescriptorRef fontd, CFStringRef attr) return ret; } -static bool get_font_info_ct(ASS_Library *lib, FT_Library ftlib, - CTFontDescriptorRef fontd, +static bool get_font_info_ct(CTFontDescriptorRef fontd, char **path_out, ASS_FontProviderMetaData *info) { @@ -139,29 +138,19 @@ static bool get_font_info_ct(ASS_Library *lib, FT_Library ftlib, } char *ps_name = get_name(fontd, kCTFontNameAttribute); + info->postscript_name = ps_name; if (!ps_name) return false; char *family_name = get_name(fontd, kCTFontFamilyNameAttribute); - if (!family_name) { - free(ps_name); + info->extended_family = family_name; + if (!family_name) return false; - } - - bool got_info = - ass_get_font_info(lib, ftlib, path, ps_name, -1, family_name, info); - free(ps_name); - if (got_info) - info->extended_family = family_name; - else - free(family_name); - - return got_info; + return true; } -static void process_descriptors(ASS_Library *lib, FT_Library ftlib, - ASS_FontProvider *provider, CFArrayRef fontsd) +static void process_descriptors(ASS_FontProvider *provider, CFArrayRef fontsd) { if (!fontsd) return; @@ -172,20 +161,11 @@ static void process_descriptors(ASS_Library *lib, FT_Library ftlib, int index = -1; char *path = NULL; - if (get_font_info_ct(lib, ftlib, fontd, &path, &meta)) { + if (get_font_info_ct(fontd, &path, &meta)) { CFRetain(fontd); ass_font_provider_add_font(provider, &meta, path, index, (void*)fontd); } - for (int j = 0; j < meta.n_family; j++) - free(meta.families[j]); - - for (int j = 0; j < meta.n_fullname; j++) - free(meta.fullnames[j]); - - free(meta.families); - free(meta.fullnames); - free(meta.postscript_name); free(meta.extended_family); @@ -196,8 +176,6 @@ static void process_descriptors(ASS_Library *lib, FT_Library ftlib, static void match_fonts(void *priv, ASS_Library *lib, ASS_FontProvider *provider, char *name) { - FT_Library ftlib = priv; - CFStringRef cfname = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); if (!cfname) @@ -256,7 +234,7 @@ static void match_fonts(void *priv, ASS_Library *lib, ASS_FontProvider *provider if (!fontsd) goto cleanup; - process_descriptors(lib, ftlib, provider, fontsd); + process_descriptors(provider, fontsd); cleanup: SAFE_CFRelease(fontsd); @@ -329,5 +307,5 @@ ASS_FontProvider * ass_coretext_add_provider(ASS_Library *lib, ASS_FontSelector *selector, const char *config, FT_Library ftlib) { - return ass_font_provider_new(selector, &coretext_callbacks, ftlib); + return ass_font_provider_new(selector, &coretext_callbacks, NULL); } diff --git a/libass/ass_font.c b/libass/ass_font.c index 9dc8772..a7ee576 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -203,8 +203,13 @@ FT_Face ass_face_stream(ASS_Library *lib, FT_Library ftlib, const char *name, FT_Face face; int error = FT_Open_Face(ftlib, &args, index, &face); if (error) { - ass_msg(lib, MSGL_WARN, - "Error opening memory font: '%s'", name); + if (name) { + ass_msg(lib, MSGL_WARN, + "Error opening memory font: '%s'", name); + } else { + ass_msg(lib, MSGL_WARN, + "Error opening memory font"); + } return NULL; } diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c index 670156e..68a4407 100644 --- a/libass/ass_fontselect.c +++ b/libass/ass_fontselect.c @@ -358,23 +358,6 @@ error: return false; } -bool ass_get_font_info(ASS_Library *lib, FT_Library ftlib, const char *path, - const char *postscript_name, int index, - const char *fallback_family_name, - ASS_FontProviderMetaData *info) -{ - FT_Face face = ass_face_open(lib, ftlib, path, postscript_name, index); - if (!face) - return false; - - bool ret = get_font_info(ftlib, face, fallback_family_name, info); - if (ret) - info->postscript_name = strdup(info->postscript_name); - FT_Done_Face(face); - - return ret; -} - /** * \brief Free the dynamically allocated fields of metadata * created by get_font_info. @@ -382,16 +365,17 @@ bool ass_get_font_info(ASS_Library *lib, FT_Library ftlib, const char *path, */ static void free_font_info(ASS_FontProviderMetaData *meta) { - int i; - - for (i = 0; i < meta->n_family; i++) - free(meta->families[i]); - - for (i = 0; i < meta->n_fullname; i++) - free(meta->fullnames[i]); + if (meta->families) { + for (int i = 0; i < meta->n_family; i++) + free(meta->families[i]); + free(meta->families); + } - free(meta->families); - free(meta->fullnames); + if (meta->fullnames) { + for (int i = 0; i < meta->n_fullname; i++) + free(meta->fullnames[i]); + free(meta->fullnames); + } } /** @@ -411,7 +395,48 @@ ass_font_provider_add_font(ASS_FontProvider *provider, int i; int weight, slant, width; ASS_FontSelector *selector = provider->parent; - ASS_FontInfo *info; + ASS_FontInfo *info = NULL; + ASS_FontProviderMetaData implicit_meta = {0}; + + if (!meta->n_family) { + FT_Face face; + if (provider->funcs.get_font_index) + index = provider->funcs.get_font_index(data); + if (!path) { + ASS_FontStream stream = { + .func = provider->funcs.get_data, + .priv = data, + }; + // This name is only used in an error message, so use + // our best name but don't panic if we don't have any. + // Prefer PostScript name because it is unique. + const char *name = meta->postscript_name ? + meta->postscript_name : meta->extended_family; + face = ass_face_stream(selector->library, selector->ftlibrary, + name, &stream, index); + } else { + face = ass_face_open(selector->library, selector->ftlibrary, + path, meta->postscript_name, index); + } + if (!face) + goto error; + if (!get_font_info(selector->ftlibrary, face, meta->extended_family, + &implicit_meta)) { + FT_Done_Face(face); + goto error; + } + if (implicit_meta.postscript_name) { + implicit_meta.postscript_name = + strdup(implicit_meta.postscript_name); + if (!implicit_meta.postscript_name) { + FT_Done_Face(face); + goto error; + } + } + FT_Done_Face(face); + implicit_meta.extended_family = meta->extended_family; + meta = &implicit_meta; + } #if 0 int j; @@ -511,7 +536,11 @@ ass_font_provider_add_font(ASS_FontProvider *provider, return true; error: - ass_font_provider_free_fontinfo(info); + if (info) + ass_font_provider_free_fontinfo(info); + + free_font_info(&implicit_meta); + free(implicit_meta.postscript_name); if (provider->funcs.destroy_font) provider->funcs.destroy_font(data); diff --git a/libass/ass_fontselect.h b/libass/ass_fontselect.h index 50c1968..522c729 100644 --- a/libass/ass_fontselect.h +++ b/libass/ass_fontselect.h @@ -171,6 +171,9 @@ typedef struct font_provider_funcs { /* * Basic font metadata. All strings must be encoded with UTF-8. * At minimum one family is required. + * If no family names are present, ass_font_provider_add_font + * will open the font file and read metadata from there, + * replacing everything but extended_family. */ struct ass_font_provider_meta_data { /** @@ -279,22 +282,6 @@ ass_font_provider_add_font(ASS_FontProvider *provider, ASS_FontProviderMetaData *meta, const char *path, int index, void *data); -/** - * \brief Read a font's parameters - * \param lib a FT_Library to use (need not be the global one) - * \param path the path to the font file to read - * \param postscript_name the PS name of the specific face to read (set either this or index) - * \param index the face index to read, or -1 if not applicable - * \param fallback_family_name family name from outside source, used as last resort - * \param info the struct to store results into - * \return success - * - */ -bool ass_get_font_info(ASS_Library *lib, FT_Library ftlib, const char *path, - const char *postscript_name, int index, - const char *fallback_family_name, - ASS_FontProviderMetaData *info); - /** * \brief Free font provider and associated fonts. * \param provider the font provider -- cgit v1.2.3