From f69ec6e0c038fe32cc5f91cc62cba52fe3934885 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Sat, 20 Aug 2011 17:46:03 +0200 Subject: Memory font support Allow memory fonts with the get_face_data callback. This feature is used for embedded fonts, but can be used by any font provider. --- libass/ass_font.c | 31 ++++---------- libass/ass_font.h | 6 +++ libass/ass_fontselect.c | 107 ++++++++++++++++++++++++++++++++++++------------ libass/ass_fontselect.h | 5 ++- 4 files changed, 98 insertions(+), 51 deletions(-) (limited to 'libass') diff --git a/libass/ass_font.c b/libass/ass_font.c index a6d1b5b..ce42781 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -92,18 +92,6 @@ uint32_t ass_font_index_magic(FT_Face face, uint32_t symbol) } } -/** - * \brief find a memory font by name - */ -static int find_font(ASS_Library *library, char *name) -{ - int i; - for (i = 0; i < library->num_fontdata; ++i) - if (strcasecmp(name, library->fontdata[i].name) == 0) - return i; - return -1; -} - static void buggy_font_workaround(FT_Face face) { // Some fonts have zero Ascender/Descender fields in 'hhea' table. @@ -130,14 +118,15 @@ static void buggy_font_workaround(FT_Face face) static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) { char *path; - int i, index, uid; - int error, mem_idx; + int i, index, uid, error; + ASS_Buffer mem_font = { NULL, 0 }; FT_Face face; if (font->n_faces == ASS_FONT_MAX_FACES) return -1; - path = ass_font_select(fontsel, font->library, font , &index, &uid, ch); + path = ass_font_select(fontsel, font->library, font , &index, &uid, + &mem_font, ch); if (!path) return -1; @@ -151,14 +140,9 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) } } - mem_idx = find_font(font->library, path); - if (mem_idx >= 0) { - error = - FT_New_Memory_Face(font->ftlibrary, - (unsigned char *) font->library-> - fontdata[mem_idx].data, - font->library->fontdata[mem_idx].size, index, - &face); + if (mem_font.buf) { + error = FT_New_Memory_Face(font->ftlibrary, mem_font.buf, mem_font.len, + index, &face); if (error) { ass_msg(font->library, MSGL_WARN, "Error opening memory font: '%s'", path); @@ -174,6 +158,7 @@ static int add_face(ASS_FontSelector *fontsel, ASS_Font *font, uint32_t ch) return -1; } } + charmap_magic(font->library, face); buggy_font_workaround(face); diff --git a/libass/ass_font.h b/libass/ass_font.h index 693cabf..06519c6 100644 --- a/libass/ass_font.h +++ b/libass/ass_font.h @@ -26,6 +26,7 @@ typedef struct ass_font ASS_Font; typedef struct ass_font_desc ASS_FontDesc; +typedef struct ass_buffer ASS_Buffer; #include "ass.h" #include "ass_types.h" @@ -58,6 +59,11 @@ struct ass_font { double size; }; +struct ass_buffer { + void *buf; + size_t len; +}; + void charmap_magic(ASS_Library *library, FT_Face face); ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, FT_Library ftlibrary, ASS_FontSelector *fontsel, diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c index efd4a39..bb9ec80 100644 --- a/libass/ass_fontselect.c +++ b/libass/ass_fontselect.c @@ -65,8 +65,8 @@ struct font_info { int weight; // TrueType scale, 100-900 // how to access this face - char *path; - int index; + char *path; // absolute path + int index; // font index inside font collections // similarity score unsigned score; @@ -109,10 +109,17 @@ struct coverage_map { uint32_t *codepoints; }; +typedef struct font_data_ft FontDataFT; +struct font_data_ft { + ASS_Library *lib; + CoverageMap *coverage; + char *name; +}; + static int check_glyph_ft(void *data, uint32_t codepoint) { int i; - CoverageMap *coverage = (CoverageMap *)data; + CoverageMap *coverage = ((FontDataFT *)data)->coverage; if (!codepoint) return 1; @@ -133,10 +140,50 @@ static void coverage_map_destroy(void *data) free(coverage); } +static void destroy_font_ft(void *data) +{ + FontDataFT *fd = (FontDataFT *)data; + + if (fd->coverage) + coverage_map_destroy(fd->coverage); + + free(fd->name); + free(fd); +} + +/** + * \brief find a memory font by name + * \param library ASS library + * \param name font name + */ +static int find_font(ASS_Library *library, char *name) +{ + int i; + for (i = 0; i < library->num_fontdata; ++i) + if (strcasecmp(name, library->fontdata[i].name) == 0) + return i; + return -1; +} + +static void *get_face_embedded(void *data, size_t *len) +{ + int i; + FontDataFT *ft = (FontDataFT *)data; + ASS_Fontdata *fd = ft->lib->fontdata; + + i = find_font(ft->lib, ft->name); + + if (i < 0) + return NULL; + + *len = fd[i].size; + return fd[i].data; +} + static ASS_FontProviderFuncs ft_funcs = { - NULL, + get_face_embedded, check_glyph_ft, - coverage_map_destroy, + destroy_font_ft, NULL, }; @@ -179,10 +226,6 @@ ass_font_provider_add_font(ASS_FontProvider *provider, ASS_FontSelector *selector = provider->parent; ASS_FontInfo *info; - // XXX: there's no support for memory fonts yet - if (!path) - return 0; - weight = meta->weight; slant = meta->slant; @@ -385,7 +428,7 @@ static int font_info_compare(const void *av, const void *bv) static char *select_font(ASS_FontSelector *priv, ASS_Library *library, const char *family, unsigned bold, unsigned italic, - int *index, int *uid, uint32_t code) + int *index, int *uid, ASS_Buffer *face, uint32_t code) { int num_fonts = priv->n_font; int idx = 0; @@ -430,14 +473,20 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, free(req.fullnames[0]); free(req.family); - // return best match - if (idx == priv->n_font) - return NULL; - if (!font_infos[idx].path) - return NULL; *index = font_infos[idx].index; *uid = font_infos[idx].uid; - return strdup(font_infos[idx].path); + + // nothing found + if (idx == priv->n_font) + return NULL; + + // if there is no valid path, this is a memory font + if (font_infos[idx].path == NULL) { + ASS_FontProvider *provider = font_infos[idx].provider; + face->buf = provider->funcs.get_face(font_infos[idx].priv, &face->len); + return strdup(""); // empty string indicates a memory font + } else + return strdup(font_infos[idx].path); } @@ -453,7 +502,8 @@ static char *select_font(ASS_FontSelector *priv, ASS_Library *library, * \return font file path */ char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, - ASS_Font *font, int *index, int *uid, uint32_t code) + ASS_Font *font, int *index, int *uid, ASS_Buffer *data, + uint32_t code) { char *res = 0; const char *family = font->desc.family; @@ -461,15 +511,16 @@ char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, unsigned italic = font->desc.italic; if (family && *family) - res = select_font(priv, library, family, bold, italic, index, uid, code); + res = select_font(priv, library, family, bold, italic, index, uid, + data, code); if (!res && priv->family_default) { res = select_font(priv, library, priv->family_default, bold, - italic, index, uid, code); + italic, index, uid, data, code); if (res) ass_msg(library, MSGL_WARN, "fontselect: Using default " "font family: (%s, %d, %d) -> %s, %d", - family, bold, italic, res, *index); + family, bold, italic, res[0] ? res : "", *index); } if (!res && priv->path_default) { @@ -482,17 +533,17 @@ char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, if (!res) { res = select_font(priv, library, "Arial", bold, italic, - index, uid, code); + index, uid, data, code); if (res) ass_msg(library, MSGL_WARN, "fontselect: Using 'Arial' " "font family: (%s, %d, %d) -> %s, %d", family, bold, - italic, res, *index); + italic, res[0] ? res : "", *index); } if (res) ass_msg(library, MSGL_V, "fontselect: (%s, %d, %d) -> %s, %d", family, bold, - italic, res, *index); + italic, res[0] ? res : "", *index); return res; } @@ -635,7 +686,7 @@ static void process_fontdata(ASS_FontProvider *priv, ASS_Library *library, for (face_index = 0; face_index < num_faces; ++face_index) { ASS_FontProviderMetaData info; - CoverageMap *coverage; + FontDataFT *ft; rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data, data_size, face_index, &face); @@ -655,8 +706,12 @@ static void process_fontdata(ASS_FontProvider *priv, ASS_Library *library, continue; } - coverage = get_coverage_map(face); - ass_font_provider_add_font(priv, &info, name, face_index, coverage); + ft = calloc(1, sizeof(FontDataFT)); + ft->lib = library; + ft->coverage = get_coverage_map(face); + ft->name = strdup(name); + + ass_font_provider_add_font(priv, &info, NULL, face_index, ft); free_font_info(&info); FT_Done_Face(face); diff --git a/libass/ass_fontselect.h b/libass/ass_fontselect.h index 8e41c45..ec4c793 100644 --- a/libass/ass_fontselect.h +++ b/libass/ass_fontselect.h @@ -33,7 +33,7 @@ typedef struct font_info ASS_FontInfo; #include "ass_font.h" // get face data -typedef void *(*GetFaceFunc)(void *); +typedef void *(*GetFaceFunc)(void *, size_t *); // check for a glyph typedef int (*CheckGlyphFunc)(void *, uint32_t); @@ -69,7 +69,8 @@ ass_fontselect_init(ASS_Library *library, FT_Library ftlibrary, const char *family, const char *path, const char *config, int fc); char *ass_font_select(ASS_FontSelector *priv, ASS_Library *library, - ASS_Font *font, int *index, int *uid, uint32_t code); + ASS_Font *font, int *index, int *uid, ASS_Buffer *data, + uint32_t code); void ass_fontselect_free(ASS_FontSelector *priv); // Font provider functions -- cgit v1.2.3