2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
3 * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
5 * This file is part of libass.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 #include FT_FREETYPE_H
29 #include "ass_utils.h"
31 #include "ass_fontconfig.h"
33 #include "ass_bitmap.h"
34 #include "ass_cache.h"
36 // type-specific functions
37 // create hash/compare functions for bitmap, glyph and composite cache
38 #define CREATE_HASH_FUNCTIONS
39 #include "ass_cache_template.h"
40 #define CREATE_COMPARISON_FUNCTIONS
41 #include "ass_cache_template.h"
44 static unsigned font_hash(void *buf, size_t len)
46 ASS_FontDesc *desc = buf;
48 hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
49 hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
50 hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
51 hval = fnv_32a_buf(&desc->treat_family_as_pattern,
52 sizeof(desc->treat_family_as_pattern), hval);
53 hval = fnv_32a_buf(&desc->vertical, sizeof(desc->vertical), hval);
57 static unsigned font_compare(void *key1, void *key2, size_t key_size)
59 ASS_FontDesc *a = key1;
60 ASS_FontDesc *b = key2;
61 if (strcmp(a->family, b->family) != 0)
63 if (a->bold != b->bold)
65 if (a->italic != b->italic)
67 if (a->treat_family_as_pattern != b->treat_family_as_pattern)
69 if (a->vertical != b->vertical)
74 static void font_destruct(void *key, void *value)
81 static void bitmap_destruct(void *key, void *value)
83 BitmapHashValue *v = value;
85 ass_free_bitmap(v->bm);
87 ass_free_bitmap(v->bm_o);
89 ass_free_bitmap(v->bm_s);
94 static size_t bitmap_size(void *value, size_t value_size)
96 BitmapHashValue *val = value;
98 return val->bm_o->w * val->bm_o->h * 3;
100 return val->bm->w * val->bm->h * 3;
105 static void glyph_destruct(void *key, void *value)
107 GlyphHashValue *v = value;
109 outline_free(v->lib, v->outline);
111 outline_free(v->lib, v->border);
116 static size_t glyph_size(void *value, size_t value_size)
119 GlyphHashValue *val = value;
120 if (val->glyph && val->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
121 FT_Bitmap *bitmap = &((FT_BitmapGlyph) val->glyph)->bitmap;
122 return bitmap->rows * bitmap->pitch;
129 static void composite_destruct(void *key, void *value)
131 CompositeHashValue *v = value;
140 typedef struct cache_item {
143 struct cache_item *next;
150 HashFunction hash_func;
152 HashCompare compare_func;
153 CacheItemDestructor destruct_func;
163 // Hash for a simple (single value or array) type
164 static unsigned hash_simple(void *key, size_t key_size)
166 return fnv_32a_buf(key, key_size, FNV1_32A_INIT);
169 // Comparison of a simple type
170 static unsigned compare_simple(void *a, void *b, size_t key_size)
172 return memcmp(a, b, key_size) == 0;
175 // Default destructor
176 static void destruct_simple(void *key, void *value)
183 // Create a cache with type-specific hash/compare/destruct/size functions
184 Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func,
185 CacheItemDestructor destruct_func, ItemSize size_func,
186 size_t key_size, size_t value_size)
188 Cache *cache = calloc(1, sizeof(*cache));
189 cache->buckets = 0xFFFF;
190 cache->hash_func = hash_simple;
191 cache->compare_func = compare_simple;
192 cache->destruct_func = destruct_simple;
193 cache->size_func = size_func;
195 cache->hash_func = hash_func;
197 cache->compare_func = compare_func;
199 cache->destruct_func = destruct_func;
200 cache->key_size = key_size;
201 cache->value_size = value_size;
202 cache->map = calloc(cache->buckets, sizeof(CacheItem *));
207 void *ass_cache_put(Cache *cache, void *key, void *value)
209 unsigned bucket = cache->hash_func(key, cache->key_size) % cache->buckets;
210 CacheItem **item = &cache->map[bucket];
212 *item = (*item)->next;
213 (*item) = calloc(1, sizeof(CacheItem));
214 (*item)->key = malloc(cache->key_size);
215 (*item)->value = malloc(cache->value_size);
216 memcpy((*item)->key, key, cache->key_size);
217 memcpy((*item)->value, value, cache->value_size);
220 if (cache->size_func)
221 cache->cache_size += cache->size_func(value, cache->value_size);
223 return (*item)->value;
226 void *ass_cache_get(Cache *cache, void *key)
228 unsigned bucket = cache->hash_func(key, cache->key_size) % cache->buckets;
229 CacheItem *item = cache->map[bucket];
231 if (cache->compare_func(key, item->key, cache->key_size)) {
241 size_t ass_cache_empty(Cache *cache, size_t max_size)
245 if (cache->cache_size < max_size)
246 return cache->cache_size;
248 for (i = 0; i < cache->buckets; i++) {
249 CacheItem *item = cache->map[i];
251 CacheItem *next = item->next;
252 cache->destruct_func(item->key, item->value);
256 cache->map[i] = NULL;
259 cache->items = cache->hits = cache->misses = cache->cache_size = 0;
264 void ass_cache_stats(Cache *cache, size_t *size, unsigned *hits,
265 unsigned *misses, unsigned *count)
267 *size = cache->cache_size;
269 *misses = cache->misses;
270 *count = cache->items;
273 void ass_cache_done(Cache *cache)
275 ass_cache_empty(cache, 0);
280 // Type-specific creation function
281 Cache *ass_font_cache_create(void)
283 return ass_cache_create(font_hash, font_compare, font_destruct,
284 (ItemSize)NULL, sizeof(ASS_FontDesc), sizeof(ASS_Font));
287 Cache *ass_glyph_cache_create(void)
289 return ass_cache_create(glyph_hash, glyph_compare, glyph_destruct,
290 glyph_size, sizeof(GlyphHashKey), sizeof(GlyphHashValue));
293 Cache *ass_bitmap_cache_create(void)
295 return ass_cache_create(bitmap_hash, bitmap_compare, bitmap_destruct,
296 bitmap_size, sizeof(BitmapHashKey), sizeof(BitmapHashValue));
299 Cache *ass_composite_cache_create(void)
301 return ass_cache_create(composite_hash, composite_compare,
302 composite_destruct, (ItemSize)NULL, sizeof(CompositeHashKey),
303 sizeof(CompositeHashValue));