]> granicus.if.org Git - libass/commitdiff
cache: unified outline cache for glyphs/drawings
authorGrigori Goronzy <greg@blackbox>
Mon, 27 Jun 2011 00:17:10 +0000 (02:17 +0200)
committerGrigori Goronzy <greg@blackbox>
Mon, 27 Jun 2011 00:17:10 +0000 (02:17 +0200)
Glyphs and drawings have wildly different hash keys. Subclass the hash
keys of glyphs and drawings in a new, unified outline cache. This also
fixes some issues with drawings in the glyph cache. Now, the textual
description of the drawing is included in the key (the hash value isn't
really good enough, especially not fnv32) and the baseline offset is
saved as well.

libass/ass_cache.c
libass/ass_cache.h
libass/ass_cache_template.h
libass/ass_render.c
libass/ass_render.h
libass/ass_render_api.c

index 5ea4f1dbbcf40d30c2c95f9720bdddc36bfe07ec..15f7376f47e380554f23efe6553e7f3c80ae5918 100644 (file)
@@ -29,7 +29,7 @@
 #include "ass_cache.h"
 
 // type-specific functions
-// create hash/compare functions for bitmap, glyph and composite cache
+// create hash/compare functions for bitmap, outline and composite cache
 #define CREATE_HASH_FUNCTIONS
 #include "ass_cache_template.h"
 #define CREATE_COMPARISON_FUNCTIONS
@@ -96,41 +96,56 @@ static size_t bitmap_size(void *value, size_t value_size)
     return 0;
 }
 
-// glyph cache
-static void glyph_destruct(void *key, void *value)
+// composite cache
+static void composite_destruct(void *key, void *value)
 {
-    GlyphHashValue *v = value;
-    if (v->outline)
-        outline_free(v->lib, v->outline);
-    if (v->border)
-        outline_free(v->lib, v->border);
+    CompositeHashValue *v = value;
+    free(v->a);
+    free(v->b);
     free(key);
     free(value);
 }
 
-static size_t glyph_size(void *value, size_t value_size)
+// outline cache
+
+static unsigned outline_hash(void *key, size_t key_size)
 {
-#if 0
-    GlyphHashValue *val = value;
-    if (val->glyph && val->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
-        FT_Bitmap *bitmap = &((FT_BitmapGlyph) val->glyph)->bitmap;
-        return bitmap->rows * bitmap->pitch;
+    OutlineHashKey *k = key;
+    switch (k->type) {
+        case OUTLINE_GLYPH: return glyph_hash(&k->u, key_size);
+        case OUTLINE_DRAWING: return drawing_hash(&k->u, key_size);
+        default: return 0;
     }
-#endif
-    return 0;
 }
 
-// composite cache
-static void composite_destruct(void *key, void *value)
+static unsigned outline_compare(void *a, void *b, size_t key_size)
 {
-    CompositeHashValue *v = value;
-    free(v->a);
-    free(v->b);
+    OutlineHashKey *ak = a;
+    OutlineHashKey *bk = b;
+    if (ak->type != bk->type) return 0;
+    switch (ak->type) {
+        case OUTLINE_GLYPH: return glyph_compare(&ak->u, &bk->u, key_size);
+        case OUTLINE_DRAWING: return drawing_compare(&ak->u, &bk->u, key_size);
+        default: return 0;
+    }
+}
+
+static void outline_destruct(void *key, void *value)
+{
+    OutlineHashValue *v = value;
+    OutlineHashKey *k = key;
+    if (v->outline)
+        outline_free(v->lib, v->outline);
+    if (v->border)
+        outline_free(v->lib, v->border);
+    if (k->type == OUTLINE_DRAWING)
+        free(k->u.drawing.text);
     free(key);
     free(value);
 }
 
 
+
 // Cache data
 typedef struct cache_item {
     void *key;
@@ -279,10 +294,10 @@ Cache *ass_font_cache_create(void)
             (ItemSize)NULL, sizeof(ASS_FontDesc), sizeof(ASS_Font));
 }
 
