Mercurial > mplayer.hg
annotate libass/ass_cache.c @ 36215:4eb27365d0b0
Add hack to fix compilation issues on OSX with broken libiconv.
Such a hack is not really a good solution, but since the
issue is relatively common it seems worth it for the moment.
author | reimar |
---|---|
date | Sun, 09 Jun 2013 13:54:47 +0000 |
parents | 6e7f60f6f9d4 |
children |
rev | line source |
---|---|
20008
fa122b7c71c6
Add copyright notice and vim/emacs comments to libass and vf_ass.c.
eugeni
parents:
19965
diff
changeset
|
1 /* |
26723 | 2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> |
34295 | 3 * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx> |
26723 | 4 * |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
5 * This file is part of libass. |
26723 | 6 * |
34011 | 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. | |
26723 | 10 * |
34011 | 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. | |
26723 | 18 */ |
20008
fa122b7c71c6
Add copyright notice and vim/emacs comments to libass and vf_ass.c.
eugeni
parents:
19965
diff
changeset
|
19 |
18937 | 20 #include "config.h" |
21 | |
22292 | 22 #include <inttypes.h> |
18937 | 23 #include <ft2build.h> |
34295 | 24 #include FT_OUTLINE_H |
18937 | 25 #include <assert.h> |
26 | |
30200 | 27 #include "ass_utils.h" |
21322 | 28 #include "ass_font.h" |
18937 | 29 #include "ass_cache.h" |
30 | |
34295 | 31 // type-specific functions |
32 // create hash/compare functions for bitmap, outline and composite cache | |
33 #define CREATE_HASH_FUNCTIONS | |
34 #include "ass_cache_template.h" | |
35 #define CREATE_COMPARISON_FUNCTIONS | |
36 #include "ass_cache_template.h" | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28860
diff
changeset
|
37 |
23016 | 38 // font cache |
34295 | 39 static unsigned font_hash(void *buf, size_t len) |
23016 | 40 { |
30200 | 41 ASS_FontDesc *desc = buf; |
42 unsigned hval; | |
43 hval = fnv_32a_str(desc->family, FNV1_32A_INIT); | |
44 hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval); | |
45 hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval); | |
34295 | 46 hval = fnv_32a_buf(&desc->treat_family_as_pattern, |
47 sizeof(desc->treat_family_as_pattern), hval); | |
48 hval = fnv_32a_buf(&desc->vertical, sizeof(desc->vertical), hval); | |
30200 | 49 return hval; |
23016 | 50 } |
51 | |
34295 | 52 static unsigned font_compare(void *key1, void *key2, size_t key_size) |
30200 | 53 { |
54 ASS_FontDesc *a = key1; | |
55 ASS_FontDesc *b = key2; | |
56 if (strcmp(a->family, b->family) != 0) | |
57 return 0; | |
58 if (a->bold != b->bold) | |
59 return 0; | |
60 if (a->italic != b->italic) | |
61 return 0; | |
62 if (a->treat_family_as_pattern != b->treat_family_as_pattern) | |
63 return 0; | |
31853 | 64 if (a->vertical != b->vertical) |
65 return 0; | |
30200 | 66 return 1; |
18937 | 67 } |
68 | |
34295 | 69 static void font_destruct(void *key, void *value) |
23016 | 70 { |
30200 | 71 ass_font_free(value); |
72 free(key); | |
23016 | 73 } |
74 | |
23017 | 75 // bitmap cache |
34295 | 76 static void bitmap_destruct(void *key, void *value) |
23016 | 77 { |
30200 | 78 BitmapHashValue *v = value; |
34295 | 79 BitmapHashKey *k = key; |
30200 | 80 if (v->bm) |
81 ass_free_bitmap(v->bm); | |
82 if (v->bm_o) | |
83 ass_free_bitmap(v->bm_o); | |
84 if (v->bm_s) | |
85 ass_free_bitmap(v->bm_s); | |
34295 | 86 if (k->type == BITMAP_CLIP) |
87 free(k->u.clip.text); | |
30200 | 88 free(key); |
89 free(value); | |
18937 | 90 } |
91 | |
34295 | 92 static size_t bitmap_size(void *value, size_t value_size) |
18937 | 93 { |
34295 | 94 BitmapHashValue *val = value; |
95 if (val->bm_o) | |
96 return val->bm_o->w * val->bm_o->h * 3; | |
97 else if (val->bm) | |
98 return val->bm->w * val->bm->h * 3; | |
99 return 0; | |
19539 | 100 } |
101 | |
34295 | 102 static unsigned bitmap_hash(void *key, size_t key_size) |
23018 | 103 { |
34295 | 104 BitmapHashKey *k = key; |
105 switch (k->type) { | |
106 case BITMAP_OUTLINE: return outline_bitmap_hash(&k->u, key_size); | |
107 case BITMAP_CLIP: return clip_bitmap_hash(&k->u, key_size); | |
108 default: return 0; | |
109 } | |
23018 | 110 } |
111 | |
34295 | 112 static unsigned bitmap_compare (void *a, void *b, size_t key_size) |
23018 | 113 { |
34295 | 114 BitmapHashKey *ak = a; |
115 BitmapHashKey *bk = b; | |
116 if (ak->type != bk->type) return 0; | |
117 switch (ak->type) { | |
118 case BITMAP_OUTLINE: return outline_bitmap_compare(&ak->u, &bk->u, key_size); | |
119 case BITMAP_CLIP: return clip_bitmap_compare(&ak->u, &bk->u, key_size); | |
120 default: return 0; | |
121 } | |
23018 | 122 } |
123 | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
124 // composite cache |
34295 | 125 static void composite_destruct(void *key, void *value) |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
126 { |
30200 | 127 CompositeHashValue *v = value; |
128 free(v->a); | |
129 free(v->b); | |
130 free(key); | |
131 free(value); | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
132 } |
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
133 |
34295 | 134 // outline cache |
135 | |
136 static unsigned outline_hash(void *key, size_t key_size) | |
137 { | |
138 OutlineHashKey *k = key; | |
139 switch (k->type) { | |
140 case OUTLINE_GLYPH: return glyph_hash(&k->u, key_size); | |
141 case OUTLINE_DRAWING: return drawing_hash(&k->u, key_size); | |
142 default: return 0; | |
143 } | |
144 } | |
145 | |
146 static unsigned outline_compare(void *a, void *b, size_t key_size) | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
147 { |
34295 | 148 OutlineHashKey *ak = a; |
149 OutlineHashKey *bk = b; | |
150 if (ak->type != bk->type) return 0; | |
151 switch (ak->type) { | |
152 case OUTLINE_GLYPH: return glyph_compare(&ak->u, &bk->u, key_size); | |
153 case OUTLINE_DRAWING: return drawing_compare(&ak->u, &bk->u, key_size); | |
154 default: return 0; | |
155 } | |
156 } | |
157 | |
158 static void outline_destruct(void *key, void *value) | |
159 { | |
160 OutlineHashValue *v = value; | |
161 OutlineHashKey *k = key; | |
162 if (v->outline) | |
163 outline_free(v->lib, v->outline); | |
164 if (v->border) | |
165 outline_free(v->lib, v->border); | |
166 if (k->type == OUTLINE_DRAWING) | |
167 free(k->u.drawing.text); | |
168 free(key); | |
169 free(value); | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
170 } |
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
171 |
34295 | 172 |
173 | |
174 // Cache data | |
175 typedef struct cache_item { | |
176 void *key; | |
177 void *value; | |
178 struct cache_item *next; | |
179 } CacheItem; | |
180 | |
181 struct cache { | |
182 unsigned buckets; | |
183 CacheItem **map; | |
184 | |
185 HashFunction hash_func; | |
186 ItemSize size_func; | |
187 HashCompare compare_func; | |
188 CacheItemDestructor destruct_func; | |
189 size_t key_size; | |
190 size_t value_size; | |
191 | |
192 size_t cache_size; | |
193 unsigned hits; | |
194 unsigned misses; | |
195 unsigned items; | |
196 }; | |
197 | |
198 // Hash for a simple (single value or array) type | |
199 static unsigned hash_simple(void *key, size_t key_size) | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
200 { |
34295 | 201 return fnv_32a_buf(key, key_size, FNV1_32A_INIT); |
202 } | |
203 | |
204 // Comparison of a simple type | |
205 static unsigned compare_simple(void *a, void *b, size_t key_size) | |
206 { | |
207 return memcmp(a, b, key_size) == 0; | |
208 } | |
209 | |
210 // Default destructor | |
211 static void destruct_simple(void *key, void *value) | |
212 { | |
213 free(key); | |
214 free(value); | |
215 } | |
216 | |
217 | |
218 // Create a cache with type-specific hash/compare/destruct/size functions | |
219 Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func, | |
220 CacheItemDestructor destruct_func, ItemSize size_func, | |
221 size_t key_size, size_t value_size) | |
222 { | |
223 Cache *cache = calloc(1, sizeof(*cache)); | |
224 cache->buckets = 0xFFFF; | |
225 cache->hash_func = hash_simple; | |
226 cache->compare_func = compare_simple; | |
227 cache->destruct_func = destruct_simple; | |
228 cache->size_func = size_func; | |
229 if (hash_func) | |
230 cache->hash_func = hash_func; | |
231 if (compare_func) | |
232 cache->compare_func = compare_func; | |
233 if (destruct_func) | |
234 cache->destruct_func = destruct_func; | |
235 cache->key_size = key_size; | |
236 cache->value_size = value_size; | |
237 cache->map = calloc(cache->buckets, sizeof(CacheItem *)); | |
238 | |
239 return cache; | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
240 } |
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
241 |
34295 | 242 void *ass_cache_put(Cache *cache, void *key, void *value) |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
243 { |
34295 | 244 unsigned bucket = cache->hash_func(key, cache->key_size) % cache->buckets; |
245 CacheItem **item = &cache->map[bucket]; | |
246 while (*item) | |
247 item = &(*item)->next; | |
248 (*item) = calloc(1, sizeof(CacheItem)); | |
249 (*item)->key = malloc(cache->key_size); | |
250 (*item)->value = malloc(cache->value_size); | |
251 memcpy((*item)->key, key, cache->key_size); | |
252 memcpy((*item)->value, value, cache->value_size); | |
253 | |
254 cache->items++; | |
255 if (cache->size_func) | |
256 cache->cache_size += cache->size_func(value, cache->value_size); | |
257 else | |
258 cache->cache_size++; | |
259 | |
260 return (*item)->value; | |
261 } | |
262 | |
263 void *ass_cache_get(Cache *cache, void *key) | |
264 { | |
265 unsigned bucket = cache->hash_func(key, cache->key_size) % cache->buckets; | |
266 CacheItem *item = cache->map[bucket]; | |
267 while (item) { | |
268 if (cache->compare_func(key, item->key, cache->key_size)) { | |
269 cache->hits++; | |
270 return item->value; | |
271 } | |
272 item = item->next; | |
273 } | |
274 cache->misses++; | |
275 return NULL; | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
276 } |
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
277 |
34295 | 278 int ass_cache_empty(Cache *cache, size_t max_size) |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
279 { |
34295 | 280 int i; |
281 | |
282 if (cache->cache_size < max_size) | |
283 return 0; | |
284 | |
285 for (i = 0; i < cache->buckets; i++) { | |
286 CacheItem *item = cache->map[i]; | |
287 while (item) { | |
288 CacheItem *next = item->next; | |
289 cache->destruct_func(item->key, item->value); | |
290 free(item); | |
291 item = next; | |
292 } | |
293 cache->map[i] = NULL; | |
294 } | |
295 | |
296 cache->items = cache->hits = cache->misses = cache->cache_size = 0; | |
297 | |
298 return 1; | |
299 } | |
300 | |
301 void ass_cache_stats(Cache *cache, size_t *size, unsigned *hits, | |
302 unsigned *misses, unsigned *count) | |
303 { | |
304 if (size) | |
305 *size = cache->cache_size; | |
306 if (hits) | |
307 *hits = cache->hits; | |
308 if (misses) | |
309 *misses = cache->misses; | |
310 if (count) | |
311 *count = cache->items; | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
312 } |
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
313 |
34295 | 314 void ass_cache_done(Cache *cache) |
315 { | |
316 ass_cache_empty(cache, 0); | |
317 free(cache->map); | |
318 free(cache); | |
319 } | |
320 | |
321 // Type-specific creation function | |
322 Cache *ass_font_cache_create(void) | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
323 { |
34295 | 324 return ass_cache_create(font_hash, font_compare, font_destruct, |
325 (ItemSize)NULL, sizeof(ASS_FontDesc), sizeof(ASS_Font)); | |
326 } | |
327 | |
328 Cache *ass_outline_cache_create(void) | |
329 { | |
330 return ass_cache_create(outline_hash, outline_compare, outline_destruct, | |
331 NULL, sizeof(OutlineHashKey), sizeof(OutlineHashValue)); | |
332 } | |
30200 | 333 |
34295 | 334 Cache *ass_glyph_metrics_cache_create(void) |
335 { | |
336 return ass_cache_create(glyph_metrics_hash, glyph_metrics_compare, NULL, | |
337 (ItemSize) NULL, sizeof(GlyphMetricsHashKey), | |
338 sizeof(GlyphMetricsHashValue)); | |
28789
a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
greg
parents:
26759
diff
changeset
|
339 } |
34295 | 340 |
341 Cache *ass_bitmap_cache_create(void) | |
342 { | |
343 return ass_cache_create(bitmap_hash, bitmap_compare, bitmap_destruct, | |
344 bitmap_size, sizeof(BitmapHashKey), sizeof(BitmapHashValue)); | |
345 } | |
346 | |
347 Cache *ass_composite_cache_create(void) | |
348 { | |
349 return ass_cache_create(composite_hash, composite_compare, | |
350 composite_destruct, (ItemSize)NULL, sizeof(CompositeHashKey), | |
351 sizeof(CompositeHashValue)); | |
352 } |