]> granicus.if.org Git - libass/blob - libass/ass_cache.c
Remove obsolete "no_more_font_messages" hack.
[libass] / libass / ass_cache.c
1 // -*- c-basic-offset: 8; indent-tabs-mode: t -*-
2 // vim:ts=8:sw=8:noet:ai:
3 /*
4   Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "config.h"
22
23 #include <ft2build.h>
24 #include FT_FREETYPE_H
25 #include FT_GLYPH_H
26
27 #include <assert.h>
28
29 #include "mputils.h"
30 #include "ass_fontconfig.h"
31 #include "ass_bitmap.h"
32 #include "ass_cache.h"
33 #include "ass_font.h"
34
35 #define MAX_FONT_CACHE_SIZE 100
36
37 static ass_font_t* font_cache;
38 static int font_cache_size;
39
40 static int font_compare(ass_font_desc_t* a, ass_font_desc_t* b) {
41         if (strcmp(a->family, b->family) != 0)
42                 return 0;
43         if (a->bold != b->bold)
44                 return 0;
45         if (a->italic != b->italic)
46                 return 0;
47         return 1;
48 }
49
50 /**
51  * \brief Get a face object, either from cache or created through FreeType+FontConfig.
52  * \param library FreeType library object
53  * \param fontconfig_priv fontconfig private data
54  * \param desc required face description
55  * \return new font struct
56 */ 
57 ass_font_t* ass_new_font(FT_Library library, void* fontconfig_priv, ass_font_desc_t* desc)
58 {
59         int i;
60         ass_font_t* item;
61         int error;
62         
63         for (i=0; i<font_cache_size; ++i)
64                 if (font_compare(desc, &(font_cache[i].desc)))
65                         return font_cache + i;
66
67         if (font_cache_size == MAX_FONT_CACHE_SIZE) {
68                 mp_msg(MSGT_ASS, MSGL_FATAL, MSGTR_LIBASS_TooManyFonts);
69                 return 0;
70         }
71
72         item = font_cache + font_cache_size;
73         error = ass_font_init(library, fontconfig_priv, item, desc);
74         if (error) // FIXME: mp_msg
75                 return 0;
76         font_cache_size++;
77
78         return item;
79 }
80
81 void ass_font_cache_init(void)
82 {
83         font_cache = calloc(MAX_FONT_CACHE_SIZE, sizeof(ass_font_t));
84         font_cache_size = 0;
85 }
86
87 void ass_font_cache_done(void)
88 {
89         int i;
90         for (i = 0; i < font_cache_size; ++i) {
91                 ass_font_t* item = font_cache + i;
92                 ass_font_free(item);
93         }
94         free(font_cache);
95         font_cache_size = 0;
96 }
97
98 //---------------------------------
99 // glyph cache
100
101 #define GLYPH_HASH_SIZE (0xFFFF + 13)
102
103 typedef struct glyph_hash_item_s {
104         glyph_hash_key_t key;
105         glyph_hash_val_t val;
106         struct glyph_hash_item_s* next;
107 } glyph_hash_item_t;
108
109 typedef glyph_hash_item_t* glyph_hash_item_p;
110
111 static glyph_hash_item_p* glyph_hash_root;
112 static int glyph_hash_size;
113
114 static int glyph_compare(glyph_hash_key_t* a, glyph_hash_key_t* b) {
115         if (memcmp(a, b, sizeof(glyph_hash_key_t)) == 0)
116                 return 1;
117         else
118                 return 0;
119 }
120
121 static unsigned glyph_hash(glyph_hash_key_t* key) {
122         unsigned val = 0;
123         unsigned i;
124         for (i = 0; i < sizeof(key->face); ++i)
125                 val += *(unsigned char *)(&(key->face) + i);
126         val <<= 21;
127         
128         if (key->bitmap)   val &= 0x80000000;
129         if (key->be) val &= 0x40000000;
130         val += key->index;
131         val += key->size << 8;
132         val += key->outline << 3;
133         val += key->advance.x << 10;
134         val += key->advance.y << 16;
135         val += key->bold << 1;
136         val += key->italic << 20;
137         return val;
138 }
139
140 /**
141  * \brief Add a glyph to glyph cache.
142  * \param key hash key
143  * \param val hash val: 2 bitmap glyphs + some additional info
144 */ 
145 void cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
146 {
147         unsigned hash = glyph_hash(key);
148         glyph_hash_item_t** next = glyph_hash_root + (hash % GLYPH_HASH_SIZE);
149         while (*next) {
150                 if (glyph_compare(key, &((*next)->key)))
151                         return;
152                 next = &((*next)->next);
153                 assert(next);
154         }
155         (*next) = malloc(sizeof(glyph_hash_item_t));
156 //      (*next)->desc = glyph_key_copy(key, &((*next)->key));
157         memcpy(&((*next)->key), key, sizeof(glyph_hash_key_t));
158         memcpy(&((*next)->val), val, sizeof(glyph_hash_val_t));
159         (*next)->next = 0;
160
161         glyph_hash_size ++;
162 /*      if (glyph_hash_size  && (glyph_hash_size % 25 == 0)) {
163                 printf("\nGlyph cache: %d entries, %d bytes\n", glyph_hash_size, glyph_hash_size * sizeof(glyph_hash_item_t));
164         } */
165 }
166
167 /**
168  * \brief Get a glyph from glyph cache.
169  * \param key hash key
170  * \return requested hash val or 0 if not found
171 */ 
172 glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key)
173 {
174         unsigned hash = glyph_hash(key);
175         glyph_hash_item_t* item = glyph_hash_root[hash % GLYPH_HASH_SIZE];
176         while (item) {
177                 if (glyph_compare(key, &(item->key))) {
178                         return &(item->val);
179                 }
180                 item = item->next;
181         }
182         return 0;
183 }
184
185 void ass_glyph_cache_init(void)
186 {
187         glyph_hash_root = calloc(GLYPH_HASH_SIZE, sizeof(glyph_hash_item_p));
188         glyph_hash_size = 0;
189 }
190
191 void ass_glyph_cache_done(void)
192 {
193         int i;
194         for (i = 0; i < GLYPH_HASH_SIZE; ++i) {
195                 glyph_hash_item_t* item = glyph_hash_root[i];
196                 while (item) {
197                         glyph_hash_item_t* next = item->next;
198                         if (item->val.bm) ass_free_bitmap(item->val.bm);
199                         if (item->val.bm_o) ass_free_bitmap(item->val.bm_o);
200                         if (item->val.bm_s) ass_free_bitmap(item->val.bm_s);
201                         free(item);
202                         item = next;
203                 }
204         }
205         free(glyph_hash_root);
206         glyph_hash_size = 0;
207 }
208
209 void ass_glyph_cache_reset(void)
210 {
211         ass_glyph_cache_done();
212         ass_glyph_cache_init();
213 }
214