1 /***************************************************************************/ 2 /* */ 3 /* ftcsbits.c */ 4 /* */ 5 /* FreeType sbits manager (body). */ 6 /* */ 7 /* Copyright 2000-2001, 2002 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 <ft2build.h> 20 #include FT_CACHE_H 21 #include FT_CACHE_SMALL_BITMAPS_H 22 #include FT_CACHE_INTERNAL_GLYPH_H 23 #include FT_INTERNAL_OBJECTS_H 24 #include FT_INTERNAL_DEBUG_H 25 #include FT_ERRORS_H 26 27 #include "ftcerror.h" 28 29 30 #define FTC_SBIT_ITEMS_PER_NODE 16 31 32 33 typedef struct FTC_SBitNodeRec_* FTC_SBitNode; 34 35 typedef struct FTC_SBitNodeRec_ 36 { 37 FTC_GlyphNodeRec gnode; 38 FTC_SBitRec sbits[FTC_SBIT_ITEMS_PER_NODE]; 39 40 } FTC_SBitNodeRec; 41 42 43 #define FTC_SBIT_NODE( x ) ( (FTC_SBitNode)( x ) ) 44 45 46 typedef struct FTC_SBitQueryRec_ 47 { 48 FTC_GlyphQueryRec gquery; 49 FTC_ImageTypeRec type; 50 51 } FTC_SBitQueryRec, *FTC_SBitQuery; 52 53 54 #define FTC_SBIT_QUERY( x ) ( (FTC_SBitQuery)( x ) ) 55 56 57 typedef struct FTC_SBitFamilyRec_* FTC_SBitFamily; 58 59 /* sbit family structure */ 60 typedef struct FTC_SBitFamilyRec_ 61 { 62 FTC_GlyphFamilyRec gfam; 63 FTC_ImageTypeRec type; 64 65 } FTC_SBitFamilyRec; 66 67 68 #define FTC_SBIT_FAMILY( x ) ( (FTC_SBitFamily)( x ) ) 69 #define FTC_SBIT_FAMILY_MEMORY( x ) FTC_GLYPH_FAMILY_MEMORY( &( x )->cset ) 70 71 72 /*************************************************************************/ 73 /*************************************************************************/ 74 /***** *****/ 75 /***** SBIT CACHE NODES *****/ 76 /***** *****/ 77 /*************************************************************************/ 78 /*************************************************************************/ 79 80 81 static FT_Error ftc_sbit_copy_bitmap(FTC_SBit sbit,FT_Bitmap * bitmap,FT_Memory memory)82 ftc_sbit_copy_bitmap( FTC_SBit sbit, 83 FT_Bitmap* bitmap, 84 FT_Memory memory ) 85 { 86 FT_Error error; 87 FT_Int pitch = bitmap->pitch; 88 FT_ULong size; 89 90 91 if ( pitch < 0 ) 92 pitch = -pitch; 93 94 size = (FT_ULong)( pitch * bitmap->rows ); 95 96 if ( !FT_ALLOC( sbit->buffer, size ) ) 97 FT_MEM_COPY( sbit->buffer, bitmap->buffer, size ); 98 99 return error; 100 } 101 102 103 FT_CALLBACK_DEF( void ) ftc_sbit_node_done(FTC_SBitNode snode,FTC_Cache cache)104 ftc_sbit_node_done( FTC_SBitNode snode, 105 FTC_Cache cache ) 106 { 107 FTC_SBit sbit = snode->sbits; 108 FT_UInt count = FTC_GLYPH_NODE( snode )->item_count; 109 FT_Memory memory = cache->memory; 110 111 112 for ( ; count > 0; sbit++, count-- ) 113 FT_FREE( sbit->buffer ); 114 115 ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache ); 116 } 117 118 119 static FT_Error ftc_sbit_node_load(FTC_SBitNode snode,FTC_Manager manager,FTC_SBitFamily sfam,FT_UInt gindex,FT_ULong * asize)120 ftc_sbit_node_load( FTC_SBitNode snode, 121 FTC_Manager manager, 122 FTC_SBitFamily sfam, 123 FT_UInt gindex, 124 FT_ULong *asize ) 125 { 126 FT_Error error; 127 FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode ); 128 FT_Memory memory; 129 FT_Face face; 130 FT_Size size; 131 FTC_SBit sbit; 132 133 134 if ( gindex < (FT_UInt)gnode->item_start || 135 gindex >= (FT_UInt)gnode->item_start + gnode->item_count ) 136 { 137 FT_ERROR(( "ftc_sbit_node_load: invalid glyph index" )); 138 return FTC_Err_Invalid_Argument; 139 } 140 141 memory = manager->library->memory; 142 143 sbit = snode->sbits + ( gindex - gnode->item_start ); 144 145 error = FTC_Manager_Lookup_Size( manager, &sfam->type.font, 146 &face, &size ); 147 if ( !error ) 148 { 149 /* by default, indicates a `missing' glyph */ 150 sbit->buffer = 0; 151 152 error = FT_Load_Glyph( face, gindex, sfam->type.flags | FT_LOAD_RENDER ); 153 if ( !error ) 154 { 155 FT_Int temp; 156 FT_GlyphSlot slot = face->glyph; 157 FT_Bitmap* bitmap = &slot->bitmap; 158 FT_Int xadvance, yadvance; 159 160 161 /* check that our values fit into 8-bit containers! */ 162 /* If this is not the case, our bitmap is too large */ 163 /* and we will leave it as `missing' with sbit.buffer = 0 */ 164 165 #define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d ) 166 #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d ) 167 168 /* XXX: FIXME: add support for vertical layouts maybe */ 169 170 /* horizontal advance in pixels */ 171 xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6; 172 yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6; 173 174 if ( CHECK_BYTE( bitmap->rows ) && 175 CHECK_BYTE( bitmap->width ) && 176 CHECK_CHAR( bitmap->pitch ) && 177 CHECK_CHAR( slot->bitmap_left ) && 178 CHECK_CHAR( slot->bitmap_top ) && 179 CHECK_CHAR( xadvance ) && 180 CHECK_CHAR( yadvance ) ) 181 { 182 sbit->width = (FT_Byte)bitmap->width; 183 sbit->height = (FT_Byte)bitmap->rows; 184 sbit->pitch = (FT_Char)bitmap->pitch; 185 sbit->left = (FT_Char)slot->bitmap_left; 186 sbit->top = (FT_Char)slot->bitmap_top; 187 sbit->xadvance = (FT_Char)xadvance; 188 sbit->yadvance = (FT_Char)yadvance; 189 sbit->format = (FT_Byte)bitmap->pixel_mode; 190 sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1); 191 192 #if 0 /* this doesn't work well with embedded bitmaps !! */ 193 194 /* grab the bitmap when possible - this is a hack! */ 195 if ( slot->flags & FT_GLYPH_OWN_BITMAP ) 196 { 197 slot->flags &= ~FT_GLYPH_OWN_BITMAP; 198 sbit->buffer = bitmap->buffer; 199 } 200 else 201 #endif 202 { 203 /* copy the bitmap into a new buffer -- ignore error */ 204 error = ftc_sbit_copy_bitmap( sbit, bitmap, memory ); 205 } 206 207 /* now, compute size */ 208 if ( asize ) 209 *asize = ABS( sbit->pitch ) * sbit->height; 210 211 } /* glyph dimensions ok */ 212 213 } /* glyph loading successful */ 214 215 /* ignore the errors that might have occurred -- */ 216 /* we mark unloaded glyphs with `sbit.buffer == 0' */ 217 /* and 'width == 255', 'height == 0' */ 218 /* */ 219 if ( error ) 220 { 221 sbit->width = 255; 222 error = 0; 223 /* sbit->buffer == NULL too! */ 224 } 225 } 226 227 return error; 228 } 229 230 231 FT_CALLBACK_DEF( FT_Error ) ftc_sbit_node_init(FTC_SBitNode snode,FTC_GlyphQuery gquery,FTC_Cache cache)232 ftc_sbit_node_init( FTC_SBitNode snode, 233 FTC_GlyphQuery gquery, 234 FTC_Cache cache ) 235 { 236 FT_Error error; 237 238 239 ftc_glyph_node_init( FTC_GLYPH_NODE( snode ), 240 gquery->gindex, 241 FTC_GLYPH_FAMILY( gquery->query.family ) ); 242 243 error = ftc_sbit_node_load( snode, 244 cache->manager, 245 FTC_SBIT_FAMILY( FTC_QUERY( gquery )->family ), 246 gquery->gindex, 247 NULL ); 248 if ( error ) 249 ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache ); 250 251 return error; 252 } 253 254 255 FT_CALLBACK_DEF( FT_ULong ) ftc_sbit_node_weight(FTC_SBitNode snode)256 ftc_sbit_node_weight( FTC_SBitNode snode ) 257 { 258 FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode ); 259 FT_UInt count = gnode->item_count; 260 FTC_SBit sbit = snode->sbits; 261 FT_Int pitch; 262 FT_ULong size; 263 264 265 /* the node itself */ 266 size = sizeof ( *snode ); 267 268 /* the sbit records */ 269 size += FTC_GLYPH_NODE( snode )->item_count * sizeof ( FTC_SBitRec ); 270 271 for ( ; count > 0; count--, sbit++ ) 272 { 273 if ( sbit->buffer ) 274 { 275 pitch = sbit->pitch; 276 if ( pitch < 0 ) 277 pitch = -pitch; 278 279 /* add the size of a given glyph image */ 280 size += pitch * sbit->height; 281 } 282 } 283 284 return size; 285 } 286 287 288 FT_CALLBACK_DEF( FT_Bool ) ftc_sbit_node_compare(FTC_SBitNode snode,FTC_SBitQuery squery,FTC_Cache cache)289 ftc_sbit_node_compare( FTC_SBitNode snode, 290 FTC_SBitQuery squery, 291 FTC_Cache cache ) 292 { 293 FTC_GlyphQuery gquery = FTC_GLYPH_QUERY( squery ); 294 FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode ); 295 FT_Bool result; 296 297 298 result = ftc_glyph_node_compare( gnode, gquery ); 299 if ( result ) 300 { 301 /* check if we need to load the glyph bitmap now */ 302 FT_UInt gindex = gquery->gindex; 303 FTC_SBit sbit = snode->sbits + ( gindex - gnode->item_start ); 304 305 306 if ( sbit->buffer == NULL && sbit->width != 255 ) 307 { 308 FT_ULong size; 309 310 311 /* yes, it's safe to ignore errors here */ 312 ftc_sbit_node_load( snode, 313 cache->manager, 314 FTC_SBIT_FAMILY( FTC_QUERY( squery )->family ), 315 gindex, 316 &size ); 317 318 cache->manager->cur_weight += size; 319 } 320 } 321 322 return result; 323 } 324 325 326 /*************************************************************************/ 327 /*************************************************************************/ 328 /***** *****/ 329 /***** SBITS FAMILIES *****/ 330 /***** *****/ 331 /*************************************************************************/ 332 /*************************************************************************/ 333 334 335 FT_CALLBACK_DEF( FT_Error ) ftc_sbit_family_init(FTC_SBitFamily sfam,FTC_SBitQuery squery,FTC_Cache cache)336 ftc_sbit_family_init( FTC_SBitFamily sfam, 337 FTC_SBitQuery squery, 338 FTC_Cache cache ) 339 { 340 FTC_Manager manager = cache->manager; 341 FT_Error error; 342 FT_Face face; 343 344 345 sfam->type = squery->type; 346 347 /* we need to compute "cquery.item_total" now */ 348 error = FTC_Manager_Lookup_Face( manager, 349 squery->type.font.face_id, 350 &face ); 351 if ( !error ) 352 { 353 error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( sfam ), 354 FTC_IMAGE_TYPE_HASH( &sfam->type ), 355 FTC_SBIT_ITEMS_PER_NODE, 356 face->num_glyphs, 357 FTC_GLYPH_QUERY( squery ), 358 cache ); 359 } 360 361 return error; 362 } 363 364 365 FT_CALLBACK_DEF( FT_Bool ) ftc_sbit_family_compare(FTC_SBitFamily sfam,FTC_SBitQuery squery)366 ftc_sbit_family_compare( FTC_SBitFamily sfam, 367 FTC_SBitQuery squery ) 368 { 369 FT_Bool result; 370 371 372 /* we need to set the "cquery.cset" field or our query for */ 373 /* faster glyph comparisons in ftc_sbit_node_compare */ 374 /* */ 375 result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &sfam->type, &squery->type ) ); 376 if ( result ) 377 FTC_GLYPH_FAMILY_FOUND( sfam, squery ); 378 379 return result; 380 } 381 382 383 /*************************************************************************/ 384 /*************************************************************************/ 385 /***** *****/ 386 /***** SBITS CACHE *****/ 387 /***** *****/ 388 /*************************************************************************/ 389 /*************************************************************************/ 390 391 392 FT_CALLBACK_TABLE_DEF 393 const FTC_Cache_ClassRec ftc_sbit_cache_class = 394 { 395 sizeof ( FTC_CacheRec ), 396 (FTC_Cache_InitFunc) ftc_cache_init, 397 (FTC_Cache_ClearFunc)ftc_cache_clear, 398 (FTC_Cache_DoneFunc) ftc_cache_done, 399 400 sizeof ( FTC_SBitFamilyRec ), 401 (FTC_Family_InitFunc) ftc_sbit_family_init, 402 (FTC_Family_CompareFunc)ftc_sbit_family_compare, 403 (FTC_Family_DoneFunc) ftc_glyph_family_done, 404 405 sizeof ( FTC_SBitNodeRec ), 406 (FTC_Node_InitFunc) ftc_sbit_node_init, 407 (FTC_Node_WeightFunc) ftc_sbit_node_weight, 408 (FTC_Node_CompareFunc)ftc_sbit_node_compare, 409 (FTC_Node_DoneFunc) ftc_sbit_node_done 410 }; 411 412 413 /* documentation is in ftcsbits.h */ 414 415 FT_EXPORT_DEF( FT_Error ) FTC_SBitCache_New(FTC_Manager manager,FTC_SBitCache * acache)416 FTC_SBitCache_New( FTC_Manager manager, 417 FTC_SBitCache *acache ) 418 { 419 return FTC_Manager_Register_Cache( manager, 420 &ftc_sbit_cache_class, 421 (FTC_Cache*)acache ); 422 } 423 424 425 /* documentation is in ftcsbits.h */ 426 427 #ifdef FTC_CACHE_USE_INLINE 428 429 #define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \ 430 ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) ) 431 432 #define GEN_CACHE_NODE_COMPARE( n, q, c ) \ 433 ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c ) 434 435 #define GEN_CACHE_LOOKUP ftc_sbit_cache_lookup 436 #include "ftccache.i" 437 438 #else /* !FTC_CACHE_USE_INLINE */ 439 440 #define ftc_sbit_cache_lookup ftc_cache_lookup 441 442 #endif /* !FTC_CACHE_USE_INLINE */ 443 444 FT_EXPORT_DEF( FT_Error ) FTC_SBitCache_Lookup(FTC_SBitCache cache,FTC_ImageType type,FT_UInt gindex,FTC_SBit * ansbit,FTC_Node * anode)445 FTC_SBitCache_Lookup( FTC_SBitCache cache, 446 FTC_ImageType type, 447 FT_UInt gindex, 448 FTC_SBit *ansbit, 449 FTC_Node *anode ) 450 { 451 FT_Error error; 452 FTC_SBitQueryRec squery; 453 FTC_SBitNode node; 454 455 456 /* other argument checks delayed to ftc_cache_lookup */ 457 if ( !ansbit ) 458 return FTC_Err_Invalid_Argument; 459 460 *ansbit = NULL; 461 462 if ( anode ) 463 *anode = NULL; 464 465 squery.gquery.gindex = gindex; 466 squery.type = *type; 467 468 error = ftc_sbit_cache_lookup( FTC_CACHE( cache ), 469 FTC_QUERY( &squery ), 470 (FTC_Node*)&node ); 471 if ( !error ) 472 { 473 *ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start ); 474 475 if ( anode ) 476 { 477 *anode = FTC_NODE( node ); 478 FTC_NODE( node )->ref_count++; 479 } 480 } 481 return error; 482 } 483 484 485 /* backwards-compatibility functions */ 486 487 FT_EXPORT_DEF( FT_Error ) FTC_SBit_Cache_New(FTC_Manager manager,FTC_SBit_Cache * acache)488 FTC_SBit_Cache_New( FTC_Manager manager, 489 FTC_SBit_Cache *acache ) 490 { 491 return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache ); 492 } 493 494 495 FT_EXPORT_DEF( FT_Error ) FTC_SBit_Cache_Lookup(FTC_SBit_Cache cache,FTC_Image_Desc * desc,FT_UInt gindex,FTC_SBit * ansbit)496 FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache, 497 FTC_Image_Desc* desc, 498 FT_UInt gindex, 499 FTC_SBit *ansbit ) 500 { 501 FTC_ImageTypeRec type0; 502 503 504 if ( !desc ) 505 return FTC_Err_Invalid_Argument; 506 507 type0.font = desc->font; 508 type0.flags = 0; 509 510 /* convert image type flags to load flags */ 511 { 512 FT_UInt load_flags = FT_LOAD_DEFAULT; 513 FT_UInt type = desc->image_type; 514 515 516 /* determine load flags, depending on the font description's */ 517 /* image type */ 518 519 if ( ftc_image_format( type ) == ftc_image_format_bitmap ) 520 { 521 if ( type & ftc_image_flag_monochrome ) 522 load_flags |= FT_LOAD_MONOCHROME; 523 524 /* disable embedded bitmaps loading if necessary */ 525 if ( type & ftc_image_flag_no_sbits ) 526 load_flags |= FT_LOAD_NO_BITMAP; 527 } 528 else 529 { 530 /* we want an outline, don't load embedded bitmaps */ 531 load_flags |= FT_LOAD_NO_BITMAP; 532 533 if ( type & ftc_image_flag_unscaled ) 534 load_flags |= FT_LOAD_NO_SCALE; 535 } 536 537 /* always render glyphs to bitmaps */ 538 load_flags |= FT_LOAD_RENDER; 539 540 if ( type & ftc_image_flag_unhinted ) 541 load_flags |= FT_LOAD_NO_HINTING; 542 543 if ( type & ftc_image_flag_autohinted ) 544 load_flags |= FT_LOAD_FORCE_AUTOHINT; 545 546 type0.flags = load_flags; 547 } 548 549 return FTC_SBitCache_Lookup( (FTC_SBitCache)cache, 550 &type0, 551 gindex, 552 ansbit, 553 NULL ); 554 } 555 556 557 /* END */ 558