]> granicus.if.org Git - libass/commitdiff
cache: keep ref_count of all active objects nonzero
authorDr.Smile <vabnick@gmail.com>
Sat, 19 Sep 2015 00:08:29 +0000 (03:08 +0300)
committerDr.Smile <vabnick@gmail.com>
Thu, 30 Jun 2016 20:13:53 +0000 (23:13 +0300)
libass/ass_cache.c
libass/ass_cache.h
libass/ass_font.c
libass/ass_parse.c
libass/ass_render.c
libass/ass_render.h
libass/ass_shaper.c

index ce742e65d6323548de9ac1abd0e373d7b587a739..18904d2f13179d90c51b62ed27bf2e80edbbaac0 100644 (file)
@@ -63,12 +63,14 @@ static unsigned font_compare(void *key1, void *key2, size_t key_size)
     return 1;
 }
 
-static bool font_key_copy(void *dst, void *src, size_t key_size)
+static bool font_key_move(void *dst, void *src, size_t key_size)
 {
-    memcpy(dst, src, key_size);
-    ASS_FontDesc *d = dst, *s = src;
-    d->family = strdup(s->family);
-    return d->family;
+    ASS_FontDesc *k = src;
+    if (dst)
+        memcpy(dst, src, key_size);
+    else
+        free(k->family);
+    return true;
 }
 
 static void font_destruct(void *key, void *value)
@@ -99,21 +101,19 @@ static unsigned bitmap_compare(void *a, void *b, size_t key_size)
     }
 }
 
-static bool bitmap_key_copy(void *dst, void *src, size_t key_size)
+static bool bitmap_key_move(void *dst, void *src, size_t key_size)
 {
-    memcpy(dst, src, key_size);
     BitmapHashKey *d = dst, *s = src;
-    switch (s->type) {
-    case BITMAP_OUTLINE:
-        ass_cache_inc_ref(s->u.outline.outline);
-        break;
-    case BITMAP_CLIP:
-        d->u.clip.text = strdup(s->u.clip.text);
-        if (!d->u.clip.text)
-            return false;
-        break;
+    if (!dst) {
+        if (s->type == BITMAP_OUTLINE)
+            ass_cache_dec_ref(s->u.outline.outline);
+        return true;
     }
-    return true;
+    memcpy(dst, src, key_size);
+    if (s->type != BITMAP_CLIP)
+        return true;
+    d->u.clip.text = strdup(s->u.clip.text);
+    return d->u.clip.text;
 }
 
 static void bitmap_destruct(void *key, void *value)
@@ -158,12 +158,16 @@ static unsigned composite_compare(void *a, void *b, size_t key_size)
     return filter_compare(&ak->filter, &bk->filter, key_size);
 }
 
-static bool composite_key_copy(void *dst, void *src, size_t key_size)
+static bool composite_key_move(void *dst, void *src, size_t key_size)
 {
-    memcpy(dst, src, key_size);
+    if (dst) {
+        memcpy(dst, src, key_size);
+        return true;
+    }
     CompositeHashKey *k = src;
     for (size_t i = 0; i < k->bitmap_count; i++)
-        ass_cache_inc_ref(k->bitmaps[i].image);
+        ass_cache_dec_ref(k->bitmaps[i].image);
+    free(k->bitmaps);
     return true;
 }
 
@@ -205,21 +209,19 @@ static unsigned outline_compare(void *a, void *b, size_t key_size)
     }
 }
 
