]> granicus.if.org Git - libass/commitdiff
Memory font support
authorGrigori Goronzy <greg@chown.ath.cx>
Sat, 20 Aug 2011 15:46:03 +0000 (17:46 +0200)
committerGrigori Goronzy <greg@chown.ath.cx>
Fri, 10 Jul 2015 08:42:40 +0000 (10:42 +0200)
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
libass/ass_font.h
libass/ass_fontselect.c
libass/ass_fontselect.h

index a6d1b5b734cb121871d255f758aaf33ad3d0b76f..ce427814845384f8fdfeb1387e1578a6bf16db8a 100644 (file)
@@ -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);
 
index 693cabf1e0238ef3113636e5b3e90eee17a3083f..06519c68a03586cfecbd558d2c2951634aff7e2a 100644 (file)
@@ -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,
index efd4a39cbe181a261deb5ddc4a158397631d458d..bb9ec803e41f6c8ff09d9eb282b84c97653e372b 100644 (file)
@@ -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 : "<memory>", *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 : "<memory>", *index);
     }
 
     if (res)
         ass_msg(library, MSGL_V,
                 "fontselect: (%s, %d, %d) -> %s, %d", family, bold,
-                italic, res, *index);
+                italic, res[0] ? res : "<memory>", *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);
index 8e41c45837f6f76ee4fff17e1efea133911fb5bd..ec4c793f5d95408d4ed8b2c10a74d3c20067132e 100644 (file)
@@ -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