2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
4 * This file is part of libass.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include FT_FREETYPE_H
28 #include "ass_utils.h"
30 #include "ass_fontconfig.h"
32 #include "ass_bitmap.h"
33 #include "ass_cache.h"
35 static unsigned hashmap_hash(void *buf
, size_t len
)
37 return fnv_32a_buf(buf
, len
, FNV1_32A_INIT
);
40 static int hashmap_key_compare(void *a
, void *b
, size_t size
)
42 return memcmp(a
, b
, size
) == 0;
45 static void hashmap_item_dtor(void *key
, size_t key_size
, void *value
,
52 Hashmap
*hashmap_init(ASS_Library
*library
, size_t key_size
,
53 size_t value_size
, int nbuckets
,
54 HashmapItemDtor item_dtor
,
55 HashmapKeyCompare key_compare
,
58 Hashmap
*map
= calloc(1, sizeof(Hashmap
));
59 map
->library
= library
;
60 map
->nbuckets
= nbuckets
;
61 map
->key_size
= key_size
;
62 map
->value_size
= value_size
;
63 map
->root
= calloc(nbuckets
, sizeof(hashmap_item_p
));
64 map
->item_dtor
= item_dtor
? item_dtor
: hashmap_item_dtor
;
65 map
->key_compare
= key_compare
? key_compare
: hashmap_key_compare
;
66 map
->hash
= hash
? hash
: hashmap_hash
;
70 void hashmap_done(Hashmap
*map
)
74 if (map
->count
> 0 || map
->hit_count
+ map
->miss_count
> 0)
75 ass_msg(map
->library
, MSGL_V
,
76 "cache statistics: \n total accesses: %d\n hits: %d\n "
77 "misses: %d\n object count: %d",
78 map
->hit_count
+ map
->miss_count
, map
->hit_count
,
79 map
->miss_count
, map
->count
);
81 for (i
= 0; i
< map
->nbuckets
; ++i
) {
82 HashmapItem
*item
= map
->root
[i
];
84 HashmapItem
*next
= item
->next
;
85 map
->item_dtor(item
->key
, map
->key_size
, item
->value
,
95 // does nothing if key already exists
96 void *hashmap_insert(Hashmap
*map
, void *key
, void *value
)
98 unsigned hash
= map
->hash(key
, map
->key_size
);
99 HashmapItem
**next
= map
->root
+ (hash
% map
->nbuckets
);
101 if (map
->key_compare(key
, (*next
)->key
, map
->key_size
))
102 return (*next
)->value
;
103 next
= &((*next
)->next
);
106 (*next
) = malloc(sizeof(HashmapItem
));
107 (*next
)->key
= malloc(map
->key_size
);
108 (*next
)->value
= malloc(map
->value_size
);
109 memcpy((*next
)->key
, key
, map
->key_size
);
110 memcpy((*next
)->value
, value
, map
->value_size
);
114 return (*next
)->value
;
117 void *hashmap_find(Hashmap
*map
, void *key
)
119 unsigned hash
= map
->hash(key
, map
->key_size
);
120 HashmapItem
*item
= map
->root
[hash
% map
->nbuckets
];
122 if (map
->key_compare(key
, item
->key
, map
->key_size
)) {
132 //---------------------------------
135 static unsigned font_desc_hash(void *buf
, size_t len
)
137 ASS_FontDesc
*desc
= buf
;
139 hval
= fnv_32a_str(desc
->family
, FNV1_32A_INIT
);
140 hval
= fnv_32a_buf(&desc
->bold
, sizeof(desc
->bold
), hval
);
141 hval
= fnv_32a_buf(&desc
->italic
, sizeof(desc
->italic
), hval
);
145 static int font_compare(void *key1
, void *key2
, size_t key_size
)
147 ASS_FontDesc
*a
= key1
;
148 ASS_FontDesc
*b
= key2
;
149 if (strcmp(a
->family
, b
->family
) != 0)
151 if (a
->bold
!= b
->bold
)
153 if (a
->italic
!= b
->italic
)
155 if (a
->treat_family_as_pattern
!= b
->treat_family_as_pattern
)
157 if (a
->vertical
!= b
->vertical
)
162 static void font_hash_dtor(void *key
, size_t key_size
, void *value
,
165 ass_font_free(value
);
169 ASS_Font
*ass_font_cache_find(Hashmap
*font_cache
,
172 return hashmap_find(font_cache
, desc
);
176 * \brief Add a face struct to cache.
177 * \param font font struct
179 void *ass_font_cache_add(Hashmap
*font_cache
, ASS_Font
*font
)
181 return hashmap_insert(font_cache
, &(font
->desc
), font
);
184 Hashmap
*ass_font_cache_init(ASS_Library
*library
)
187 font_cache
= hashmap_init(library
, sizeof(ASS_FontDesc
),
190 font_hash_dtor
, font_compare
, font_desc_hash
);
194 void ass_font_cache_done(Hashmap
*font_cache
)
196 hashmap_done(font_cache
);
200 // Create hash/compare functions for bitmap and glyph
201 #define CREATE_HASH_FUNCTIONS
202 #include "ass_cache_template.h"
203 #define CREATE_COMPARISON_FUNCTIONS
204 #include "ass_cache_template.h"
206 //---------------------------------
209 static void bitmap_hash_dtor(void *key
, size_t key_size
, void *value
,
212 BitmapHashValue
*v
= value
;
214 ass_free_bitmap(v
->bm
);
216 ass_free_bitmap(v
->bm_o
);
218 ass_free_bitmap(v
->bm_s
);
223 void *cache_add_bitmap(Hashmap
*bitmap_cache
, BitmapHashKey
*key
,
224 BitmapHashValue
*val
)
226 // Note: this is only an approximation
228 bitmap_cache
->cache_size
+= val
->bm_o
->w
* val
->bm_o
->h
* 3;
230 bitmap_cache
->cache_size
+= val
->bm
->w
* val
->bm
->h
* 3;
232 return hashmap_insert(bitmap_cache
, key
, val
);
236 * \brief Get a bitmap from bitmap cache.
237 * \param key hash key
238 * \return requested hash val or 0 if not found
240 BitmapHashValue
*cache_find_bitmap(Hashmap
*bitmap_cache
,
243 return hashmap_find(bitmap_cache
, key
);
246 Hashmap
*ass_bitmap_cache_init(ASS_Library
*library
)
248 Hashmap
*bitmap_cache
;
249 bitmap_cache
= hashmap_init(library
,
250 sizeof(BitmapHashKey
),
251 sizeof(BitmapHashValue
),
253 bitmap_hash_dtor
, bitmap_compare
,
258 void ass_bitmap_cache_done(Hashmap
*bitmap_cache
)
260 hashmap_done(bitmap_cache
);
263 Hashmap
*ass_bitmap_cache_reset(Hashmap
*bitmap_cache
)
265 ASS_Library
*lib
= bitmap_cache
->library
;
267 ass_bitmap_cache_done(bitmap_cache
);
268 return ass_bitmap_cache_init(lib
);
271 //---------------------------------
274 static void glyph_hash_dtor(void *key
, size_t key_size
, void *value
,
277 GlyphHashValue
*v
= value
;
279 FT_Done_Glyph(v
->glyph
);
280 if (v
->outline_glyph
)
281 FT_Done_Glyph(v
->outline_glyph
);
286 void *cache_add_glyph(Hashmap
*glyph_cache
, GlyphHashKey
*key
,
289 if (val
->glyph
&& val
->glyph
->format
== FT_GLYPH_FORMAT_BITMAP
) {
290 FT_Bitmap
*bitmap
= &((FT_BitmapGlyph
) val
->glyph
)->bitmap
;
291 glyph_cache
->cache_size
+= bitmap
->rows
* bitmap
->pitch
;
294 return hashmap_insert(glyph_cache
, key
, val
);
298 * \brief Get a glyph from glyph cache.
299 * \param key hash key
300 * \return requested hash val or 0 if not found
302 GlyphHashValue
*cache_find_glyph(Hashmap
*glyph_cache
,
305 return hashmap_find(glyph_cache
, key
);
308 Hashmap
*ass_glyph_cache_init(ASS_Library
*library
)
310 Hashmap
*glyph_cache
;
311 glyph_cache
= hashmap_init(library
, sizeof(GlyphHashKey
),
312 sizeof(GlyphHashValue
),
314 glyph_hash_dtor
, glyph_compare
, glyph_hash
);
318 void ass_glyph_cache_done(Hashmap
*glyph_cache
)
320 hashmap_done(glyph_cache
);
323 Hashmap
*ass_glyph_cache_reset(Hashmap
*glyph_cache
)
325 ASS_Library
*lib
= glyph_cache
->library
;
327 ass_glyph_cache_done(glyph_cache
);
328 return ass_glyph_cache_init(lib
);
332 //---------------------------------
335 static void composite_hash_dtor(void *key
, size_t key_size
, void *value
,
338 CompositeHashValue
*v
= value
;
345 void *cache_add_composite(Hashmap
*composite_cache
,
346 CompositeHashKey
*key
,
347 CompositeHashValue
*val
)
349 return hashmap_insert(composite_cache
, key
, val
);
353 * \brief Get a composite bitmap from composite cache.
354 * \param key hash key
355 * \return requested hash val or 0 if not found
357 CompositeHashValue
*cache_find_composite(Hashmap
*composite_cache
,
358 CompositeHashKey
*key
)
360 return hashmap_find(composite_cache
, key
);
363 Hashmap
*ass_composite_cache_init(ASS_Library
*library
)
365 Hashmap
*composite_cache
;
366 composite_cache
= hashmap_init(library
, sizeof(CompositeHashKey
),
367 sizeof(CompositeHashValue
),
369 composite_hash_dtor
, composite_compare
,
371 return composite_cache
;
374 void ass_composite_cache_done(Hashmap
*composite_cache
)
376 hashmap_done(composite_cache
);
379 Hashmap
*ass_composite_cache_reset(Hashmap
*composite_cache
)
381 ASS_Library
*lib
= composite_cache
->library
;
383 ass_composite_cache_done(composite_cache
);
384 return ass_composite_cache_init(lib
);