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