comparison libass/ass_cache.c @ 18937:9e95ac641e77

Initial libass release (without mencoder support).
author eugeni
date Fri, 07 Jul 2006 18:26:51 +0000
parents
children 64009ae411fb
comparison
equal deleted inserted replaced
18936:b80b0c115a24 18937:9e95ac641e77
1 #include "config.h"
2
3 #include <ft2build.h>
4 #include FT_FREETYPE_H
5
6 #include <assert.h>
7
8 #include "mp_msg.h"
9 #include "ass_fontconfig.h"
10 #include "ass_cache.h"
11
12
13 typedef struct face_cache_item_s {
14 face_desc_t desc;
15 char* path;
16 int index;
17 FT_Face face;
18 } face_cache_item_t;
19
20 #define MAX_FACE_CACHE_SIZE 100
21
22 static face_cache_item_t* face_cache;
23 static int face_cache_size;
24
25 extern int no_more_font_messages;
26
27 static int font_compare(face_desc_t* a, face_desc_t* b) {
28 if (strcmp(a->family, b->family) != 0)
29 return 0;
30 if (a->bold != b->bold)
31 return 0;
32 if (a->italic != b->italic)
33 return 0;
34 return 1;
35 }
36
37 /**
38 * \brief Get a face object, either from cache or created through FreeType+FontConfig.
39 * \param library FreeType library object
40 * \param fontconfig_priv fontconfig private data
41 * \param desc required face description
42 * \param face out: the face object
43 */
44 int ass_new_face(FT_Library library, void* fontconfig_priv, face_desc_t* desc, /*out*/ FT_Face* face)
45 {
46 FT_Error error;
47 int i;
48 char* path;
49 int index;
50 face_cache_item_t* item;
51
52 for (i=0; i<face_cache_size; ++i)
53 if (font_compare(desc, &(face_cache[i].desc))) {
54 *face = face_cache[i].face;
55 return 0;
56 }
57
58 if (face_cache_size == MAX_FACE_CACHE_SIZE) {
59 mp_msg(MSGT_GLOBAL, MSGL_FATAL, "Too many fonts\n");
60 return 1;
61 }
62
63 path = fontconfig_select(fontconfig_priv, desc->family, desc->bold, desc->italic, &index);
64
65 error = FT_New_Face(library, path, index, face);
66 if (error) {
67 if (!no_more_font_messages)
68 mp_msg(MSGT_GLOBAL, MSGL_WARN, "Error opening font: %s, %d\n", path, index);
69 no_more_font_messages = 1;
70 return 1;
71 }
72
73 item = face_cache + face_cache_size;
74 item->path = strdup(path);
75 item->index = index;
76 item->face = *face;
77 memcpy(&(item->desc), desc, sizeof(face_desc_t));
78 face_cache_size++;
79 return 0;
80 }
81
82 void ass_face_cache_init(void)
83 {
84 face_cache = calloc(MAX_FACE_CACHE_SIZE, sizeof(face_cache_item_t));
85 face_cache_size = 0;
86 }
87
88 void ass_face_cache_done(void)
89 {
90 int i;
91 for (i = 0; i < face_cache_size; ++i) {
92 face_cache_item_t* item = face_cache + i;
93 if (item->face) FT_Done_Face(item->face);
94 if (item->path) free(item->path);
95 // FIXME: free desc ?
96 }
97 free(face_cache);
98 face_cache_size = 0;
99 }
100
101 //---------------------------------
102 // glyph cache
103
104 #define GLYPH_HASH_SIZE (0xFFFF + 13)
105
106 typedef struct glyph_hash_item_s {
107 glyph_hash_key_t key;
108 glyph_hash_val_t val;
109 struct glyph_hash_item_s* next;
110 } glyph_hash_item_t;
111
112 typedef glyph_hash_item_t* glyph_hash_item_p;
113
114 static glyph_hash_item_p* glyph_hash_root;
115 static int glyph_hash_size;
116
117 static int glyph_compare(glyph_hash_key_t* a, glyph_hash_key_t* b) {
118 if (memcmp(a, b, sizeof(glyph_hash_key_t)) == 0)
119 return 1;
120 else
121 return 0;
122 }
123
124 static unsigned glyph_hash(glyph_hash_key_t* key) {
125 unsigned val = 0;
126 unsigned i;
127 for (i = 0; i < sizeof(key->face); ++i)
128 val += *(unsigned char *)(&(key->face) + i);
129 val <<= 21;
130
131 if (key->bitmap) val &= 0x80000000;
132 val += key->index;
133 val += key->size << 8;
134 val += key->outline << 3;
135 val += key->advance.x << 10;
136 val += key->advance.y << 16;
137 val += key->bold << 1;
138 val += key->italic << 20;
139 return val;
140 }
141
142 /**
143 * \brief Add a glyph to glyph cache.
144 * \param key hash key
145 * \param val hash val: 2 bitmap glyphs + some additional info
146 */
147 void cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
148 {
149 unsigned hash = glyph_hash(key);
150 glyph_hash_item_t** next = glyph_hash_root + (hash % GLYPH_HASH_SIZE);
151 while (*next) {
152 if (glyph_compare(key, &((*next)->key)))
153 return;
154 next = &((*next)->next);
155 assert(next);
156 }
157 (*next) = malloc(sizeof(glyph_hash_item_t));
158 // (*next)->desc = glyph_key_copy(key, &((*next)->key));
159 memcpy(&((*next)->key), key, sizeof(glyph_hash_key_t));
160 memcpy(&((*next)->val), val, sizeof(glyph_hash_val_t));
161 (*next)->next = 0;
162
163 glyph_hash_size ++;
164 /* if (glyph_hash_size && (glyph_hash_size % 25 == 0)) {
165 printf("\nGlyph cache: %d entries, %d bytes\n", glyph_hash_size, glyph_hash_size * sizeof(glyph_hash_item_t));
166 } */
167 }
168
169 /**
170 * \brief Get a glyph from glyph cache.
171 * \param key hash key
172 * \return requested hash val or 0 if not found
173 */
174 glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key)
175 {
176 unsigned hash = glyph_hash(key);
177 glyph_hash_item_t* item = glyph_hash_root[hash % GLYPH_HASH_SIZE];
178 while (item) {
179 if (glyph_compare(key, &(item->key))) {
180 return &(item->val);
181 }
182 item = item->next;
183 }
184 return 0;
185 }
186
187 void ass_glyph_cache_init(void)
188 {
189 glyph_hash_root = calloc(GLYPH_HASH_SIZE, sizeof(glyph_hash_item_p));
190 glyph_hash_size = 0;
191 }
192
193 void ass_glyph_cache_done(void)
194 {
195 int i;
196 for (i = 0; i < GLYPH_HASH_SIZE; ++i) {
197 glyph_hash_item_t* item = glyph_hash_root[i];
198 while (item) {
199 glyph_hash_item_t* next = item->next;
200 if (item->val.glyph) FT_Done_Glyph(item->val.glyph);
201 if (item->val.outline_glyph) FT_Done_Glyph(item->val.outline_glyph);
202 free(item);
203 item = next;
204 }
205 }
206 free(glyph_hash_root);
207 glyph_hash_size = 0;
208 }
209