blob: 281b48bfb08d6f9dd94277506567b930eee98a30 [file] [log] [blame]
David Turnerece63792000-10-28 23:34:45 +00001#include <freetype/cache/ftcsbits.h>
2#include <freetype/fterrors.h>
3
4#define FTC_SBITSET_ELEMENT_COUNT 16
5
6
7 typedef struct FTC_SBitSetRec_
8 {
9 FTC_ChunkSetRec root;
10 FTC_Image_Desc desc;
11
12 } FTC_SBitSetRec, *FTC_SBitSet;
13
14
15 typedef struct FTC_SBit_CacheRec_
16 {
17 FTC_Chunk_CacheRec root;
18
19 } FTC_SBit_CacheRec;
20
21
David Turner4e4a4362000-10-28 13:17:11 +000022
23 /*************************************************************************/
24 /*************************************************************************/
25 /***** *****/
David Turnerece63792000-10-28 23:34:45 +000026 /***** SBIT CACHE NODES *****/
David Turner4e4a4362000-10-28 13:17:11 +000027 /***** *****/
28 /*************************************************************************/
29 /*************************************************************************/
30
31
32 LOCAL_FUNC_X
33 void ftc_sbit_chunk_node_destroy( FTC_ChunkNode node )
34 {
35 FTC_ChunkSet cset = node->cset;
36 FT_Memory memory = cset->memory;
37 FT_UInt count = node->num_elements;
38 FTC_SBit sbit = (FTC_SBit)node->elements;
39
40 for ( ; count > 0; sbit++, count-- )
41 FREE( sbit->buffer );
42
David Turnerece63792000-10-28 23:34:45 +000043 FREE( node->elements );
David Turner4e4a4362000-10-28 13:17:11 +000044 FREE( node );
45 }
46
47
David Turnerece63792000-10-28 23:34:45 +000048
49
David Turner4e4a4362000-10-28 13:17:11 +000050 static
51 FT_Error ftc_bitmap_copy( FT_Memory memory,
52 FT_Bitmap* source,
53 FTC_SBit target )
54 {
55 FT_Error error;
56 FT_Int pitch = source->pitch;
57 FT_ULong size;
58
59 if ( pitch < 0 )
60 pitch = -pitch;
61
62 size = (FT_ULong)( pitch * source->rows );
63
64 if ( !ALLOC( target->buffer, size ) )
65 MEM_Copy( target->buffer, source->buffer, size );
66
67 return error;
68 }
69
70
71 LOCAL_FUNC_X
72 FT_Error ftc_sbit_chunk_node_new( FTC_ChunkSet cset,
73 FT_UInt index,
David Turnerece63792000-10-28 23:34:45 +000074 FTC_ChunkNode *anode )
David Turner4e4a4362000-10-28 13:17:11 +000075 {
76 FT_Error error;
77 FT_Memory memory = cset->memory;
78 FTC_SBitSet sbitset = (FTC_SBitSet)cset;
David Turnerece63792000-10-28 23:34:45 +000079 FTC_ChunkNode node = 0;
David Turner4e4a4362000-10-28 13:17:11 +000080 FT_Face face;
81 FT_Size size;
82
83
84 /* allocate node */
85 if ( ALLOC( node, sizeof ( *node ) ) )
86 goto Exit;
87
88 /* init its inner fields */
David Turnerece63792000-10-28 23:34:45 +000089 error = FTC_ChunkNode_Init( node, cset, index, 1 );
David Turner4e4a4362000-10-28 13:17:11 +000090 if (error)
91 goto Exit;
92
David Turnerece63792000-10-28 23:34:45 +000093 /* we will now load all glyph images for this chunk */
David Turner4e4a4362000-10-28 13:17:11 +000094 error = FTC_Manager_Lookup_Size( cset->manager,
David Turnerece63792000-10-28 23:34:45 +000095 &sbitset->desc.font,
David Turner4e4a4362000-10-28 13:17:11 +000096 &face, &size );
97 if ( !error )
98 {
David Turnerece63792000-10-28 23:34:45 +000099 FT_UInt glyph_index = index * cset->element_count;
David Turner4e4a4362000-10-28 13:17:11 +0000100 FT_UInt load_flags = FT_LOAD_DEFAULT;
David Turnerece63792000-10-28 23:34:45 +0000101 FT_UInt image_type = sbitset->desc.image_type;
David Turner4e4a4362000-10-28 13:17:11 +0000102 FT_UInt count = node->num_elements;
103 FTC_SBit sbit = (FTC_SBit)node->elements;
104
David Turnerece63792000-10-28 23:34:45 +0000105 /* determine load flags, depending on the font description's */
106 /* image type.. */
David Turner4e4a4362000-10-28 13:17:11 +0000107 {
David Turnerece63792000-10-28 23:34:45 +0000108 if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
David Turner4e4a4362000-10-28 13:17:11 +0000109 {
David Turnerece63792000-10-28 23:34:45 +0000110 if ( image_type & ftc_image_flag_monochrome )
111 load_flags |= FT_LOAD_MONOCHROME;
112
113 /* disable embedded bitmaps loading if necessary */
114 if ( image_type & ftc_image_flag_no_sbits )
115 load_flags |= FT_LOAD_NO_BITMAP;
116 }
117 else
118 {
119 FT_ERROR(( "FTC_SBit_Cache: cannot load scalable glyphs in a"
David Turner4e4a4362000-10-28 13:17:11 +0000120 " sbit cache, please check your arguments !!\n" ));
David Turnerece63792000-10-28 23:34:45 +0000121 error = FT_Err_Invalid_Argument;
David Turner4e4a4362000-10-28 13:17:11 +0000122 goto Exit;
123 }
David Turner4e4a4362000-10-28 13:17:11 +0000124
David Turnerece63792000-10-28 23:34:45 +0000125 /* always render glyphs to bitmaps */
126 load_flags |= FT_LOAD_RENDER;
David Turner4e4a4362000-10-28 13:17:11 +0000127
David Turnerece63792000-10-28 23:34:45 +0000128 if ( image_type & ftc_image_flag_unhinted )
129 load_flags |= FT_LOAD_NO_HINTING;
David Turner4e4a4362000-10-28 13:17:11 +0000130
David Turnerece63792000-10-28 23:34:45 +0000131 if ( image_type & ftc_image_flag_autohinted )
132 load_flags |= FT_LOAD_FORCE_AUTOHINT;
133 }
David Turner4e4a4362000-10-28 13:17:11 +0000134
135
136 /* load a chunk of small bitmaps in a row */
David Turnerece63792000-10-28 23:34:45 +0000137 for ( ; count > 0; count--, glyph_index++, sbit++ )
David Turner4e4a4362000-10-28 13:17:11 +0000138 {
David Turnerece63792000-10-28 23:34:45 +0000139 /* by default, indicates a "missing" glyph */
140 sbit->buffer = 0;
141
David Turner4e4a4362000-10-28 13:17:11 +0000142 error = FT_Load_Glyph( face, glyph_index, load_flags );
143 if (!error)
144 {
145 FT_Int temp;
146 FT_GlyphSlot slot = face->glyph;
147 FT_Bitmap* bitmap = &slot->bitmap;
David Turnerece63792000-10-28 23:34:45 +0000148 FT_Int xadvance, yadvance;
David Turner4e4a4362000-10-28 13:17:11 +0000149
David Turnerece63792000-10-28 23:34:45 +0000150 /* check that our values fit in 8-bit containers !! */
151 /* if this is not the case, our bitmap is too large */
152 /* and we will leave it as "missing" with sbit.buffer = 0 */
153
154#define CHECK_CHAR(d) ( temp = (FT_Char)d, temp == d )
155#define CHECK_BYTE(d) ( temp = (FT_Byte)d, temp == d )
David Turner4e4a4362000-10-28 13:17:11 +0000156
David Turnerece63792000-10-28 23:34:45 +0000157 /* FIXME: add support for vertical layouts maybe.. */
158
159 /* horizontal advance in pixels */
160 xadvance = (slot->metrics.horiAdvance+32) >> 6;
161 yadvance = (slot->metrics.vertAdvance+32) >> 6;
David Turner4e4a4362000-10-28 13:17:11 +0000162
163 if ( CHECK_BYTE ( bitmap->rows ) &&
164 CHECK_BYTE ( bitmap->width ) &&
David Turnerece63792000-10-28 23:34:45 +0000165 CHECK_CHAR ( bitmap->pitch ) &&
166 CHECK_CHAR ( slot->bitmap_left ) &&
167 CHECK_CHAR ( slot->bitmap_top ) &&
168 CHECK_CHAR ( xadvance ) &&
169 CHECK_CHAR ( yadvance ) )
David Turner4e4a4362000-10-28 13:17:11 +0000170 {
David Turnerece63792000-10-28 23:34:45 +0000171 sbit->width = (FT_Byte) bitmap->width;
172 sbit->height = (FT_Byte) bitmap->rows;
173 sbit->pitch = (FT_Char) bitmap->pitch;
174 sbit->left = (FT_Char) slot->bitmap_left;
175 sbit->top = (FT_Char) slot->bitmap_top;
176 sbit->xadvance = (FT_Char) xadvance;
177 sbit->yadvance = (FT_Char) yadvance;
178 sbit->format = (FT_Byte) bitmap->pixel_mode;
David Turner4e4a4362000-10-28 13:17:11 +0000179
180 /* grab the bitmap when possible */
181 if ( slot->flags & ft_glyph_own_bitmap )
182 {
183 slot->flags &= ~ft_glyph_own_bitmap;
184 sbit->buffer = bitmap->buffer;
185 }
186 else
187 {
188 /* copy the bitmap into a new buffer - ignore error */
189 ftc_bitmap_copy( memory, bitmap, sbit );
190 }
191 }
192 }
David Turner4e4a4362000-10-28 13:17:11 +0000193 }
194
195 /* ignore the errors that might have occured there */
196 /* we recognize unloaded glyphs with "sbit.buffer == 0" */
197 error = 0;
198 }
199
200 Exit:
201 if ( error && node )
202 {
203 FREE( node->elements );
204 FREE( node );
205 }
206
207 *anode = node;
208 return error;
209 }
210
211
212 /* this function is important because it is both part of */
David Turnerece63792000-10-28 23:34:45 +0000213 /* a FTC_ChunkSet_Class and a FTC_CacheNode_Class */
David Turner4e4a4362000-10-28 13:17:11 +0000214 /* */
215 LOCAL_FUNC_X
David Turnerece63792000-10-28 23:34:45 +0000216 FT_ULong ftc_sbit_chunk_node_size( FTC_ChunkNode node )
David Turner4e4a4362000-10-28 13:17:11 +0000217 {
David Turnerece63792000-10-28 23:34:45 +0000218 FT_ULong size;
219 FTC_ChunkSet cset = node->cset;
220 FT_UInt count = node->num_elements;
221 FT_Int pitch;
222 FTC_SBit sbit = (FTC_SBit)node->elements;
David Turner4e4a4362000-10-28 13:17:11 +0000223
David Turnerece63792000-10-28 23:34:45 +0000224 size = sizeof (*node); /* the node itself */
225 size += cset->element_count * sizeof(FTC_SBitRec); /* the sbit recors */
David Turner4e4a4362000-10-28 13:17:11 +0000226
David Turnerece63792000-10-28 23:34:45 +0000227 for ( ; count > 0; count--, sbit++ )
David Turner4e4a4362000-10-28 13:17:11 +0000228 {
David Turnerece63792000-10-28 23:34:45 +0000229 if (sbit->buffer)
David Turner4e4a4362000-10-28 13:17:11 +0000230 {
David Turnerece63792000-10-28 23:34:45 +0000231 pitch = sbit->pitch;
232 if (pitch < 0)
233 pitch = -pitch;
234
235 /* add the size of a given glyph image */
236 size += pitch * sbit->height;
David Turner4e4a4362000-10-28 13:17:11 +0000237 }
David Turner4e4a4362000-10-28 13:17:11 +0000238 }
239
David Turner4e4a4362000-10-28 13:17:11 +0000240 return size;
241 }
242
243
244 /*************************************************************************/
245 /*************************************************************************/
246 /***** *****/
David Turnerece63792000-10-28 23:34:45 +0000247 /***** SBIT CHUNK SETS *****/
David Turner4e4a4362000-10-28 13:17:11 +0000248 /***** *****/
249 /*************************************************************************/
250 /*************************************************************************/
251
252
253 LOCAL_FUNC_X
David Turnerece63792000-10-28 23:34:45 +0000254 FT_Error ftc_sbit_chunk_set_sizes( FTC_ChunkSet cset,
255 FTC_Image_Desc* desc )
David Turner4e4a4362000-10-28 13:17:11 +0000256 {
David Turnerece63792000-10-28 23:34:45 +0000257 FT_Error error;
258 FT_Face face;
259
260 cset->element_count = FTC_SBITSET_ELEMENT_COUNT;
261 cset->element_size = sizeof(FTC_SBitRec);
262
263 /* lookup the FT_Face to obtain the number of glyphs */
264 error = FTC_Manager_Lookup_Face( cset->manager,
265 &desc->font, &face );
266 if (!error)
267 cset->element_max = face->num_glyphs;
268
269 return error;
270 }
271
272
273
274 LOCAL_FUNC_X
275 FT_Error ftc_sbit_chunk_set_init( FTC_SBitSet sset,
276 FTC_Image_Desc* type )
277 {
278 sset->desc = *type;
David Turner4e4a4362000-10-28 13:17:11 +0000279 return 0;
280 }
281
282
283 LOCAL_FUNC_X
David Turnerece63792000-10-28 23:34:45 +0000284 FT_Bool ftc_sbit_chunk_set_compare( FTC_SBitSet sset,
285 FTC_Image_Desc* type )
David Turner4e4a4362000-10-28 13:17:11 +0000286 {
David Turnerece63792000-10-28 23:34:45 +0000287 return !memcmp( &sset->desc, type, sizeof ( *type ) );
David Turner4e4a4362000-10-28 13:17:11 +0000288 }
289
290
291 FT_CPLUSPLUS( const FTC_ChunkSet_Class ) ftc_sbit_chunk_set_class =
292 {
293 sizeof( FTC_ImageSetRec ),
294
David Turnerece63792000-10-28 23:34:45 +0000295 (FTC_ChunkSet_InitFunc) ftc_sbit_chunk_set_init,
296 (FTC_ChunkSet_DoneFunc) 0,
297 (FTC_ChunkSet_CompareFunc) ftc_sbit_chunk_set_compare,
298 (FTC_ChunkSet_SizesFunc) ftc_sbit_chunk_set_sizes,
David Turner4e4a4362000-10-28 13:17:11 +0000299
David Turnerece63792000-10-28 23:34:45 +0000300 (FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new,
301 (FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size,
302 (FTC_ChunkSet_DestroyNodeFunc) ftc_sbit_chunk_node_destroy
David Turner4e4a4362000-10-28 13:17:11 +0000303 };
304
305
306 /*************************************************************************/
307 /*************************************************************************/
308 /***** *****/
David Turnerece63792000-10-28 23:34:45 +0000309 /***** SBITS CACHE *****/
David Turner4e4a4362000-10-28 13:17:11 +0000310 /***** *****/
311 /*************************************************************************/
312 /*************************************************************************/
313
314
David Turnerece63792000-10-28 23:34:45 +0000315 FT_CPLUSPLUS( const FTC_Chunk_Cache_Class ) ftc_sbit_cache_class =
David Turner4e4a4362000-10-28 13:17:11 +0000316 {
317 {
David Turnerece63792000-10-28 23:34:45 +0000318 sizeof( FTC_SBit_CacheRec ),
319 (FTC_Cache_InitFunc) FTC_Chunk_Cache_Init,
320 (FTC_Cache_DoneFunc) FTC_Chunk_Cache_Done
David Turner4e4a4362000-10-28 13:17:11 +0000321 },
322 (FTC_ChunkSet_Class*) &ftc_sbit_chunk_set_class
323 };
324
325
David Turnerece63792000-10-28 23:34:45 +0000326 FT_EXPORT_FUNC( FT_Error )
327 FTC_SBit_Cache_New( FTC_Manager manager,
328 FTC_SBit_Cache* acache )
David Turner4e4a4362000-10-28 13:17:11 +0000329 {
330 return FTC_Manager_Register_Cache(
331 manager,
David Turnerece63792000-10-28 23:34:45 +0000332 (FTC_Cache_Class*)&ftc_sbit_cache_class,
David Turner4e4a4362000-10-28 13:17:11 +0000333 (FTC_Cache*)acache );
334 }
335
336
337 FT_EXPORT_DEF( FT_Error )
David Turnerece63792000-10-28 23:34:45 +0000338 FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache,
339 FTC_Image_Desc* desc,
340 FT_UInt gindex,
341 FTC_SBit *asbit )
David Turner4e4a4362000-10-28 13:17:11 +0000342 {
343 FT_Error error;
David Turnerece63792000-10-28 23:34:45 +0000344 FTC_ChunkSet cset;
345 FTC_ChunkNode node;
346 FT_UInt cindex;
David Turner4e4a4362000-10-28 13:17:11 +0000347 FTC_Manager manager;
348
David Turnerece63792000-10-28 23:34:45 +0000349 FTC_SBitSet sset;
350 FTC_SBit sbit;
David Turner4e4a4362000-10-28 13:17:11 +0000351
352
353 /* check for valid `desc' delayed to FT_Lru_Lookup() */
354
David Turnerece63792000-10-28 23:34:45 +0000355 if ( !cache || !asbit )
David Turner4e4a4362000-10-28 13:17:11 +0000356 return FT_Err_Invalid_Argument;
357
David Turnerece63792000-10-28 23:34:45 +0000358 *asbit = 0;
359 cset = cache->root.last_cset;
360 sset = (FTC_SBitSet)cset;
361 if ( !cset || memcmp( &sset->desc, desc, sizeof ( *desc ) ) )
David Turner4e4a4362000-10-28 13:17:11 +0000362 {
David Turnerece63792000-10-28 23:34:45 +0000363 error = FT_Lru_Lookup( cache->root.csets_lru,
David Turner4e4a4362000-10-28 13:17:11 +0000364 (FT_LruKey)desc,
David Turnerece63792000-10-28 23:34:45 +0000365 (FT_Pointer*)&cset );
366 cache->root.last_cset = cset;
David Turner4e4a4362000-10-28 13:17:11 +0000367 if ( error )
368 goto Exit;
369 }
370
David Turnerece63792000-10-28 23:34:45 +0000371 error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex );
David Turner4e4a4362000-10-28 13:17:11 +0000372 if ( error )
373 goto Exit;
374
375 /* now compress the manager's cache pool if needed */
376 manager = cache->root.root.manager;
377 if ( manager->num_bytes > manager->max_bytes )
378 {
David Turnerece63792000-10-28 23:34:45 +0000379 FTC_ChunkNode_Ref ( node );
David Turner4e4a4362000-10-28 13:17:11 +0000380 FTC_Manager_Compress( manager );
David Turnerece63792000-10-28 23:34:45 +0000381 FTC_ChunkNode_Unref ( node );
David Turner4e4a4362000-10-28 13:17:11 +0000382 }
383
David Turnerece63792000-10-28 23:34:45 +0000384 sbit = ((FTC_SBit)((FTC_ChunkNode)node)->elements) + cindex;
385 if (sbit->buffer == 0)
386 {
387 /* the glyph was missing, we return a NULL pointer !! */
388 sbit = 0;
389 }
390
391 *asbit = sbit;
David Turner4e4a4362000-10-28 13:17:11 +0000392
393 Exit:
394 return error;
395 }
396