1 /***************************************************************************/ 2 /* */ 3 /* ftcbasic.c */ 4 /* */ 5 /* The FreeType basic cache interface (body). */ 6 /* */ 7 /* Copyright 2003-2015 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_INTERNAL_OBJECTS_H 21 #include FT_INTERNAL_DEBUG_H 22 #include FT_CACHE_H 23 #include "ftcglyph.h" 24 #include "ftcimage.h" 25 #include "ftcsbits.h" 26 27 #include "ftccback.h" 28 #include "ftcerror.h" 29 30 #define FT_COMPONENT trace_cache 31 32 33 /* 34 * Basic Families 35 * 36 */ 37 typedef struct FTC_BasicAttrRec_ 38 { 39 FTC_ScalerRec scaler; 40 FT_UInt load_flags; 41 42 } FTC_BasicAttrRec, *FTC_BasicAttrs; 43 44 #define FTC_BASIC_ATTR_COMPARE( a, b ) \ 45 FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \ 46 (a)->load_flags == (b)->load_flags ) 47 48 #define FTC_BASIC_ATTR_HASH( a ) \ 49 ( FTC_SCALER_HASH( &(a)->scaler ) + 31 * (a)->load_flags ) 50 51 52 typedef struct FTC_BasicQueryRec_ 53 { 54 FTC_GQueryRec gquery; 55 FTC_BasicAttrRec attrs; 56 57 } FTC_BasicQueryRec, *FTC_BasicQuery; 58 59 60 typedef struct FTC_BasicFamilyRec_ 61 { 62 FTC_FamilyRec family; 63 FTC_BasicAttrRec attrs; 64 65 } FTC_BasicFamilyRec, *FTC_BasicFamily; 66 67 68 FT_CALLBACK_DEF( FT_Bool ) 69 ftc_basic_family_compare( FTC_MruNode ftcfamily, 70 FT_Pointer ftcquery ) 71 { 72 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 73 FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; 74 75 76 return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ); 77 } 78 79 80 FT_CALLBACK_DEF( FT_Error ) 81 ftc_basic_family_init( FTC_MruNode ftcfamily, 82 FT_Pointer ftcquery, 83 FT_Pointer ftccache ) 84 { 85 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 86 FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; 87 FTC_Cache cache = (FTC_Cache)ftccache; 88 89 90 FTC_Family_Init( FTC_FAMILY( family ), cache ); 91 family->attrs = query->attrs; 92 return 0; 93 } 94 95 96 FT_CALLBACK_DEF( FT_UInt ) 97 ftc_basic_family_get_count( FTC_Family ftcfamily, 98 FTC_Manager manager ) 99 { 100 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 101 FT_Error error; 102 FT_Face face; 103 FT_UInt result = 0; 104 105 106 error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id, 107 &face ); 108 109 if ( error || !face ) 110 return result; 111 112 if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs ) 113 FT_TRACE1(( "ftc_basic_family_get_count:" 114 " too large number of glyphs in this face, truncated\n", 115 face->num_glyphs )); 116 117 if ( !error ) 118 result = (FT_UInt)face->num_glyphs; 119 120 return result; 121 } 122 123 124 FT_CALLBACK_DEF( FT_Error ) 125 ftc_basic_family_load_bitmap( FTC_Family ftcfamily, 126 FT_UInt gindex, 127 FTC_Manager manager, 128 FT_Face *aface ) 129 { 130 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 131 FT_Error error; 132 FT_Size size; 133 134 135 error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size ); 136 if ( !error ) 137 { 138 FT_Face face = size->face; 139 140 141 error = FT_Load_Glyph( 142 face, 143 gindex, 144 (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER ); 145 if ( !error ) 146 *aface = face; 147 } 148 149 return error; 150 } 151 152 153 FT_CALLBACK_DEF( FT_Error ) 154 ftc_basic_family_load_glyph( FTC_Family ftcfamily, 155 FT_UInt gindex, 156 FTC_Cache cache, 157 FT_Glyph *aglyph ) 158 { 159 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 160 FT_Error error; 161 FTC_Scaler scaler = &family->attrs.scaler; 162 FT_Face face; 163 FT_Size size; 164 165 166 /* we will now load the glyph image */ 167 error = FTC_Manager_LookupSize( cache->manager, 168 scaler, 169 &size ); 170 if ( !error ) 171 { 172 face = size->face; 173 174 error = FT_Load_Glyph( face, 175 gindex, 176 (FT_Int)family->attrs.load_flags ); 177 if ( !error ) 178 { 179 if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || 180 face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) 181 { 182 /* ok, copy it */ 183 FT_Glyph glyph; 184 185 186 error = FT_Get_Glyph( face->glyph, &glyph ); 187 if ( !error ) 188 { 189 *aglyph = glyph; 190 goto Exit; 191 } 192 } 193 else 194 error = FT_THROW( Invalid_Argument ); 195 } 196 } 197 198 Exit: 199 return error; 200 } 201 202 203 FT_CALLBACK_DEF( FT_Bool ) 204 ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode, 205 FT_Pointer ftcface_id, 206 FTC_Cache cache, 207 FT_Bool* list_changed ) 208 { 209 FTC_GNode gnode = (FTC_GNode)ftcgnode; 210 FTC_FaceID face_id = (FTC_FaceID)ftcface_id; 211 FTC_BasicFamily family = (FTC_BasicFamily)gnode->family; 212 FT_Bool result; 213 214 215 if ( list_changed ) 216 *list_changed = FALSE; 217 result = FT_BOOL( family->attrs.scaler.face_id == face_id ); 218 if ( result ) 219 { 220 /* we must call this function to avoid this node from appearing 221 * in later lookups with the same face_id! 222 */ 223 FTC_GNode_UnselectFamily( gnode, cache ); 224 } 225 return result; 226 } 227 228 229 /* 230 * 231 * basic image cache 232 * 233 */ 234 235 static 236 const FTC_IFamilyClassRec ftc_basic_image_family_class = 237 { 238 { 239 sizeof ( FTC_BasicFamilyRec ), 240 ftc_basic_family_compare, 241 ftc_basic_family_init, 242 0, /* FTC_MruNode_ResetFunc */ 243 0 /* FTC_MruNode_DoneFunc */ 244 }, 245 ftc_basic_family_load_glyph 246 }; 247 248 249 static 250 const FTC_GCacheClassRec ftc_basic_image_cache_class = 251 { 252 { 253 ftc_inode_new, 254 ftc_inode_weight, 255 ftc_gnode_compare, 256 ftc_basic_gnode_compare_faceid, 257 ftc_inode_free, 258 259 sizeof ( FTC_GCacheRec ), 260 ftc_gcache_init, 261 ftc_gcache_done 262 }, 263 (FTC_MruListClass)&ftc_basic_image_family_class 264 }; 265 266 267 /* documentation is in ftcache.h */ 268 269 FT_EXPORT_DEF( FT_Error ) 270 FTC_ImageCache_New( FTC_Manager manager, 271 FTC_ImageCache *acache ) 272 { 273 return FTC_GCache_New( manager, &ftc_basic_image_cache_class, 274 (FTC_GCache*)acache ); 275 } 276 277 278 /* documentation is in ftcache.h */ 279 280 FT_EXPORT_DEF( FT_Error ) 281 FTC_ImageCache_Lookup( FTC_ImageCache cache, 282 FTC_ImageType type, 283 FT_UInt gindex, 284 FT_Glyph *aglyph, 285 FTC_Node *anode ) 286 { 287 FTC_BasicQueryRec query; 288 FTC_Node node = 0; /* make compiler happy */ 289 FT_Error error; 290 FT_Offset hash; 291 292 293 /* some argument checks are delayed to `FTC_Cache_Lookup' */ 294 if ( !aglyph ) 295 { 296 error = FT_THROW( Invalid_Argument ); 297 goto Exit; 298 } 299 300 *aglyph = NULL; 301 if ( anode ) 302 *anode = NULL; 303 304 if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX ) 305 FT_TRACE1(( "FTC_ImageCache_Lookup:" 306 " higher bits in load_flags 0x%x are dropped\n", 307 (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) )); 308 309 query.attrs.scaler.face_id = type->face_id; 310 query.attrs.scaler.width = type->width; 311 query.attrs.scaler.height = type->height; 312 query.attrs.load_flags = (FT_UInt)type->flags; 313 314 query.attrs.scaler.pixel = 1; 315 query.attrs.scaler.x_res = 0; /* make compilers happy */ 316 query.attrs.scaler.y_res = 0; 317 318 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; 319 320 #if 1 /* inlining is about 50% faster! */ 321 FTC_GCACHE_LOOKUP_CMP( cache, 322 ftc_basic_family_compare, 323 FTC_GNode_Compare, 324 hash, gindex, 325 &query, 326 node, 327 error ); 328 #else 329 error = FTC_GCache_Lookup( FTC_GCACHE( cache ), 330 hash, gindex, 331 FTC_GQUERY( &query ), 332 &node ); 333 #endif 334 if ( !error ) 335 { 336 *aglyph = FTC_INODE( node )->glyph; 337 338 if ( anode ) 339 { 340 *anode = node; 341 node->ref_count++; 342 } 343 } 344 345 Exit: 346 return error; 347 } 348 349 350 /* documentation is in ftcache.h */ 351 352 FT_EXPORT_DEF( FT_Error ) 353 FTC_ImageCache_LookupScaler( FTC_ImageCache cache, 354 FTC_Scaler scaler, 355 FT_ULong load_flags, 356 FT_UInt gindex, 357 FT_Glyph *aglyph, 358 FTC_Node *anode ) 359 { 360 FTC_BasicQueryRec query; 361 FTC_Node node = 0; /* make compiler happy */ 362 FT_Error error; 363 FT_Offset hash; 364 365 366 /* some argument checks are delayed to `FTC_Cache_Lookup' */ 367 if ( !aglyph || !scaler ) 368 { 369 error = FT_THROW( Invalid_Argument ); 370 goto Exit; 371 } 372 373 *aglyph = NULL; 374 if ( anode ) 375 *anode = NULL; 376 377 /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */ 378 if ( load_flags > FT_UINT_MAX ) 379 FT_TRACE1(( "FTC_ImageCache_LookupScaler:" 380 " higher bits in load_flags 0x%x are dropped\n", 381 load_flags & ~((FT_ULong)FT_UINT_MAX) )); 382 383 query.attrs.scaler = scaler[0]; 384 query.attrs.load_flags = (FT_UInt)load_flags; 385 386 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; 387 388 FTC_GCACHE_LOOKUP_CMP( cache, 389 ftc_basic_family_compare, 390 FTC_GNode_Compare, 391 hash, gindex, 392 &query, 393 node, 394 error ); 395 if ( !error ) 396 { 397 *aglyph = FTC_INODE( node )->glyph; 398 399 if ( anode ) 400 { 401 *anode = node; 402 node->ref_count++; 403 } 404 } 405 406 Exit: 407 return error; 408 } 409 410 411 /* 412 * 413 * basic small bitmap cache 414 * 415 */ 416 417 static 418 const FTC_SFamilyClassRec ftc_basic_sbit_family_class = 419 { 420 { 421 sizeof ( FTC_BasicFamilyRec ), 422 ftc_basic_family_compare, 423 ftc_basic_family_init, 424 0, /* FTC_MruNode_ResetFunc */ 425 0 /* FTC_MruNode_DoneFunc */ 426 }, 427 ftc_basic_family_get_count, 428 ftc_basic_family_load_bitmap 429 }; 430 431 432 static 433 const FTC_GCacheClassRec ftc_basic_sbit_cache_class = 434 { 435 { 436 ftc_snode_new, 437 ftc_snode_weight, 438 ftc_snode_compare, 439 ftc_basic_gnode_compare_faceid, 440 ftc_snode_free, 441 442 sizeof ( FTC_GCacheRec ), 443 ftc_gcache_init, 444 ftc_gcache_done 445 }, 446 (FTC_MruListClass)&ftc_basic_sbit_family_class 447 }; 448 449 450 /* documentation is in ftcache.h */ 451 452 FT_EXPORT_DEF( FT_Error ) 453 FTC_SBitCache_New( FTC_Manager manager, 454 FTC_SBitCache *acache ) 455 { 456 return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class, 457 (FTC_GCache*)acache ); 458 } 459 460 461 /* documentation is in ftcache.h */ 462 463 FT_EXPORT_DEF( FT_Error ) 464 FTC_SBitCache_Lookup( FTC_SBitCache cache, 465 FTC_ImageType type, 466 FT_UInt gindex, 467 FTC_SBit *ansbit, 468 FTC_Node *anode ) 469 { 470 FT_Error error; 471 FTC_BasicQueryRec query; 472 FTC_Node node = 0; /* make compiler happy */ 473 FT_Offset hash; 474 475 476 if ( anode ) 477 *anode = NULL; 478 479 /* other argument checks delayed to `FTC_Cache_Lookup' */ 480 if ( !ansbit ) 481 return FT_THROW( Invalid_Argument ); 482 483 *ansbit = NULL; 484 485 if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX ) 486 FT_TRACE1(( "FTC_ImageCache_Lookup:" 487 " higher bits in load_flags 0x%x are dropped\n", 488 (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) )); 489 490 query.attrs.scaler.face_id = type->face_id; 491 query.attrs.scaler.width = type->width; 492 query.attrs.scaler.height = type->height; 493 query.attrs.load_flags = (FT_UInt)type->flags; 494 495 query.attrs.scaler.pixel = 1; 496 query.attrs.scaler.x_res = 0; /* make compilers happy */ 497 query.attrs.scaler.y_res = 0; 498 499 /* beware, the hash must be the same for all glyph ranges! */ 500 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + 501 gindex / FTC_SBIT_ITEMS_PER_NODE; 502 503 #if 1 /* inlining is about 50% faster! */ 504 FTC_GCACHE_LOOKUP_CMP( cache, 505 ftc_basic_family_compare, 506 FTC_SNode_Compare, 507 hash, gindex, 508 &query, 509 node, 510 error ); 511 #else 512 error = FTC_GCache_Lookup( FTC_GCACHE( cache ), 513 hash, 514 gindex, 515 FTC_GQUERY( &query ), 516 &node ); 517 #endif 518 if ( error ) 519 goto Exit; 520 521 *ansbit = FTC_SNODE( node )->sbits + 522 ( gindex - FTC_GNODE( node )->gindex ); 523 524 if ( anode ) 525 { 526 *anode = node; 527 node->ref_count++; 528 } 529 530 Exit: 531 return error; 532 } 533 534 535 /* documentation is in ftcache.h */ 536 537 FT_EXPORT_DEF( FT_Error ) 538 FTC_SBitCache_LookupScaler( FTC_SBitCache cache, 539 FTC_Scaler scaler, 540 FT_ULong load_flags, 541 FT_UInt gindex, 542 FTC_SBit *ansbit, 543 FTC_Node *anode ) 544 { 545 FT_Error error; 546 FTC_BasicQueryRec query; 547 FTC_Node node = 0; /* make compiler happy */ 548 FT_Offset hash; 549 550 551 if ( anode ) 552 *anode = NULL; 553 554 /* other argument checks delayed to `FTC_Cache_Lookup' */ 555 if ( !ansbit || !scaler ) 556 return FT_THROW( Invalid_Argument ); 557 558 *ansbit = NULL; 559 560 /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */ 561 if ( load_flags > FT_UINT_MAX ) 562 FT_TRACE1(( "FTC_ImageCache_LookupScaler:" 563 " higher bits in load_flags 0x%x are dropped\n", 564 load_flags & ~((FT_ULong)FT_UINT_MAX) )); 565 566 query.attrs.scaler = scaler[0]; 567 query.attrs.load_flags = (FT_UInt)load_flags; 568 569 /* beware, the hash must be the same for all glyph ranges! */ 570 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + 571 gindex / FTC_SBIT_ITEMS_PER_NODE; 572 573 FTC_GCACHE_LOOKUP_CMP( cache, 574 ftc_basic_family_compare, 575 FTC_SNode_Compare, 576 hash, gindex, 577 &query, 578 node, 579 error ); 580 if ( error ) 581 goto Exit; 582 583 *ansbit = FTC_SNODE( node )->sbits + 584 ( gindex - FTC_GNODE( node )->gindex ); 585 586 if ( anode ) 587 { 588 *anode = node; 589 node->ref_count++; 590 } 591 592 Exit: 593 return error; 594 } 595 596 597 /* END */ 598