1 // -*- c-basic-offset: 8; indent-tabs-mode: t -*-
2 // vim:ts=8:sw=8:noet:ai:
4 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
6 * This file is part of libass.
8 * libass is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * libass is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with libass; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include FT_FREETYPE_H
34 #include "ass_fontconfig.h"
36 #include "ass_bitmap.h"
37 #include "ass_cache.h"
40 typedef struct hashmap_item_s
{
43 struct hashmap_item_s
* next
;
45 typedef hashmap_item_t
* hashmap_item_p
;
49 size_t key_size
, value_size
;
51 hashmap_item_dtor_t item_dtor
; // a destructor for hashmap key/value pairs
52 hashmap_key_compare_t key_compare
;
60 #define FNV1_32A_INIT (unsigned)0x811c9dc5
62 static inline unsigned fnv_32a_buf(void* buf
, size_t len
, unsigned hval
)
64 unsigned char *bp
= buf
;
65 unsigned char *be
= bp
+ len
;
67 hval
^= (unsigned)*bp
++;
68 hval
+= (hval
<<1) + (hval
<<4) + (hval
<<7) + (hval
<<8) + (hval
<<24);
72 static inline unsigned fnv_32a_str(char* str
, unsigned hval
)
74 unsigned char* s
= (unsigned char*)str
;
76 hval
^= (unsigned)*s
++;
77 hval
+= (hval
<<1) + (hval
<<4) + (hval
<<7) + (hval
<<8) + (hval
<<24);
82 static unsigned hashmap_hash(void* buf
, size_t len
)
84 return fnv_32a_buf(buf
, len
, FNV1_32A_INIT
);
87 static int hashmap_key_compare(void* a
, void* b
, size_t size
)
89 return memcmp(a
, b
, size
) == 0;
92 static void hashmap_item_dtor(void* key
, size_t key_size
, void* value
, size_t value_size
)
98 hashmap_t
* hashmap_init(size_t key_size
, size_t value_size
, int nbuckets
,
99 hashmap_item_dtor_t item_dtor
, hashmap_key_compare_t key_compare
,
102 hashmap_t
* map
= calloc(1, sizeof(hashmap_t
));
103 map
->nbuckets
= nbuckets
;
104 map
->key_size
= key_size
;
105 map
->value_size
= value_size
;
106 map
->root
= calloc(nbuckets
, sizeof(hashmap_item_p
));
107 map
->item_dtor
= item_dtor
? item_dtor
: hashmap_item_dtor
;
108 map
->key_compare
= key_compare
? key_compare
: hashmap_key_compare
;
109 map
->hash
= hash
? hash
: hashmap_hash
;
113 void hashmap_done(hashmap_t
* map
)
117 if (map
->count
> 0 || map
->hit_count
+ map
->miss_count
> 0)
118 mp_msg(MSGT_ASS
, MSGL_V
, "cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n",
119 map
->hit_count
+ map
->miss_count
, map
->hit_count
, map
->miss_count
, map
->count
);
121 for (i
= 0; i
< map
->nbuckets
; ++i
) {
122 hashmap_item_t
* item
= map
->root
[i
];
124 hashmap_item_t
* next
= item
->next
;
125 map
->item_dtor(item
->key
, map
->key_size
, item
->value
, map
->value_size
);
134 // does nothing if key already exists
135 void* hashmap_insert(hashmap_t
* map
, void* key
, void* value
)
137 unsigned hash
= map
->hash(key
, map
->key_size
);
138 hashmap_item_t
** next
= map
->root
+ (hash
% map
->nbuckets
);
140 if (map
->key_compare(key
, (*next
)->key
, map
->key_size
))
141 return (*next
)->value
;
142 next
= &((*next
)->next
);
145 (*next
) = malloc(sizeof(hashmap_item_t
));
146 (*next
)->key
= malloc(map
->key_size
);
147 (*next
)->value
= malloc(map
->value_size
);
148 memcpy((*next
)->key
, key
, map
->key_size
);
149 memcpy((*next
)->value
, value
, map
->value_size
);
153 return (*next
)->value
;
156 void* hashmap_find(hashmap_t
* map
, void* key
)
158 unsigned hash
= map
->hash(key
, map
->key_size
);
159 hashmap_item_t
* item
= map
->root
[hash
% map
->nbuckets
];
161 if (map
->key_compare(key
, item
->key
, map
->key_size
)) {
171 //---------------------------------
174 hashmap_t
* font_cache
;
176 static unsigned font_desc_hash(void* buf
, size_t len
)
178 ass_font_desc_t
* desc
= buf
;
180 hval
= fnv_32a_str(desc
->family
, FNV1_32A_INIT
);
181 hval
= fnv_32a_buf(&desc
->bold
, sizeof(desc
->bold
), hval
);
182 hval
= fnv_32a_buf(&desc
->italic
, sizeof(desc
->italic
), hval
);
186 static int font_compare(void* key1
, void* key2
, size_t key_size
) {
187 ass_font_desc_t
* a
= key1
;
188 ass_font_desc_t
* b
= key2
;
189 if (strcmp(a
->family
, b
->family
) != 0)
191 if (a
->bold
!= b
->bold
)
193 if (a
->italic
!= b
->italic
)
198 static void font_hash_dtor(void* key
, size_t key_size
, void* value
, size_t value_size
)
200 ass_font_free(value
);
204 ass_font_t
* ass_font_cache_find(ass_font_desc_t
* desc
)
206 return hashmap_find(font_cache
, desc
);
210 * \brief Add a face struct to cache.
211 * \param font font struct
213 void* ass_font_cache_add(ass_font_t
* font
)
215 return hashmap_insert(font_cache
, &(font
->desc
), font
);
218 void ass_font_cache_init(void)
220 font_cache
= hashmap_init(sizeof(ass_font_desc_t
),
223 font_hash_dtor
, font_compare
, font_desc_hash
);
226 void ass_font_cache_done(void)
228 hashmap_done(font_cache
);
232 // Create hash/compare functions for bitmap and glyph
233 #define CREATE_HASH_FUNCTIONS
234 #include "ass_cache_template.c"
235 #define CREATE_COMPARISON_FUNCTIONS
236 #include "ass_cache_template.c"
238 //---------------------------------
241 hashmap_t
* bitmap_cache
;
243 static void bitmap_hash_dtor(void* key
, size_t key_size
, void* value
, size_t value_size
)
245 bitmap_hash_val_t
* v
= value
;
246 if (v
->bm
) ass_free_bitmap(v
->bm
);
247 if (v
->bm_o
) ass_free_bitmap(v
->bm_o
);
248 if (v
->bm_s
) ass_free_bitmap(v
->bm_s
);
253 void* cache_add_bitmap(bitmap_hash_key_t
* key
, bitmap_hash_val_t
* val
)
255 return hashmap_insert(bitmap_cache
, key
, val
);
259 * \brief Get a bitmap from bitmap cache.
260 * \param key hash key
261 * \return requested hash val or 0 if not found
263 bitmap_hash_val_t
* cache_find_bitmap(bitmap_hash_key_t
* key
)
265 return hashmap_find(bitmap_cache
, key
);
268 void ass_bitmap_cache_init(void)
270 bitmap_cache
= hashmap_init(sizeof(bitmap_hash_key_t
),
271 sizeof(bitmap_hash_val_t
),
273 bitmap_hash_dtor
, bitmap_compare
,
277 void ass_bitmap_cache_done(void)
279 hashmap_done(bitmap_cache
);
282 void ass_bitmap_cache_reset(void)
284 ass_bitmap_cache_done();
285 ass_bitmap_cache_init();
288 //---------------------------------
291 hashmap_t
* glyph_cache
;
293 static void glyph_hash_dtor(void* key
, size_t key_size
, void* value
, size_t value_size
)
295 glyph_hash_val_t
* v
= value
;
296 if (v
->glyph
) FT_Done_Glyph(v
->glyph
);
297 if (v
->outline_glyph
) FT_Done_Glyph(v
->outline_glyph
);
302 void* cache_add_glyph(glyph_hash_key_t
* key
, glyph_hash_val_t
* val
)
304 return hashmap_insert(glyph_cache
, key
, val
);
308 * \brief Get a glyph from glyph cache.
309 * \param key hash key
310 * \return requested hash val or 0 if not found
312 glyph_hash_val_t
* cache_find_glyph(glyph_hash_key_t
* key
)
314 return hashmap_find(glyph_cache
, key
);
317 void ass_glyph_cache_init(void)
319 glyph_cache
= hashmap_init(sizeof(glyph_hash_key_t
),
320 sizeof(glyph_hash_val_t
),
322 glyph_hash_dtor
, glyph_compare
, glyph_hash
);
325 void ass_glyph_cache_done(void)
327 hashmap_done(glyph_cache
);
330 void ass_glyph_cache_reset(void)
332 ass_glyph_cache_done();
333 ass_glyph_cache_init();
337 //---------------------------------
340 hashmap_t
* composite_cache
;
342 static void composite_hash_dtor(void* key
, size_t key_size
, void* value
, size_t value_size
)
344 composite_hash_val_t
* v
= value
;
351 void* cache_add_composite(composite_hash_key_t
* key
, composite_hash_val_t
* val
)
353 return hashmap_insert(composite_cache
, key
, val
);
357 * \brief Get a composite bitmap from composite cache.
358 * \param key hash key
359 * \return requested hash val or 0 if not found
361 composite_hash_val_t
* cache_find_composite(composite_hash_key_t
* key
)
363 return hashmap_find(composite_cache
, key
);
366 void ass_composite_cache_init(void)
368 composite_cache
= hashmap_init(sizeof(composite_hash_key_t
),
369 sizeof(composite_hash_val_t
),
371 composite_hash_dtor
, NULL
, NULL
);
374 void ass_composite_cache_done(void)
376 hashmap_done(composite_cache
);
379 void ass_composite_cache_reset(void)
381 ass_composite_cache_done();
382 ass_composite_cache_init();