-static bool outline_key_copy(void *dst, void *src, size_t key_size)
+static bool outline_key_move(void *dst, void *src, size_t key_size)
 {
-    memcpy(dst, src, key_size);
     OutlineHashKey *d = dst, *s = src;
-    switch (s->type) {
-    case OUTLINE_GLYPH:
-        ass_cache_inc_ref(s->u.glyph.font);
-        break;
-    case OUTLINE_DRAWING:
-        d->u.drawing.text = strdup(s->u.drawing.text);
-        if (!d->u.drawing.text)
-            return false;
-        break;
+    if (!dst) {
+        if (s->type == OUTLINE_GLYPH)
+            ass_cache_dec_ref(s->u.glyph.font);
+        return true;
     }
-    return true;
+    memcpy(dst, src, key_size);
+    if (s->type != OUTLINE_DRAWING)
+        return true;
+    d->u.drawing.text = strdup(s->u.drawing.text);
+    return d->u.drawing.text;
 }
 
 static void outline_destruct(void *key, void *value)
@@ -238,8 +240,10 @@ static void outline_destruct(void *key, void *value)
 
 
 // glyph metric cache
-static bool glyph_metric_key_copy(void *dst, void *src, size_t key_size)
+static bool glyph_metric_key_move(void *dst, void *src, size_t key_size)
 {
+    if (!dst)
+        return true;
     memcpy(dst, src, key_size);
     GlyphMetricsHashKey *k = src;
     ass_cache_inc_ref(k->font);
@@ -269,7 +273,7 @@ struct cache {
 
     HashFunction hash_func;
     HashCompare compare_func;
-    CacheKeyCopy copy_func;
+    CacheKeyMove key_move_func;
     CacheItemDestructor destruct_func;
     size_t key_size;
     size_t value_size;
@@ -306,9 +310,10 @@ static unsigned compare_simple(void *a, void *b, size_t key_size)
 }
 
 // Default copy function
-static bool copy_simple(void *dst, void *src, size_t key_size)
+static bool key_move_simple(void *dst, void *src, size_t key_size)
 {
-    memcpy(dst, src, key_size);
+    if (dst)
+        memcpy(dst, src, key_size);
     return true;
 }
 
@@ -320,7 +325,7 @@ static void destruct_simple(void *key, void *value)
 
 // Create a cache with type-specific hash/compare/destruct/size functions
 Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func,
-                        CacheKeyCopy copy_func, CacheItemDestructor destruct_func,
+                        CacheKeyMove key_move_func, CacheItemDestructor destruct_func,
                         size_t key_size, size_t value_size)
 {
     Cache *cache = calloc(1, sizeof(*cache));
@@ -330,7 +335,7 @@ Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func,
     cache->queue_last = &cache->queue_first;
     cache->hash_func = hash_func ? hash_func : hash_simple;
     cache->compare_func = compare_func ? compare_func : compare_simple;
-    cache->copy_func = copy_func ? copy_func : copy_simple;
+    cache->key_move_func = key_move_func ? key_move_func : key_move_simple;
     cache->destruct_func = destruct_func ? destruct_func : destruct_simple;
     cache->key_size = key_size;
     cache->value_size = value_size;
@@ -363,7 +368,9 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
                 item->queue_next = NULL;
             }
             cache->hits++;
+            cache->key_move_func(NULL, key, cache->key_size);
             *value = (char *) item + CACHE_ITEM_SIZE;
+            item->ref_count++;
             return true;
         }
         item = item->next;
@@ -372,12 +379,13 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
 
     item = malloc(key_offs + cache->key_size);
     if (!item) {
+        cache->key_move_func(NULL, key, cache->key_size);
         *value = NULL;
         return false;
     }
     item->size = 0;
     item->cache = cache;
-    if (!cache->copy_func((char *) item + key_offs, key, cache->key_size)) {
+    if (!cache->key_move_func((char *) item + key_offs, key, cache->key_size)) {
         free(item);
         *value = NULL;
         return false;
@@ -391,16 +399,13 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr)
     item->next = *bucketptr;
     *bucketptr = item;
 
-    *cache->queue_last = item;
-    item->queue_prev = cache->queue_last;
-    cache->queue_last = &item->queue_next;
+    item->queue_prev = NULL;
     item->queue_next = NULL;
-
-    item->ref_count = 0;
+    item->ref_count = 1;
     return false;
 }
 
-void *ass_cache_get_key(void *value)
+void *ass_cache_key(void *value)
 {
     CacheItem *item = value_to_item(value);
     return (char *) value + align_cache(item->cache->value_size);
@@ -414,6 +419,10 @@ void ass_cache_commit(void *value, size_t item_size)
     Cache *cache = item->cache;
     cache->cache_size += item_size;
     cache->items++;
+
+    *cache->queue_last = item;
+    item->queue_prev = cache->queue_last;
+    cache->queue_last = &item->queue_next;
 }
 
 static inline void destroy_item(Cache *cache, CacheItem *item)
