ftcsbits.c revision ab8552321c70e947fedfd31709c43c4cb27d496f
1/***************************************************************************/ 2/* */ 3/* ftcsbits.c */ 4/* */ 5/* FreeType sbits manager (body). */ 6/* */ 7/* Copyright 2000 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/***************************************************************************/ 17 18 19#include <freetype/cache/ftcsbits.h> 20#include <freetype/internal/ftobjs.h> 21#include <freetype/internal/ftdebug.h> 22#include <freetype/fterrors.h> 23 24#include <string.h> /* memcmp() */ 25 26 27#define FTC_SBITSET_ELEMENT_COUNT 16 28 29 30 typedef struct FTC_SBitSetRec_ 31 { 32 FTC_ChunkSetRec root; 33 FTC_Image_Desc desc; 34 35 } FTC_SBitSetRec, *FTC_SBitSet; 36 37 38 typedef struct FTC_SBit_CacheRec_ 39 { 40 FTC_Chunk_CacheRec root; 41 42 } FTC_SBit_CacheRec; 43 44 45 46 /*************************************************************************/ 47 /*************************************************************************/ 48 /***** *****/ 49 /***** SBIT CACHE NODES *****/ 50 /***** *****/ 51 /*************************************************************************/ 52 /*************************************************************************/ 53 54 55 LOCAL_FUNC_X 56 void ftc_sbit_chunk_node_destroy( FTC_ChunkNode node ) 57 { 58 FTC_ChunkSet cset = node->cset; 59 FT_Memory memory = cset->memory; 60 FT_UInt count = node->num_elements; 61 FTC_SBit sbit = (FTC_SBit)node->elements; 62 63 64 for ( ; count > 0; sbit++, count-- ) 65 FREE( sbit->buffer ); 66 67 FREE( node->elements ); 68 FREE( node ); 69 } 70 71 72 LOCAL_FUNC_X 73 FT_Error ftc_bitmap_copy( FT_Memory memory, 74 FT_Bitmap* source, 75 FTC_SBit target ) 76 { 77 FT_Error error; 78 FT_Int pitch = source->pitch; 79 FT_ULong size; 80 81 82 if ( pitch < 0 ) 83 pitch = -pitch; 84 85 size = (FT_ULong)( pitch * source->rows ); 86 87 if ( !ALLOC( target->buffer, size ) ) 88 MEM_Copy( target->buffer, source->buffer, size ); 89 90 return error; 91 } 92 93 94 LOCAL_FUNC_X 95 FT_Error ftc_sbit_chunk_node_new( FTC_ChunkSet cset, 96 FT_UInt index, 97 FTC_ChunkNode* anode ) 98 { 99 FT_Error error; 100 FT_Memory memory = cset->memory; 101 FTC_SBitSet sbitset = (FTC_SBitSet)cset; 102 FTC_ChunkNode node = 0; 103 FT_Face face; 104 FT_Size size; 105 106 107 /* allocate node */ 108 if ( ALLOC( node, sizeof ( *node ) ) ) 109 goto Exit; 110 111 /* initialize its inner fields */ 112 error = FTC_ChunkNode_Init( node, cset, index, 1 ); 113 if ( error ) 114 goto Exit; 115 116 /* we will now load all glyph images for this chunk */ 117 error = FTC_Manager_Lookup_Size( cset->manager, 118 &sbitset->desc.font, 119 &face, &size ); 120 if ( !error ) 121 { 122 FT_UInt glyph_index = index * cset->element_count; 123 FT_UInt load_flags = FT_LOAD_DEFAULT; 124 FT_UInt image_type = sbitset->desc.image_type; 125 FT_UInt count = node->num_elements; 126 FTC_SBit sbit = (FTC_SBit)node->elements; 127 128 129 /* determine load flags, depending on the font description's */ 130 /* image type */ 131 132 if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap ) 133 { 134 if ( image_type & ftc_image_flag_monochrome ) 135 load_flags |= FT_LOAD_MONOCHROME; 136 137 /* disable embedded bitmaps loading if necessary */ 138 if ( image_type & ftc_image_flag_no_sbits ) 139 load_flags |= FT_LOAD_NO_BITMAP; 140 } 141 else 142 { 143 FT_ERROR(( "FTC_SBit_Cache: cannot load scalable glyphs in an" 144 " sbit cache, please check your arguments!\n" )); 145 error = FT_Err_Invalid_Argument; 146 goto Exit; 147 } 148 149 /* always render glyphs to bitmaps */ 150 load_flags |= FT_LOAD_RENDER; 151 152 if ( image_type & ftc_image_flag_unhinted ) 153 load_flags |= FT_LOAD_NO_HINTING; 154 155 if ( image_type & ftc_image_flag_autohinted ) 156 load_flags |= FT_LOAD_FORCE_AUTOHINT; 157 158 /* load a chunk of small bitmaps in a row */ 159 for ( ; count > 0; count--, glyph_index++, sbit++ ) 160 { 161 /* by default, indicates a `missing' glyph */ 162 sbit->buffer = 0; 163 164 error = FT_Load_Glyph( face, glyph_index, load_flags ); 165 if ( !error ) 166 { 167 FT_Int temp; 168 FT_GlyphSlot slot = face->glyph; 169 FT_Bitmap* bitmap = &slot->bitmap; 170 FT_Int xadvance, yadvance; 171 172 173 /* check that our values fit into 8-bit containers! */ 174 /* If this is not the case, our bitmap is too large */ 175 /* and we will leave it as `missing' with sbit.buffer = 0 */ 176 177#define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d ) 178#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d ) 179 180 /* XXX: FIXME: add support for vertical layouts maybe */ 181 182 /* horizontal advance in pixels */ 183 xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6; 184 yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6; 185 186 if ( CHECK_BYTE( bitmap->rows ) && 187 CHECK_BYTE( bitmap->width ) && 188 CHECK_CHAR( bitmap->pitch ) && 189 CHECK_CHAR( slot->bitmap_left ) && 190 CHECK_CHAR( slot->bitmap_top ) && 191 CHECK_CHAR( xadvance ) && 192 CHECK_CHAR( yadvance ) ) 193 { 194 sbit->width = (FT_Byte)bitmap->width; 195 sbit->height = (FT_Byte)bitmap->rows; 196 sbit->pitch = (FT_Char)bitmap->pitch; 197 sbit->left = (FT_Char)slot->bitmap_left; 198 sbit->top = (FT_Char)slot->bitmap_top; 199 sbit->xadvance = (FT_Char)xadvance; 200 sbit->yadvance = (FT_Char)yadvance; 201 sbit->format = (FT_Byte)bitmap->pixel_mode; 202 203 /* grab the bitmap when possible */ 204 if ( slot->flags & ft_glyph_own_bitmap ) 205 { 206 slot->flags &= ~ft_glyph_own_bitmap; 207 sbit->buffer = bitmap->buffer; 208 } 209 else 210 { 211 /* copy the bitmap into a new buffer -- ignore error */ 212 ftc_bitmap_copy( memory, bitmap, sbit ); 213 } 214 } 215 } 216 } 217 218 /* ignore the errors that might have occurred -- */ 219 /* we recognize unloaded glyphs with `sbit.buffer == 0' */ 220 error = 0; 221 } 222 223 Exit: 224 if ( error && node ) 225 { 226 FREE( node->elements ); 227 FREE( node ); 228 } 229 230 *anode = node; 231 232 return error; 233 } 234 235 236 /* this function is important because it is both part of */ 237 /* an FTC_ChunkSet_Class and an FTC_CacheNode_Class */ 238 /* */ 239 LOCAL_FUNC_X 240 FT_ULong ftc_sbit_chunk_node_size( FTC_ChunkNode node ) 241 { 242 FT_ULong size; 243 FTC_ChunkSet cset = node->cset; 244 FT_UInt count = node->num_elements; 245 FT_Int pitch; 246 FTC_SBit sbit = (FTC_SBit)node->elements; 247 248 249 /* the node itself */ 250 size = sizeof ( *node ); 251 /* the sbit records */ 252 size += cset->element_count * sizeof ( FTC_SBitRec ); 253 254 for ( ; count > 0; count--, sbit++ ) 255 { 256 if ( sbit->buffer ) 257 { 258 pitch = sbit->pitch; 259 if ( pitch < 0 ) 260 pitch = -pitch; 261 262 /* add the size of a given glyph image */ 263 size += pitch * sbit->height; 264 } 265 } 266 267 return size; 268 } 269 270 271 /*************************************************************************/ 272 /*************************************************************************/ 273 /***** *****/ 274 /***** SBIT CHUNK SETS *****/ 275 /***** *****/ 276 /*************************************************************************/ 277 /*************************************************************************/ 278 279 280 LOCAL_FUNC_X 281 FT_Error ftc_sbit_chunk_set_sizes( FTC_ChunkSet cset, 282 FTC_Image_Desc* desc ) 283 { 284 FT_Error error; 285 FT_Face face; 286 287 288 cset->element_count = FTC_SBITSET_ELEMENT_COUNT; 289 cset->element_size = sizeof ( FTC_SBitRec ); 290 291 /* lookup the FT_Face to obtain the number of glyphs */ 292 error = FTC_Manager_Lookup_Face( cset->manager, 293 desc->font.face_id, &face ); 294 if ( !error ) 295 cset->element_max = face->num_glyphs; 296 297 return error; 298 } 299 300 301 LOCAL_FUNC_X 302 FT_Error ftc_sbit_chunk_set_init( FTC_SBitSet sset, 303 FTC_Image_Desc* type ) 304 { 305 sset->desc = *type; 306 307 return 0; 308 } 309 310 311 LOCAL_FUNC_X 312 FT_Bool ftc_sbit_chunk_set_compare( FTC_SBitSet sset, 313 FTC_Image_Desc* type ) 314 { 315 return !memcmp( &sset->desc, type, sizeof ( *type ) ); 316 } 317 318 319 FT_CPLUSPLUS( const FTC_ChunkSet_Class ) ftc_sbit_chunk_set_class = 320 { 321 sizeof( FTC_SBitSetRec ), 322 323 (FTC_ChunkSet_InitFunc) ftc_sbit_chunk_set_init, 324 (FTC_ChunkSet_DoneFunc) 0, 325 (FTC_ChunkSet_CompareFunc) ftc_sbit_chunk_set_compare, 326 (FTC_ChunkSet_SizesFunc) ftc_sbit_chunk_set_sizes, 327 328 (FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new, 329 (FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size, 330 (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy 331 }; 332 333 334 /*************************************************************************/ 335 /*************************************************************************/ 336 /***** *****/ 337 /***** SBITS CACHE *****/ 338 /***** *****/ 339 /*************************************************************************/ 340 /*************************************************************************/ 341 342 343 FT_CPLUSPLUS( const FTC_Chunk_Cache_Class ) ftc_sbit_cache_class = 344 { 345 { 346 sizeof( FTC_SBit_CacheRec ), 347 (FTC_Cache_InitFunc)FTC_Chunk_Cache_Init, 348 (FTC_Cache_DoneFunc)FTC_Chunk_Cache_Done 349 }, 350 (FTC_ChunkSet_Class*)&ftc_sbit_chunk_set_class 351 }; 352 353 354 FT_EXPORT_FUNC( FT_Error ) FTC_SBit_Cache_New( FTC_Manager manager, 355 FTC_SBit_Cache* acache ) 356 { 357 return FTC_Manager_Register_Cache( 358 manager, 359 (FTC_Cache_Class*)&ftc_sbit_cache_class, 360 (FTC_Cache*)acache ); 361 } 362 363 364 FT_EXPORT_DEF( FT_Error ) FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache, 365 FTC_Image_Desc* desc, 366 FT_UInt gindex, 367 FTC_SBit* asbit ) 368 { 369 FT_Error error; 370 FTC_ChunkSet cset; 371 FTC_ChunkNode node; 372 FT_UInt cindex; 373 FTC_Manager manager; 374 375 FTC_SBitSet sset; 376 FTC_SBit sbit; 377 378 379 /* check for valid `desc' delayed to FT_Lru_Lookup() */ 380 381 if ( !cache || !asbit ) 382 return FT_Err_Invalid_Argument; 383 384 *asbit = 0; 385 cset = cache->root.last_cset; 386 sset = (FTC_SBitSet)cset; 387 388 if ( !cset || memcmp( &sset->desc, desc, sizeof ( *desc ) ) ) 389 { 390 error = FT_Lru_Lookup( cache->root.csets_lru, 391 (FT_LruKey)desc, 392 (FT_Pointer*)&cset ); 393 cache->root.last_cset = cset; 394 if ( error ) 395 goto Exit; 396 } 397 398 error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex ); 399 if ( error ) 400 goto Exit; 401 402 /* now compress the manager's cache pool if needed */ 403 manager = cache->root.root.manager; 404 if ( manager->num_bytes > manager->max_bytes ) 405 { 406 FTC_ChunkNode_Ref ( node ); 407 FTC_Manager_Compress( manager ); 408 FTC_ChunkNode_Unref ( node ); 409 } 410 411 sbit = ((FTC_SBit)((FTC_ChunkNode)node)->elements) + cindex; 412 *asbit = sbit; 413 414 Exit: 415 return error; 416 } 417 418 419/* END */ 420