1 /***************************************************************************/
2 /* */
3 /* ftcsbits.c */
4 /* */
5 /* FreeType sbits manager (body). */
6 /* */
7 /* Copyright 2000-2001 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
19 #include <ft2build.h>
20 #include FT_CACHE_H
21 #include FT_CACHE_SMALL_BITMAPS_H
22 #include FT_INTERNAL_OBJECTS_H
23 #include FT_INTERNAL_DEBUG_H
24 #include FT_ERRORS_H
26 #include "ftcerror.h"
28 #include <string.h> /* memcmp() */
31 #define FTC_SBITSET_ELEMENT_COUNT 16
34 typedef struct FTC_SBitSetRec_
35 {
36 FTC_ChunkSetRec root;
37 FTC_Image_Desc desc;
39 } FTC_SBitSetRec, *FTC_SBitSet;
42 typedef struct FTC_SBit_CacheRec_
43 {
44 FTC_Chunk_CacheRec root;
46 } FTC_SBit_CacheRec;
50 /*************************************************************************/
51 /*************************************************************************/
52 /***** *****/
53 /***** SBIT CACHE NODES *****/
54 /***** *****/
55 /*************************************************************************/
56 /*************************************************************************/
59 FT_CALLBACK_DEF( void )
60 ftc_sbit_chunk_node_destroy( FTC_ChunkNode node )
61 {
62 FTC_ChunkSet cset = node->cset;
63 FT_Memory memory = cset->memory;
64 FT_UInt count = node->num_elements;
65 FTC_SBit sbit = (FTC_SBit)node->elements;
68 for ( ; count > 0; sbit++, count-- )
69 FREE( sbit->buffer );
71 FREE( node->elements );
72 FREE( node );
73 }
76 FT_CALLBACK_DEF( FT_Error )
77 ftc_bitmap_copy( FT_Memory memory,
78 FT_Bitmap* source,
79 FTC_SBit target )
80 {
81 FT_Error error;
82 FT_Int pitch = source->pitch;
83 FT_ULong size;
86 if ( pitch < 0 )
87 pitch = -pitch;
89 size = (FT_ULong)( pitch * source->rows );
91 if ( !ALLOC( target->buffer, size ) )
92 MEM_Copy( target->buffer, source->buffer, size );
94 return error;
95 }
98 FT_CALLBACK_DEF( FT_Error )
99 ftc_sbit_chunk_node_new( FTC_ChunkSet cset,
100 FT_UInt index,
101 FTC_ChunkNode *anode )
102 {
103 FT_Error error;
104 FT_Memory memory = cset->memory;
105 FTC_SBitSet sbitset = (FTC_SBitSet)cset;
106 FTC_ChunkNode node = 0;
107 FT_Face face;
108 FT_Size size;
111 /* allocate node */
112 if ( ALLOC( node, sizeof ( *node ) ) )
113 goto Exit;
115 /* initialize its inner fields */
116 error = FTC_ChunkNode_Init( node, cset, index, 1 );
117 if ( error )
118 goto Exit;
120 /* we will now load all glyph images for this chunk */
121 error = FTC_Manager_Lookup_Size( cset->manager,
122 &sbitset->desc.font,
123 &face, &size );
124 if ( !error )
125 {
126 FT_UInt glyph_index = index * cset->element_count;
127 FT_UInt load_flags = FT_LOAD_DEFAULT;
128 FT_UInt image_type = sbitset->desc.image_type;
129 FT_UInt count = node->num_elements;
130 FTC_SBit sbit = (FTC_SBit)node->elements;
133 /* determine load flags, depending on the font description's */
134 /* image type */
136 if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
137 {
138 if ( image_type & ftc_image_flag_monochrome )
139 load_flags |= FT_LOAD_MONOCHROME;
141 /* disable embedded bitmaps loading if necessary */
142 if ( image_type & ftc_image_flag_no_sbits )
143 load_flags |= FT_LOAD_NO_BITMAP;
144 }
145 else
146 {
147 FT_ERROR(( "FTC_SBit_Cache: cannot load scalable glyphs in an"
148 " sbit cache, please check your arguments!\n" ));
149 error = FTC_Err_Invalid_Argument;
150 goto Exit;
151 }
153 /* always render glyphs to bitmaps */
154 load_flags |= FT_LOAD_RENDER;
156 if ( image_type & ftc_image_flag_unhinted )
157 load_flags |= FT_LOAD_NO_HINTING;
159 if ( image_type & ftc_image_flag_autohinted )
160 load_flags |= FT_LOAD_FORCE_AUTOHINT;
162 /* load a chunk of small bitmaps in a row */
163 for ( ; count > 0; count--, glyph_index++, sbit++ )
164 {
165 /* by default, indicates a `missing' glyph */
166 sbit->buffer = 0;
168 error = FT_Load_Glyph( face, glyph_index, load_flags );
169 if ( !error )
170 {
171 FT_Int temp;
172 FT_GlyphSlot slot = face->glyph;
173 FT_Bitmap* bitmap = &slot->bitmap;
174 FT_Int xadvance, yadvance;
177 /* check that our values fit into 8-bit containers! */
178 /* If this is not the case, our bitmap is too large */
179 /* and we will leave it as `missing' with sbit.buffer = 0 */
181 #define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
182 #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
184 /* XXX: FIXME: add support for vertical layouts maybe */
186 /* horizontal advance in pixels */
187 xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
188 yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
190 if ( CHECK_BYTE( bitmap->rows ) &&
191 CHECK_BYTE( bitmap->width ) &&
192 CHECK_CHAR( bitmap->pitch ) &&
193 CHECK_CHAR( slot->bitmap_left ) &&
194 CHECK_CHAR( slot->bitmap_top ) &&
195 CHECK_CHAR( xadvance ) &&
196 CHECK_CHAR( yadvance ) )
197 {
198 sbit->width = (FT_Byte)bitmap->width;
199 sbit->height = (FT_Byte)bitmap->rows;
200 sbit->pitch = (FT_Char)bitmap->pitch;
201 sbit->left = (FT_Char)slot->bitmap_left;
202 sbit->top = (FT_Char)slot->bitmap_top;
203 sbit->xadvance = (FT_Char)xadvance;
204 sbit->yadvance = (FT_Char)yadvance;
205 sbit->format = (FT_Byte)bitmap->pixel_mode;
207 /* grab the bitmap when possible */
208 if ( slot->flags & ft_glyph_own_bitmap )
209 {
210 slot->flags &= ~ft_glyph_own_bitmap;
211 sbit->buffer = bitmap->buffer;
212 }
213 else
214 {
215 /* copy the bitmap into a new buffer -- ignore error */
216 ftc_bitmap_copy( memory, bitmap, sbit );
217 }
218 }
219 }
220 }
222 /* ignore the errors that might have occurred -- */
223 /* we recognize unloaded glyphs with `sbit.buffer == 0' */
224 error = 0;
225 }
227 Exit:
228 if ( error && node )
229 {
230 FREE( node->elements );
231 FREE( node );
232 }
234 *anode = node;
236 return error;
237 }
240 /* this function is important because it is both part of */
241 /* an FTC_ChunkSet_Class and an FTC_CacheNode_Class */
242 /* */
243 FT_CALLBACK_DEF( FT_ULong )
244 ftc_sbit_chunk_node_size( FTC_ChunkNode node )
245 {
246 FT_ULong size;
247 FTC_ChunkSet cset = node->cset;
248 FT_UInt count = node->num_elements;
249 FT_Int pitch;
250 FTC_SBit sbit = (FTC_SBit)node->elements;
253 /* the node itself */
254 size = sizeof ( *node );
256 /* the sbit records */
257 size += cset->element_count * sizeof ( FTC_SBitRec );
259 for ( ; count > 0; count--, sbit++ )
260 {
261 if ( sbit->buffer )
262 {
263 pitch = sbit->pitch;
264 if ( pitch < 0 )
265 pitch = -pitch;
267 /* add the size of a given glyph image */
268 size += pitch * sbit->height;
269 }
270 }
272 return size;
273 }
276 /*************************************************************************/
277 /*************************************************************************/
278 /***** *****/
279 /***** SBIT CHUNK SETS *****/
280 /***** *****/
281 /*************************************************************************/
282 /*************************************************************************/
285 FT_CALLBACK_DEF( FT_Error )
286 ftc_sbit_chunk_set_sizes( FTC_ChunkSet cset,
287 FTC_Image_Desc* desc )
288 {
289 FT_Error error;
290 FT_Face face;
293 cset->element_count = FTC_SBITSET_ELEMENT_COUNT;
294 cset->element_size = sizeof ( FTC_SBitRec );
296 /* lookup the FT_Face to obtain the number of glyphs */
297 error = FTC_Manager_Lookup_Face( cset->manager,
298 desc->font.face_id, &face );
299 if ( !error )
300 cset->element_max = face->num_glyphs;
302 return error;
303 }
306 FT_CALLBACK_DEF( FT_Error )
307 ftc_sbit_chunk_set_init( FTC_SBitSet sset,
308 FTC_Image_Desc* type )
309 {
310 sset->desc = *type;
312 return 0;
313 }
316 FT_CALLBACK_DEF( FT_Bool )
317 ftc_sbit_chunk_set_compare( FTC_SBitSet sset,
318 FTC_Image_Desc* type )
319 {
320 return FT_BOOL( !memcmp( &sset->desc, type, sizeof ( *type ) ) );
321 }
324 FT_CALLBACK_TABLE_DEF
325 const FTC_ChunkSet_Class ftc_sbit_chunk_set_class =
326 {
327 sizeof( FTC_SBitSetRec ),
329 (FTC_ChunkSet_InitFunc) ftc_sbit_chunk_set_init,
330 (FTC_ChunkSet_DoneFunc) 0,
331 (FTC_ChunkSet_CompareFunc) ftc_sbit_chunk_set_compare,
332 (FTC_ChunkSet_SizesFunc) ftc_sbit_chunk_set_sizes,
334 (FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new,
335 (FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size,
336 (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy
337 };
340 /*************************************************************************/
341 /*************************************************************************/
342 /***** *****/
343 /***** SBITS CACHE *****/
344 /***** *****/
345 /*************************************************************************/
346 /*************************************************************************/
349 FT_CALLBACK_TABLE_DEF
350 const FTC_Chunk_Cache_Class ftc_sbit_cache_class =
351 {
352 {
353 sizeof( FTC_SBit_CacheRec ),
354 (FTC_Cache_InitFunc)FTC_Chunk_Cache_Init,
355 (FTC_Cache_DoneFunc)FTC_Chunk_Cache_Done
356 },
357 (FTC_ChunkSet_Class*)&ftc_sbit_chunk_set_class
358 };
361 /* documentation is in ftcsbits.h */
363 FT_EXPORT_DEF( FT_Error )
364 FTC_SBit_Cache_New( FTC_Manager manager,
365 FTC_SBit_Cache *acache )
366 {
367 return FTC_Manager_Register_Cache(
368 manager,
369 (FTC_Cache_Class*)&ftc_sbit_cache_class,
370 (FTC_Cache*)acache );
371 }
374 /* documentation is in ftcsbits.h */
376 FT_EXPORT_DEF( FT_Error )
377 FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache,
378 FTC_Image_Desc* desc,
379 FT_UInt gindex,
380 FTC_SBit *ansbit )
381 {
382 FT_Error error;
383 FTC_ChunkNode node;
384 FT_UInt cindex;
387 /* argument checks delayed to FTC_Chunk_Cache_Lookup */
388 if ( !ansbit )
389 return FTC_Err_Invalid_Argument;
391 *ansbit = 0;
392 error = FTC_Chunk_Cache_Lookup( &cache->root, desc, gindex,
393 &node, &cindex );
394 if ( !error )
395 *ansbit = (FTC_SBit)node->elements + cindex;
397 return error;
398 }
401 /* END */