@@ -426,6 +435,8 @@ static inline void destroy_item(Cache *cache, CacheItem *item)
 
 void ass_cache_inc_ref(void *value)
 {
+    if (!value)
+        return;
     CacheItem *item = value_to_item(value);
     assert(item->size);
     item->ref_count++;
@@ -433,6 +444,8 @@ void ass_cache_inc_ref(void *value)
 
 void ass_cache_dec_ref(void *value)
 {
+    if (!value)
+        return;
     CacheItem *item = value_to_item(value);
     assert(item->size && item->ref_count);
 
@@ -498,7 +511,7 @@ void ass_cache_empty(Cache *cache)
     for (int i = 0; i < cache->buckets; i++) {
         CacheItem *item = cache->map[i];
         while (item) {
-            assert(item->size);
+            assert(item->size && !item->ref_count);
             CacheItem *next = item->next;
             destroy_item(cache, item);
             item = next;
@@ -522,34 +535,34 @@ void ass_cache_done(Cache *cache)
 Cache *ass_font_cache_create(void)
 {
     return ass_cache_create(font_hash, font_compare,
-                            font_key_copy, font_destruct,
+                            font_key_move, font_destruct,
                             sizeof(ASS_FontDesc), sizeof(ASS_Font));
 }
 
 Cache *ass_outline_cache_create(void)
 {
     return ass_cache_create(outline_hash, outline_compare,
-                            outline_key_copy, outline_destruct,
+                            outline_key_move, outline_destruct,
                             sizeof(OutlineHashKey), sizeof(OutlineHashValue));
 }
 
 Cache *ass_glyph_metrics_cache_create(void)
 {
     return ass_cache_create(glyph_metrics_hash, glyph_metrics_compare,
-                            glyph_metric_key_copy, glyph_metric_destruct,
+                            glyph_metric_key_move, glyph_metric_destruct,
                             sizeof(GlyphMetricsHashKey), sizeof(GlyphMetricsHashValue));
 }
 
 Cache *ass_bitmap_cache_create(void)
 {
     return ass_cache_create(bitmap_hash, bitmap_compare,
-                            bitmap_key_copy, bitmap_destruct,
+                            bitmap_key_move, bitmap_destruct,
                             sizeof(BitmapHashKey), sizeof(BitmapHashValue));
 }
 
 Cache *ass_composite_cache_create(void)
 {
     return ass_cache_create(composite_hash, composite_compare,
-                            composite_key_copy, composite_destruct,
+                            composite_key_move, composite_destruct,
                             sizeof(CompositeHashKey), sizeof(CompositeHashValue));
 }
index 6cea269493f67c371c0713d5006fa42008f76cba..cd7253335d37173787bc7acc372ec4b36f57e78b 100644 (file)
@@ -58,7 +58,7 @@ typedef struct {
 // Type-specific function pointers
 typedef unsigned(*HashFunction)(void *key, size_t key_size);
 typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size);
-typedef bool(*CacheKeyCopy)(void *dst, void *src, size_t key_size);
+typedef bool(*CacheKeyMove)(void *dst, void *src, size_t key_size);
 typedef void(*CacheItemDestructor)(void *key, void *value);
 
 // cache hash keys
@@ -104,10 +104,10 @@ typedef struct {
 } CompositeHashKey;
 
 Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func,
-                        CacheKeyCopy copy_func, CacheItemDestructor destruct_func,
+                        CacheKeyMove copy_func, CacheItemDestructor destruct_func,
                         size_t key_size, size_t value_size);
 bool ass_cache_get(Cache *cache, void *key, void *value_ptr);
-void *ass_cache_get_key(void *value);
+void *ass_cache_key(void *value);
 void ass_cache_commit(void *value, size_t item_size);
 void ass_cache_inc_ref(void *value);
 void ass_cache_dec_ref(void *value);
index d9dc7babf91472dad3eca6ffcbe875b0b9890fc1..5889b49044be3dd5a64c7b1170659bcfbf1cfa00 100644 (file)
@@ -229,8 +229,12 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
                        ASS_FontDesc *desc)
 {
     ASS_Font *font;
-    if (ass_cache_get(font_cache, desc, &font))
-        return font->desc.family ? font : NULL;
+    if (ass_cache_get(font_cache, desc, &font)) {
+        if (font->desc.family)
+            return font;
+        ass_cache_dec_ref(font);
+        return NULL;
+    }
     if (!font)
         return NULL;
 
@@ -238,7 +242,7 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
     font->ftlibrary = ftlibrary;
     font->shaper_priv = NULL;
     font->n_faces = 0;
-    ASS_FontDesc *new_desc = ass_cache_get_key(font);
+    ASS_FontDesc *new_desc = ass_cache_key(font);
     font->desc.family = new_desc->family;
     font->desc.bold = desc->bold;
     font->desc.italic = desc->italic;
@@ -252,6 +256,7 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library,
     if (error == -1) {
         font->desc.family = NULL;
         ass_cache_commit(font, 1);
+        ass_cache_dec_ref(font);
         return NULL;
     }
     ass_cache_commit(font, 1);
index e6db422453d7049ac24822248b934b81ab21222b..569866976b93968c8ce0244c611d2ceef490522a 100644 (file)
@@ -127,11 +127,11 @@ void update_font(ASS_Renderer *render_priv)
         val = 0;                // normal
     desc.italic = val;
 
+    ass_cache_dec_ref(render_priv->state.font);
     render_priv->state.font =
         ass_font_new(render_priv->cache.font_cache, render_priv->library,
                      render_priv->ftlibrary, render_priv->fontselect,
                      &desc);
-    free(desc.family);
 
     if (render_priv->state.font)
         change_font_size(render_priv, render_priv->state.font_size);
index 53d2681a58d979107c5832a0c1beeee573832f56..29a5a3d2d03cb8644957cf214e48ebf70d8c06c9 100644 (file)
@@ -515,6 +515,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
             ass_msg(render_priv->library, MSGL_WARN,
                     "Clip vector parsing failed. Skipping.");
             ass_cache_commit(val, sizeof(BitmapHashKey) + sizeof(BitmapHashValue));
+            ass_cache_dec_ref(val);
             return;
         }
 
@@ -534,7 +535,10 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
     }
 
     Bitmap *clip_bm = val->bm;
-    if (!clip_bm) return;
+    if (!clip_bm) {
+        ass_cache_dec_ref(val);
+        return;
+    }
 
     // Iterate through bitmaps and blend/clip them
     for (ASS_Image *cur = head; cur; cur = cur->next) {
@@ -582,7 +586,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
             nbuffer = ass_aligned_alloc(32, as * ah);
             if (!free_list_add(render_priv, nbuffer)) {
                 ass_aligned_free(nbuffer);
-                return;
+                break;
             }
 
             // Blend together
@@ -604,7 +608,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
             nbuffer = ass_aligned_alloc(align, ns * h);
             if (!free_list_add(render_priv, nbuffer)) {
                 ass_aligned_free(nbuffer);
-                return;
+                break;
             }
 
             // Blend together
@@ -620,6 +624,8 @@ static void blend_vector_clip(ASS_Renderer *render_priv,
         }
         cur->bitmap = nbuffer;
     }
+
+    ass_cache_dec_ref(val);
 }
 
 /**
@@ -685,6 +691,11 @@ static ASS_Image *render_text(ASS_Renderer *render_priv)
     *tail = 0;
     blend_vector_clip(render_priv, head);
 
+    for (int i = 0; i < text_info->n_bitmaps; ++i) {
+        CombinedBitmapInfo *info = &text_info->combined_bitmaps[i];
+        ass_cache_dec_ref(info->image);  // XXX: not thread safe
+    }
+
     return head;
 }
 
@@ -921,9 +932,11 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
 
 static void free_render_context(ASS_Renderer *render_priv)
 {
+    ass_cache_dec_ref(render_priv->state.font);
     free(render_priv->state.family);
     ass_drawing_free(render_priv->state.clip_drawing);
 
+    render_priv->state.font = NULL;
     render_priv->state.family = NULL;
     render_priv->state.clip_drawing = NULL;
 
@@ -1168,6 +1181,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
             ass_drawing_hash(drawing);
             if(!ass_drawing_parse(drawing, 0)) {
                 ass_cache_commit(val, 1);
+                ass_cache_dec_ref(val);
                 return;
             }
             val->outline = outline_copy(&drawing->outline);
@@ -1200,6 +1214,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
 
         if (!val->outline) {
             ass_cache_commit(val, 1);
+            ass_cache_dec_ref(val);
             return;
         }
 
@@ -1212,6 +1227,7 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
                 free(val->outline);
                 val->outline = NULL;
                 ass_cache_commit(val, 1);
+                ass_cache_dec_ref(val);
                 return;
             }
 
@@ -1238,8 +1254,10 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info)
         ass_cache_commit(val, 1);
     }
 
-    if (!val->outline)
+    if (!val->outline) {
+        ass_cache_dec_ref(val);
         return;
+    }
 
     info->hash_key.u.outline.outline = val;
     info->outline = val->outline;
@@ -1903,6 +1921,8 @@ static int parse_events(ASS_Renderer *render_priv, ASS_Event *event)
         // Fill glyph information
         info->symbol = code;
         info->font = render_priv->state.font;
+        if (!info->drawing)
+            ass_cache_inc_ref(info->font);
         for (i = 0; i < 4; ++i) {
             uint32_t clr = render_priv->state.c[i];
             // VSFilter compatibility: apply fade only when it's positive
@@ -2166,10 +2186,14 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
     CombinedBitmapInfo *combined_info = text_info->combined_bitmaps;
     CombinedBitmapInfo *current_info = NULL;
     GlyphInfo *last_info = NULL;
-    for (int i = 0; i < text_info->length; ++i) {
+    for (int i = 0; i < text_info->length; i++) {
         GlyphInfo *info = text_info->glyphs + i;
         if (info->linebreak) linebreak = 1;
-        if (info->skip) continue;
+        if (info->skip) {
+            for (; info; info = info->next)
+                ass_cache_dec_ref(info->hash_key.u.outline.outline);
+            continue;
+        }
         for (; info; info = info->next) {
             OutlineBitmapHashKey *key = &info->hash_key.u.outline;
 
@@ -2185,8 +2209,10 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
                 last_info = NULL;
                 if (nb_bitmaps >= text_info->max_bitmaps) {
                     size_t new_size = 2 * text_info->max_bitmaps;
-                    if (!ASS_REALLOC_ARRAY(text_info->combined_bitmaps, new_size))
+                    if (!ASS_REALLOC_ARRAY(text_info->combined_bitmaps, new_size)) {
+                        ass_cache_dec_ref(info->image);
                         continue;
+                    }
                     text_info->max_bitmaps = new_size;
                     combined_info = text_info->combined_bitmaps;
                 }
@@ -2217,49 +2243,56 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
                 current_info->x = current_info->y = INT_MAX;
                 rectangle_reset(&current_info->rect);
                 rectangle_reset(&current_info->rect_o);
-                current_info->bm = current_info->bm_o = current_info->bm_s = NULL;
                 current_info->n_bm = current_info->n_bm_o = 0;
+                current_info->bm = current_info->bm_o = current_info->bm_s = NULL;
+                current_info->image = NULL;
 
                 current_info->bitmap_count = current_info->max_bitmap_count = 0;
                 current_info->bitmaps = malloc(MAX_SUB_BITMAPS_INITIAL * sizeof(BitmapRef));
-                if (!current_info->bitmaps)
+                if (!current_info->bitmaps) {
+                    ass_cache_dec_ref(info->image);
                     continue;
+                }
                 current_info->max_bitmap_count = MAX_SUB_BITMAPS_INITIAL;
 
-                ++nb_bitmaps;
+                nb_bitmaps++;
             }
             last_info = info;
 
-            if (!info->image || !current_info)
+            if (!info->image || !current_info) {
+                ass_cache_dec_ref(info->image);
                 continue;
+            }
 
             if (current_info->bitmap_count >= current_info->max_bitmap_count) {
                 size_t new_size = 2 * current_info->max_bitmap_count;
-                if (!ASS_REALLOC_ARRAY(current_info->bitmaps, new_size))
+                if (!ASS_REALLOC_ARRAY(current_info->bitmaps, new_size)) {
+                    ass_cache_dec_ref(info->image);
                     continue;
+                }
                 current_info->max_bitmap_count = new_size;
             }
             current_info->bitmaps[current_info->bitmap_count].image = info->image;
             current_info->bitmaps[current_info->bitmap_count].x = x;
             current_info->bitmaps[current_info->bitmap_count].y = y;
-            ++current_info->bitmap_count;
+            current_info->bitmap_count++;
 
             current_info->x = FFMIN(current_info->x, x);
             current_info->y = FFMIN(current_info->y, y);
             if (info->image->bm) {
                 rectangle_combine(&current_info->rect, info->image->bm, x, y);
-                ++current_info->n_bm;
+                current_info->n_bm++;
             }
             if (info->image->bm_o) {
                 rectangle_combine(&current_info->rect_o, info->image->bm_o, x, y);
-                ++current_info->n_bm_o;
+                current_info->n_bm_o++;
             }
         }
     }
 
-    for (int i = 0; i < nb_bitmaps; ++i) {
+    for (int i = 0; i < nb_bitmaps; i++) {
         CombinedBitmapInfo *info = &combined_info[i];
-        for (int j = 0; j < info->bitmap_count; ++j) {
+        for (int j = 0; j < info->bitmap_count; j++) {
             info->bitmaps[j].x -= info->x;
             info->bitmaps[j].y -= info->y;
         }
@@ -2271,7 +2304,7 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
             info->bm = hv->bm;
             info->bm_o = hv->bm_o;
             info->bm_s = hv->bm_s;
-            free(info->bitmaps);
+            info->image = hv;
             continue;
         }
         if (!hv)
@@ -2279,7 +2312,7 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
 
         int bord = be_padding(info->filter.be);
         if (!bord && info->n_bm == 1) {
-            for (int j = 0; j < info->bitmap_count; ++j) {
+            for (int j = 0; j < info->bitmap_count; j++) {
                 if (!info->bitmaps[j].image->bm)
                     continue;
                 info->bm = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm);
@@ -2297,7 +2330,7 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
             if (dst) {
                 dst->left = info->rect.x_min - info->x - bord;
                 dst->top  = info->rect.y_min - info->y - bord;
-                for (int j = 0; j < info->bitmap_count; ++j) {
+                for (int j = 0; j < info->bitmap_count; j++) {
                     Bitmap *src = info->bitmaps[j].image->bm;
                     if (!src)
                         continue;
@@ -2313,7 +2346,7 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
             }
         }
         if (!bord && info->n_bm_o == 1) {
-            for (int j = 0; j < info->bitmap_count; ++j) {
+            for (int j = 0; j < info->bitmap_count; j++) {
                 if (!info->bitmaps[j].image->bm_o)
                     continue;
                 info->bm_o = copy_bitmap(render_priv->engine, info->bitmaps[j].image->bm_o);
@@ -2331,7 +2364,7 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
             if (dst) {
                 dst->left = info->rect_o.x_min - info->x - bord;
                 dst->top  = info->rect_o.y_min - info->y - bord;
-                for (int j = 0; j < info->bitmap_count; ++j) {
+                for (int j = 0; j < info->bitmap_count; j++) {
                     Bitmap *src = info->bitmaps[j].image->bm_o;
                     if (!src)
                         continue;
@@ -2360,6 +2393,7 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv,
         ass_cache_commit(hv, bitmap_size(hv->bm) +
                          bitmap_size(hv->bm_o) + bitmap_size(hv->bm_s) +
                          sizeof(CompositeHashKey) + sizeof(CompositeHashValue));
+        info->image = hv;
     }
 
     text_info->n_bitmaps = nb_bitmaps;
index 83dd1d80f1f1e1ff6f34712d21c9e1ed5eb09a30..ac7d34759915af28205be70e0b13b1a5180f2fca 100644 (file)
@@ -125,8 +125,10 @@ typedef struct {
 
     int x, y;
     Rectangle rect, rect_o;
-    Bitmap *bm, *bm_o, *bm_s;   // glyphs, outline, shadow bitmaps
     size_t n_bm, n_bm_o;
+
+    Bitmap *bm, *bm_o, *bm_s;   // glyphs, outline, shadow bitmaps
+    CompositeHashValue *image;
 } CombinedBitmapInfo;
 
 // describes a glyph
index 8cb865403afa0ae946178fe9a54482c5147cf455..95222ae449fb87aa2d88fc2c6138a99a71739b85 100644 (file)
@@ -208,8 +208,12 @@ get_cached_metrics(struct ass_shaper_metrics_data *metrics, FT_Face face,
 {
     GlyphMetricsHashValue *val;
     metrics->hash_key.glyph_index = glyph;
-    if (ass_cache_get(metrics->metrics_cache, &metrics->hash_key, &val))
-        return val->metrics.width < 0 ? NULL : val;
+    if (ass_cache_get(metrics->metrics_cache, &metrics->hash_key, &val)) {
+        if (val->metrics.width >= 0)
+            return val;
+        ass_cache_dec_ref(val);
+        return NULL;
+    }
     if (!val)
         return NULL;
 
@@ -219,6 +223,7 @@ get_cached_metrics(struct ass_shaper_metrics_data *metrics, FT_Face face,
     if (FT_Load_Glyph(face, glyph, load_flags)) {
         val->metrics.width = -1;
         ass_cache_commit(val, 1);
+        ass_cache_dec_ref(val);
         return NULL;
     }
 
@@ -244,12 +249,13 @@ get_glyph(hb_font_t *font, void *font_data, hb_codepoint_t unicode,
         *glyph = FT_Face_GetCharVariantIndex(face, ass_font_index_magic(face, unicode), variation);
     else
         *glyph = FT_Get_Char_Index(face, ass_font_index_magic(face, unicode));
+    if (!*glyph)
+        return false;
 
     // rotate glyph advances for @fonts while we still know the Unicode codepoints
-    if (*glyph != 0)
-        get_cached_metrics(metrics_priv, face, unicode, *glyph);
-
-    return *glyph != 0;
+    GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, unicode, *glyph);
+    ass_cache_dec_ref(metrics);
+    return true;
 }
 
 static hb_position_t
@@ -259,11 +265,12 @@ cached_h_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
     FT_Face face = font_data;
     struct ass_shaper_metrics_data *metrics_priv = user_data;
     GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
-
     if (!metrics)
         return 0;
 
-    return metrics->metrics.horiAdvance;
+    hb_position_t advance = metrics->metrics.horiAdvance;
+    ass_cache_dec_ref(metrics);
+    return advance;
 }
 
 static hb_position_t
@@ -273,19 +280,19 @@ cached_v_advance(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
     FT_Face face = font_data;
     struct ass_shaper_metrics_data *metrics_priv = user_data;
     GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
-
     if (!metrics)
         return 0;
 
-    return metrics->metrics.vertAdvance;
-
+    hb_position_t advance = metrics->metrics.vertAdvance;
+    ass_cache_dec_ref(metrics);
+    return advance;
 }
 
 static hb_bool_t
 cached_h_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
                 hb_position_t *x, hb_position_t *y, void *user_data)
 {
-    return 1;
+    return true;
 }
 
 static hb_bool_t
@@ -295,14 +302,13 @@ cached_v_origin(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
     FT_Face face = font_data;
     struct ass_shaper_metrics_data *metrics_priv = user_data;
     GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
-
     if (!metrics)
-        return 0;
+        return false;
 
     *x = metrics->metrics.horiBearingX - metrics->metrics.vertBearingX;
     *y = metrics->metrics.horiBearingY - (-metrics->metrics.vertBearingY);
-
-    return 1;
+    ass_cache_dec_ref(metrics);
+    return true;
 }
 
 static hb_position_t
@@ -312,7 +318,7 @@ get_h_kerning(hb_font_t *font, void *font_data, hb_codepoint_t first,
     FT_Face face = font_data;
     FT_Vector kern;
 
-    if (FT_Get_Kerning (face, first, second, FT_KERNING_DEFAULT, &kern))
+    if (FT_Get_Kerning(face, first, second, FT_KERNING_DEFAULT, &kern))
         return 0;
 
     return kern.x;
@@ -332,16 +338,15 @@ cached_extents(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
     FT_Face face = font_data;
     struct ass_shaper_metrics_data *metrics_priv = user_data;
     GlyphMetricsHashValue *metrics = get_cached_metrics(metrics_priv, face, 0, glyph);
-
     if (!metrics)
-        return 0;
+        return false;
 
     extents->x_bearing = metrics->metrics.horiBearingX;
     extents->y_bearing = metrics->metrics.horiBearingY;
     extents->width     = metrics->metrics.width;
     extents->height    = -metrics->metrics.height;
-
-    return 1;
+    ass_cache_dec_ref(metrics);
+    return true;
 }
 
 static hb_bool_t
@@ -354,15 +359,14 @@ get_contour_point(hb_font_t *font, void *font_data, hb_codepoint_t glyph,
         | FT_LOAD_IGNORE_TRANSFORM;
 
     if (FT_Load_Glyph(face, glyph, load_flags))
-        return 0;
+        return false;
 
     if (point_index >= (unsigned)face->glyph->outline.n_points)
-        return 0;
+        return false;
 
     *x = face->glyph->outline.points[point_index].x;
     *y = face->glyph->outline.points[point_index].y;
-
-    return 1;
+    return true;
 }
 
 /**