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