ftcbasic.c (16761B)
1 /**************************************************************************** 2 * 3 * ftcbasic.c 4 * 5 * The FreeType basic cache interface (body). 6 * 7 * Copyright (C) 2003-2025 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_Int32 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 ) + \ 50 (FT_Offset)( 31 * (a)->load_flags ) ) 51 52 53 typedef struct FTC_BasicQueryRec_ 54 { 55 FTC_GQueryRec gquery; 56 FTC_BasicAttrRec attrs; 57 58 } FTC_BasicQueryRec, *FTC_BasicQuery; 59 60 61 typedef struct FTC_BasicFamilyRec_ 62 { 63 FTC_FamilyRec family; 64 FTC_BasicAttrRec attrs; 65 66 } FTC_BasicFamilyRec, *FTC_BasicFamily; 67 68 69 FT_CALLBACK_DEF( FT_Bool ) 70 ftc_basic_family_compare( FTC_MruNode ftcfamily, 71 FT_Pointer ftcquery ) 72 { 73 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 74 FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; 75 76 77 return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ); 78 } 79 80 81 FT_CALLBACK_DEF( FT_Error ) 82 ftc_basic_family_init( FTC_MruNode ftcfamily, 83 FT_Pointer ftcquery, 84 FT_Pointer ftccache ) 85 { 86 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 87 FTC_BasicQuery query = (FTC_BasicQuery)ftcquery; 88 FTC_Cache cache = (FTC_Cache)ftccache; 89 90 91 FTC_Family_Init( FTC_FAMILY( family ), cache ); 92 family->attrs = query->attrs; 93 return 0; 94 } 95 96 97 FT_CALLBACK_DEF( FT_UInt ) 98 ftc_basic_family_get_count( FTC_Family ftcfamily, 99 FTC_Manager manager ) 100 { 101 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 102 FT_Error error; 103 FT_Face face; 104 FT_UInt result = 0; 105 106 107 error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id, 108 &face ); 109 110 if ( error || !face ) 111 return result; 112 113 #ifdef FT_DEBUG_LEVEL_TRACE 114 if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs ) 115 { 116 FT_TRACE1(( "ftc_basic_family_get_count:" 117 " the number of glyphs in this face is %ld,\n", 118 face->num_glyphs )); 119 FT_TRACE1(( " " 120 " which is too much and thus truncated\n" )); 121 } 122 #endif 123 124 result = (FT_UInt)face->num_glyphs; 125 126 return result; 127 } 128 129 130 FT_CALLBACK_DEF( FT_Error ) 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( face, 148 gindex, 149 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 ) 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, gindex, family->attrs.load_flags ); 180 if ( !error ) 181 { 182 if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || 183 face->glyph->format == FT_GLYPH_FORMAT_OUTLINE || 184 face->glyph->format == FT_GLYPH_FORMAT_SVG ) 185 { 186 /* ok, copy it */ 187 FT_Glyph glyph; 188 189 190 error = FT_Get_Glyph( face->glyph, &glyph ); 191 if ( !error ) 192 { 193 *aglyph = glyph; 194 goto Exit; 195 } 196 } 197 else 198 error = FT_THROW( Invalid_Argument ); 199 } 200 } 201 202 Exit: 203 return error; 204 } 205 206 207 FT_CALLBACK_DEF( FT_Bool ) 208 ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode, 209 FT_Pointer ftcface_id, 210 FTC_Cache cache, 211 FT_Bool* list_changed ) 212 { 213 FTC_GNode gnode = (FTC_GNode)ftcgnode; 214 FTC_FaceID face_id = (FTC_FaceID)ftcface_id; 215 FTC_BasicFamily family = (FTC_BasicFamily)gnode->family; 216 FT_Bool result; 217 218 219 if ( list_changed ) 220 *list_changed = FALSE; 221 result = FT_BOOL( family->attrs.scaler.face_id == face_id ); 222 if ( result ) 223 { 224 /* we must call this function to avoid this node from appearing 225 * in later lookups with the same face_id! 226 */ 227 FTC_GNode_UnselectFamily( gnode, cache ); 228 } 229 return result; 230 } 231 232 233 /* 234 * 235 * basic image cache 236 * 237 */ 238 239 static 240 const FTC_IFamilyClassRec ftc_basic_image_family_class = 241 { 242 { 243 sizeof ( FTC_BasicFamilyRec ), 244 245 ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */ 246 ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ 247 NULL /* FTC_MruNode_DoneFunc node_done */ 248 }, 249 250 ftc_basic_family_load_glyph /* FTC_IFamily_LoadGlyphFunc family_load_glyph */ 251 }; 252 253 254 static 255 const FTC_GCacheClassRec ftc_basic_image_cache_class = 256 { 257 { 258 ftc_inode_new, /* FTC_Node_NewFunc node_new */ 259 ftc_inode_weight, /* FTC_Node_WeightFunc node_weight */ 260 ftc_gnode_compare, /* FTC_Node_CompareFunc node_compare */ 261 ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ 262 ftc_inode_free, /* FTC_Node_FreeFunc node_free */ 263 264 sizeof ( FTC_GCacheRec ), 265 ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */ 266 ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */ 267 }, 268 269 (FTC_MruListClass)&ftc_basic_image_family_class 270 }; 271 272 273 /* documentation is in ftcache.h */ 274 275 FT_EXPORT_DEF( FT_Error ) 276 FTC_ImageCache_New( FTC_Manager manager, 277 FTC_ImageCache *acache ) 278 { 279 return FTC_GCache_New( manager, &ftc_basic_image_cache_class, 280 (FTC_GCache*)acache ); 281 } 282 283 284 /* documentation is in ftcache.h */ 285 286 FT_EXPORT_DEF( FT_Error ) 287 FTC_ImageCache_Lookup( FTC_ImageCache cache, 288 FTC_ImageType type, 289 FT_UInt gindex, 290 FT_Glyph *aglyph, 291 FTC_Node *anode ) 292 { 293 FT_Error error; 294 FTC_BasicQueryRec query; 295 FTC_Node node = NULL; /* make compiler happy */ 296 FT_Offset hash; 297 298 299 /* other argument checks delayed to `FTC_Cache_Lookup' */ 300 if ( !aglyph ) 301 return FT_THROW( Invalid_Argument ); 302 303 *aglyph = NULL; 304 if ( anode ) 305 *anode = NULL; 306 307 query.attrs.scaler.face_id = type->face_id; 308 query.attrs.scaler.width = type->width; 309 query.attrs.scaler.height = type->height; 310 query.attrs.load_flags = type->flags; 311 312 query.attrs.scaler.pixel = 1; 313 query.attrs.scaler.x_res = 0; /* make compilers happy */ 314 query.attrs.scaler.y_res = 0; 315 316 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; 317 318 #ifdef FTC_INLINE /* inlining is about 50% faster! */ 319 FTC_GCACHE_LOOKUP_CMP( cache, 320 ftc_basic_family_compare, 321 ftc_gnode_compare, 322 hash, gindex, 323 &query, 324 node, 325 error ); 326 #else 327 error = FTC_GCache_Lookup( FTC_GCACHE( cache ), 328 hash, gindex, 329 FTC_GQUERY( &query ), 330 &node ); 331 #endif 332 if ( !error ) 333 { 334 *aglyph = FTC_INODE( node )->glyph; 335 336 if ( anode ) 337 { 338 *anode = node; 339 node->ref_count++; 340 } 341 } 342 343 return error; 344 } 345 346 347 /* documentation is in ftcache.h */ 348 349 FT_EXPORT_DEF( FT_Error ) 350 FTC_ImageCache_LookupScaler( FTC_ImageCache cache, 351 FTC_Scaler scaler, 352 FT_ULong load_flags, 353 FT_UInt gindex, 354 FT_Glyph *aglyph, 355 FTC_Node *anode ) 356 { 357 FT_Error error; 358 FTC_BasicQueryRec query; 359 FTC_Node node = NULL; /* make compiler happy */ 360 FT_Offset hash; 361 362 363 /* other argument checks delayed to `FTC_Cache_Lookup' */ 364 if ( !aglyph || !scaler ) 365 return FT_THROW( Invalid_Argument ); 366 367 *aglyph = NULL; 368 if ( anode ) 369 *anode = NULL; 370 371 /* 372 * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32', 373 * but public `FT_Face->face_flags' is of type `FT_Long'. 374 * 375 * On long > int systems, higher bits of load_flags cannot be handled. 376 */ 377 #if FT_ULONG_MAX > 0xFFFFFFFFUL 378 if ( load_flags > 0xFFFFFFFFUL ) 379 FT_TRACE1(( "FTC_ImageCache_LookupScaler:" 380 " higher bits in load_flags 0x%lx are dropped\n", 381 load_flags & ~0xFFFFFFFFUL )); 382 #endif 383 384 query.attrs.scaler = scaler[0]; 385 query.attrs.load_flags = (FT_Int32)load_flags; 386 387 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; 388 389 FTC_GCACHE_LOOKUP_CMP( cache, 390 ftc_basic_family_compare, 391 ftc_gnode_compare, 392 hash, gindex, 393 &query, 394 node, 395 error ); 396 if ( !error ) 397 { 398 *aglyph = FTC_INODE( node )->glyph; 399 400 if ( anode ) 401 { 402 *anode = node; 403 node->ref_count++; 404 } 405 } 406 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, /* FTC_MruNode_CompareFunc node_compare */ 423 ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ 424 NULL /* FTC_MruNode_DoneFunc node_done */ 425 }, 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, /* FTC_Node_NewFunc node_new */ 437 ftc_snode_weight, /* FTC_Node_WeightFunc node_weight */ 438 ftc_snode_compare, /* FTC_Node_CompareFunc node_compare */ 439 ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc node_remove_faceid */ 440 ftc_snode_free, /* FTC_Node_FreeFunc node_free */ 441 442 sizeof ( FTC_GCacheRec ), 443 ftc_gcache_init, /* FTC_Cache_InitFunc cache_init */ 444 ftc_gcache_done /* FTC_Cache_DoneFunc cache_done */ 445 }, 446 447 (FTC_MruListClass)&ftc_basic_sbit_family_class 448 }; 449 450 451 /* documentation is in ftcache.h */ 452 453 FT_EXPORT_DEF( FT_Error ) 454 FTC_SBitCache_New( FTC_Manager manager, 455 FTC_SBitCache *acache ) 456 { 457 return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class, 458 (FTC_GCache*)acache ); 459 } 460 461 462 /* documentation is in ftcache.h */ 463 464 FT_EXPORT_DEF( FT_Error ) 465 FTC_SBitCache_Lookup( FTC_SBitCache cache, 466 FTC_ImageType type, 467 FT_UInt gindex, 468 FTC_SBit *ansbit, 469 FTC_Node *anode ) 470 { 471 FT_Error error; 472 FTC_BasicQueryRec query; 473 FTC_Node node = NULL; /* make compiler happy */ 474 FT_Offset hash; 475 476 477 /* other argument checks delayed to `FTC_Cache_Lookup' */ 478 if ( !ansbit ) 479 return FT_THROW( Invalid_Argument ); 480 481 *ansbit = NULL; 482 if ( anode ) 483 *anode = NULL; 484 485 query.attrs.scaler.face_id = type->face_id; 486 query.attrs.scaler.width = type->width; 487 query.attrs.scaler.height = type->height; 488 query.attrs.load_flags = type->flags; 489 490 query.attrs.scaler.pixel = 1; 491 query.attrs.scaler.x_res = 0; /* make compilers happy */ 492 query.attrs.scaler.y_res = 0; 493 494 /* beware, the hash must be the same for all glyph ranges! */ 495 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + 496 gindex / FTC_SBIT_ITEMS_PER_NODE; 497 498 #ifdef FTC_INLINE /* inlining is about 50% faster! */ 499 FTC_GCACHE_LOOKUP_CMP( cache, 500 ftc_basic_family_compare, 501 ftc_snode_compare, 502 hash, gindex, 503 &query, 504 node, 505 error ); 506 #else 507 error = FTC_GCache_Lookup( FTC_GCACHE( cache ), 508 hash, 509 gindex, 510 FTC_GQUERY( &query ), 511 &node ); 512 #endif 513 if ( error ) 514 goto Exit; 515 516 *ansbit = FTC_SNODE( node )->sbits + 517 ( gindex - FTC_GNODE( node )->gindex ); 518 519 if ( anode ) 520 { 521 *anode = node; 522 node->ref_count++; 523 } 524 525 Exit: 526 return error; 527 } 528 529 530 /* documentation is in ftcache.h */ 531 532 FT_EXPORT_DEF( FT_Error ) 533 FTC_SBitCache_LookupScaler( FTC_SBitCache cache, 534 FTC_Scaler scaler, 535 FT_ULong load_flags, 536 FT_UInt gindex, 537 FTC_SBit *ansbit, 538 FTC_Node *anode ) 539 { 540 FT_Error error; 541 FTC_BasicQueryRec query; 542 FTC_Node node = NULL; /* make compiler happy */ 543 FT_Offset hash; 544 545 546 /* other argument checks delayed to `FTC_Cache_Lookup' */ 547 if ( !ansbit || !scaler ) 548 return FT_THROW( Invalid_Argument ); 549 550 *ansbit = NULL; 551 if ( anode ) 552 *anode = NULL; 553 554 /* 555 * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32', 556 * but public `FT_Face->face_flags' is of type `FT_Long'. 557 * 558 * On long > int systems, higher bits of load_flags cannot be handled. 559 */ 560 #if FT_ULONG_MAX > 0xFFFFFFFFUL 561 if ( load_flags > 0xFFFFFFFFUL ) 562 FT_TRACE1(( "FTC_ImageCache_LookupScaler:" 563 " higher bits in load_flags 0x%lx are dropped\n", 564 load_flags & ~0xFFFFFFFFUL )); 565 #endif 566 567 query.attrs.scaler = scaler[0]; 568 query.attrs.load_flags = (FT_Int32)load_flags; 569 570 /* beware, the hash must be the same for all glyph ranges! */ 571 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + 572 gindex / FTC_SBIT_ITEMS_PER_NODE; 573 574 FTC_GCACHE_LOOKUP_CMP( cache, 575 ftc_basic_family_compare, 576 ftc_snode_compare, 577 hash, gindex, 578 &query, 579 node, 580 error ); 581 if ( error ) 582 goto Exit; 583 584 *ansbit = FTC_SNODE( node )->sbits + 585 ( gindex - FTC_GNODE( node )->gindex ); 586 587 if ( anode ) 588 { 589 *anode = node; 590 node->ref_count++; 591 } 592 593 Exit: 594 return error; 595 } 596 597 598 /* END */