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