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