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