-Cache *ass_glyph_cache_create(void)
+Cache *ass_outline_cache_create(void)
 {
-    return ass_cache_create(glyph_hash, glyph_compare, glyph_destruct,
-            glyph_size, sizeof(GlyphHashKey), sizeof(GlyphHashValue));
+    return ass_cache_create(outline_hash, outline_compare, outline_destruct,
+            NULL, sizeof(OutlineHashKey), sizeof(OutlineHashValue));
 }
 
 Cache *ass_bitmap_cache_create(void)
index cf2c400d8a4d122a186ae586334e9f789ba91eee..0ad7cae2c0f847b7c030d04e2e75b1413d50dcbf 100644 (file)
 
 typedef struct cache Cache;
 
-// Create definitions for bitmap, glyph and composite hash keys
+// Create definitions for bitmap, outline and composite hash keys
 #define CREATE_STRUCT_DEFINITIONS
 #include "ass_cache_template.h"
 
+// Type-specific function pointers
+typedef unsigned(*HashFunction)(void *key, size_t key_size);
+typedef size_t(*ItemSize)(void *value, size_t value_size);
+typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size);
+typedef void(*CacheItemDestructor)(void *key, void *value);
+
+// cache hash keys
+
+typedef struct outline_hash_key {
+    enum {
+        OUTLINE_GLYPH,
+        OUTLINE_DRAWING,
+    } type;
+    union {
+        GlyphHashKey glyph;
+        DrawingHashKey drawing;
+    } u;
+} OutlineHashKey;
+
+// cache values
+
 typedef struct {
     Bitmap *bm;               // the actual bitmaps
     Bitmap *bm_o;
@@ -46,15 +67,9 @@ typedef struct {
     FT_Outline *outline;
     FT_Outline *border;
     FT_BBox bbox_scaled;        // bbox after scaling, but before rotation
-    FT_Vector advance;          // 26.6, advance distance to the next bitmap in line
-    int asc, desc;              // ascender/descender of a drawing
-} GlyphHashValue;
-
-// Type-specific function pointers
-typedef unsigned(*HashFunction)(void *key, size_t key_size);
-typedef size_t(*ItemSize)(void *value, size_t value_size);
-typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size);
-typedef void(*CacheItemDestructor)(void *key, void *value);
+    FT_Vector advance;          // 26.6, advance distance to the next outline in line
+    int asc, desc;              // ascender/descender
+} OutlineHashValue;
 
 Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func,
                         CacheItemDestructor destruct_func, ItemSize size_func,
@@ -66,7 +81,7 @@ void ass_cache_stats(Cache *cache, size_t *size, unsigned *hits,
                      unsigned *misses, unsigned *count);
 void ass_cache_done(Cache *cache);
 Cache *ass_font_cache_create(void);
-Cache *ass_glyph_cache_create(void);
+Cache *ass_outline_cache_create(void);
 Cache *ass_bitmap_cache_create(void);
 Cache *ass_composite_cache_create(void);
 
index 9243ada92439104fd625b7fb266e5ec65c8b1908..cdb5826d964fc3a37769b77619760fc5c1a38473 100644 (file)
@@ -4,6 +4,8 @@
     typedef struct structname {
 #define GENERIC(type, member) \
         type member;
+#define STRING(member) \
+        char *member;
 #define FTVECTOR(member) \
         FT_Vector member;
 #define BITMAPHASHKEY(member) \
@@ -21,6 +23,8 @@
         return // conditions follow
 #define GENERIC(type, member) \
             a->member == b->member &&
+#define STRING(member) \
+            strcmp(a->member, b->member) == 0 &&
 #define FTVECTOR(member) \
             a->member.x == b->member.x && a->member.y == b->member.y &&
 #define BITMAPHASHKEY(member) \
@@ -38,6 +42,8 @@
         unsigned hval = FNV1_32A_INIT;
 #define GENERIC(type, member) \
         hval = fnv_32a_buf(&p->member, sizeof(p->member), hval);
+#define STRING(member) \
+        hval = fnv_32a_str(p->member, hval);
 #define FTVECTOR(member) GENERIC(, member.x); GENERIC(, member.y);
 #define BITMAPHASHKEY(member) { \
         unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \
@@ -98,6 +104,18 @@ START(glyph, glyph_hash_key)
     GENERIC(unsigned, border_style)
 END(GlyphHashKey)
 
+// describes an outline drawing
+START(drawing, drawing_hash_key)
+    GENERIC(unsigned, scale_x)
+    GENERIC(unsigned, scale_y)
+    GENERIC(int, pbo)
+    FTVECTOR(outline)
+    GENERIC(unsigned, border_style)
+    GENERIC(int, scale)
+    GENERIC(unsigned, hash)
+    STRING(text)
+END(DrawingHashKey)
+
 // Cache for composited bitmaps
 START(composite, composite_hash_key)
     GENERIC(int, aw)
@@ -117,6 +135,7 @@ END(CompositeHashKey)
 
 #undef START
 #undef GENERIC
+#undef STRING
 #undef FTVECTOR
 #undef BITMAPHASHKEY
 #undef END
index b036bf2e247416a7215c9b792f564fca1f43337e..55d959683b1afd22d89be69493958dd8b478f5cf 100644 (file)
@@ -63,7 +63,7 @@ ASS_Renderer *ass_renderer_init(ASS_Library *library)
     priv->cache.font_cache = ass_font_cache_create();
     priv->cache.bitmap_cache = ass_bitmap_cache_create();
     priv->cache.composite_cache = ass_composite_cache_create();
-    priv->cache.glyph_cache = ass_glyph_cache_create();
+    priv->cache.outline_cache = ass_outline_cache_create();
     priv->cache.glyph_max = GLYPH_CACHE_MAX;
     priv->cache.bitmap_max_size = BITMAP_CACHE_MAX_SIZE;
 
@@ -102,7 +102,7 @@ void ass_renderer_done(ASS_Renderer *render_priv)
     ass_cache_done(render_priv->cache.font_cache);
     ass_cache_done(render_priv->cache.bitmap_cache);
     ass_cache_done(render_priv->cache.composite_cache);
-    ass_cache_done(render_priv->cache.glyph_cache);
+    ass_cache_done(render_priv->cache.outline_cache);
 
     ass_free_images(render_priv->images_root);
     ass_free_images(render_priv->prev_images_root);
@@ -536,8 +536,8 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
     Bitmap *clip_bm = NULL;
     ASS_Image *cur;
     ASS_Drawing *drawing = render_priv->state.clip_drawing;
-    GlyphHashKey key;
-    GlyphHashValue *val;
+    //GlyphHashKey key;
+    //GlyphHashValue *val;
     int error;
 
     if (!drawing)
@@ -556,7 +556,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
         clip_bm = (FT_BitmapGlyph) val->glyph;
     } else {
 #endif
-        GlyphHashValue v;
+        //GlyphHashValue v;
 
         // Not found in cache, parse and rasterize it
         outline = ass_drawing_parse(drawing, 1);
@@ -1004,20 +1004,24 @@ static void stroke_outline(ASS_Renderer *render_priv, FT_Outline *outline,
  * \brief Prepare glyph hash
  */
 static void
-fill_glyph_hash(ASS_Renderer *priv, GlyphHashKey *key,
+fill_glyph_hash(ASS_Renderer *priv, OutlineHashKey *outline_key,
                 ASS_Drawing *drawing, uint32_t ch)
 {
     if (drawing->hash) {
+        DrawingHashKey *key = &outline_key->u.drawing;
+        outline_key->type = OUTLINE_DRAWING;
         key->scale_x = double_to_d16(priv->state.scale_x);
         key->scale_y = double_to_d16(priv->state.scale_y);
-        key->outline.x = priv->state.border_x * 0xFFFF;
-        key->outline.y = priv->state.border_y * 0xFFFF;
+        key->outline.x = double_to_d16(priv->state.border_x);
+        key->outline.y = double_to_d16(priv->state.border_y);
         key->border_style = priv->state.style->BorderStyle;
-        key->drawing_hash = drawing->hash;
-        // not very clean, but works
-        key->size = drawing->scale;
-        key->ch = -1;
+        key->hash = drawing->hash;
+        key->text = strdup(drawing->text);
+        key->pbo = drawing->pbo;
+        key->scale = drawing->scale;
     } else {
+        GlyphHashKey *key = &outline_key->u.glyph;
+        outline_key->type = OUTLINE_GLYPH;
         key->font = priv->state.font;
         key->size = priv->state.font_size;
         key->ch = ch;
@@ -1025,8 +1029,8 @@ fill_glyph_hash(ASS_Renderer *priv, GlyphHashKey *key,
         key->italic = priv->state.italic;
         key->scale_x = double_to_d16(priv->state.scale_x);
         key->scale_y = double_to_d16(priv->state.scale_y);
-        key->outline.x = priv->state.border_x * 0xFFFF;
-        key->outline.y = priv->state.border_y * 0xFFFF;
+        key->outline.x = double_to_d16(priv->state.border_x);
+        key->outline.y = double_to_d16(priv->state.border_y);
         key->flags = priv->state.flags;
         key->border_style = priv->state.style->BorderStyle;
     }
@@ -1045,14 +1049,14 @@ static void
 get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
                   ASS_Drawing *drawing)
 {
-    GlyphHashValue *val;
-    GlyphHashKey key;
+    OutlineHashValue *val;
+    OutlineHashKey key;
 
     memset(&key, 0, sizeof(key));
     memset(info, 0, sizeof(GlyphInfo));
 
     fill_glyph_hash(render_priv, &key, drawing, symbol);
-    val = ass_cache_get(render_priv->cache.glyph_cache, &key);
+    val = ass_cache_get(render_priv->cache.outline_cache, &key);
     if (val) {
         info->outline = val->outline;
         info->border = val->border;
@@ -1064,7 +1068,7 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
             drawing->desc = val->desc;
         }
     } else {
-        GlyphHashValue v;
+        OutlineHashValue v;
         if (drawing->hash) {
             if(!ass_drawing_parse(drawing, 0))
                 return;
@@ -1103,7 +1107,8 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
                                          render_priv->border_scale));
         } else if ((render_priv->state.border_x > 0
                     || render_priv->state.border_y > 0)
-                   && key.scale_x && key.scale_y) {
+                && double_to_d6(render_priv->state.scale_x)
+                && double_to_d6(render_priv->state.scale_y)) {
 
             outline_copy(render_priv->ftlibrary, info->outline, &info->border);
             stroke_outline(render_priv, info->border,
@@ -1123,7 +1128,7 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info,
             v.asc = drawing->asc;
             v.desc = drawing->desc;
         }
-        ass_cache_put(render_priv->cache.glyph_cache, &key, &v);
+        ass_cache_put(render_priv->cache.outline_cache, &key, &v);
     }
 }
 
@@ -2067,7 +2072,7 @@ static void check_cache_limits(ASS_Renderer *priv, CacheStore *cache)
         ass_free_images(priv->prev_images_root);
         priv->prev_images_root = 0;
     }
-    ass_cache_empty(cache->glyph_cache, cache->glyph_max);
+    ass_cache_empty(cache->outline_cache, cache->glyph_max);
 }
 
 /**
index 087658908fd29740f084b5af1083cb8707ec7a32..de2377adc960271c63bf088545378540dd204c47 100644 (file)
@@ -204,7 +204,7 @@ typedef struct {
 
 typedef struct {
     Cache *font_cache;
-    Cache *glyph_cache;
+    Cache *outline_cache;
     Cache *bitmap_cache;
     Cache *composite_cache;
     size_t glyph_max;
index 5995d31f3875a776e9b86ee749e5877dd6a262e7..5b02b46ccc0ee4fdf5a2fd609640624cbf89eac1 100644 (file)
@@ -25,7 +25,7 @@ static void ass_reconfigure(ASS_Renderer *priv)
     ASS_Settings *settings = &priv->settings;
 
     priv->render_id++;
-    ass_cache_empty(priv->cache.glyph_cache, 0);
+    ass_cache_empty(priv->cache.outline_cache, 0);
     ass_cache_empty(priv->cache.bitmap_cache, 0);
     ass_cache_empty(priv->cache.composite_cache, 0);
     ass_free_images(priv->prev_images_root);