1 /***************************************************************************/ 2 /* */ 3 /* ftcbasic.c */ 4 /* */ 5 /* The FreeType basic cache interface (body). */ 6 /* */ 7 /* Copyright 2003-2007, 2009-2011, 2013, 2014 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 trace_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 { 114 FT_TRACE1(( "ftc_basic_family_get_count: too large number of glyphs " )); 115 FT_TRACE1(( "in this face, truncated\n", face->num_glyphs )); 116 } 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( face, gindex, 143 family->attrs.load_flags | FT_LOAD_RENDER ); 144 if ( !error ) 145 *aface = face; 146 } 147 148 return error; 149 } 150 151 152 FT_CALLBACK_DEF( FT_Error ) ftc_basic_family_load_glyph(FTC_Family ftcfamily,FT_UInt gindex,FTC_Cache cache,FT_Glyph * aglyph)153 ftc_basic_family_load_glyph( FTC_Family ftcfamily, 154 FT_UInt gindex, 155 FTC_Cache cache, 156 FT_Glyph *aglyph ) 157 { 158 FTC_BasicFamily family = (FTC_BasicFamily)ftcfamily; 159 FT_Error error; 160 FTC_Scaler scaler = &family->attrs.scaler; 161 FT_Face face; 162 FT_Size size; 163 164 165 /* we will now load the glyph image */ 166 error = FTC_Manager_LookupSize( cache->manager, 167 scaler, 168 &size ); 169 if ( !error ) 170 { 171 face = size->face; 172 173 error = FT_Load_Glyph( face, gindex, family->attrs.load_flags ); 174 if ( !error ) 175 { 176 if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || 177 face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) 178 { 179 /* ok, copy it */ 180 FT_Glyph glyph; 181 182 183 error = FT_Get_Glyph( face->glyph, &glyph ); 184 if ( !error ) 185 { 186 *aglyph = glyph; 187 goto Exit; 188 } 189 } 190 else 191 error = FT_THROW( Invalid_Argument ); 192 } 193 } 194 195 Exit: 196 return error; 197 } 198 199 200 FT_CALLBACK_DEF( FT_Bool ) ftc_basic_gnode_compare_faceid(FTC_Node ftcgnode,FT_Pointer ftcface_id,FTC_Cache cache,FT_Bool * list_changed)201 ftc_basic_gnode_compare_faceid( FTC_Node ftcgnode, 202 FT_Pointer ftcface_id, 203 FTC_Cache cache, 204 FT_Bool* list_changed ) 205 { 206 FTC_GNode gnode = (FTC_GNode)ftcgnode; 207 FTC_FaceID face_id = (FTC_FaceID)ftcface_id; 208 FTC_BasicFamily family = (FTC_BasicFamily)gnode->family; 209 FT_Bool result; 210 211 212 if ( list_changed ) 213 *list_changed = FALSE; 214 result = FT_BOOL( family->attrs.scaler.face_id == face_id ); 215 if ( result ) 216 { 217 /* we must call this function to avoid this node from appearing 218 * in later lookups with the same face_id! 219 */ 220 FTC_GNode_UnselectFamily( gnode, cache ); 221 } 222 return result; 223 } 224 225 226 /* 227 * 228 * basic image cache 229 * 230 */ 231 232 static 233 const FTC_IFamilyClassRec ftc_basic_image_family_class = 234 { 235 { 236 sizeof ( FTC_BasicFamilyRec ), 237 ftc_basic_family_compare, 238 ftc_basic_family_init, 239 0, /* FTC_MruNode_ResetFunc */ 240 0 /* FTC_MruNode_DoneFunc */ 241 }, 242 ftc_basic_family_load_glyph 243 }; 244 245 246 static 247 const FTC_GCacheClassRec ftc_basic_image_cache_class = 248 { 249 { 250 ftc_inode_new, 251 ftc_inode_weight, 252 ftc_gnode_compare, 253 ftc_basic_gnode_compare_faceid, 254 ftc_inode_free, 255 256 sizeof ( FTC_GCacheRec ), 257 ftc_gcache_init, 258 ftc_gcache_done 259 }, 260 (FTC_MruListClass)&ftc_basic_image_family_class 261 }; 262 263 264 /* documentation is in ftcache.h */ 265 266 FT_EXPORT_DEF( FT_Error ) FTC_ImageCache_New(FTC_Manager manager,FTC_ImageCache * acache)267 FTC_ImageCache_New( FTC_Manager manager, 268 FTC_ImageCache *acache ) 269 { 270 return FTC_GCache_New( manager, &ftc_basic_image_cache_class, 271 (FTC_GCache*)acache ); 272 } 273 274 275 /* documentation is in ftcache.h */ 276 277 FT_EXPORT_DEF( FT_Error ) FTC_ImageCache_Lookup(FTC_ImageCache cache,FTC_ImageType type,FT_UInt gindex,FT_Glyph * aglyph,FTC_Node * anode)278 FTC_ImageCache_Lookup( FTC_ImageCache cache, 279 FTC_ImageType type, 280 FT_UInt gindex, 281 FT_Glyph *aglyph, 282 FTC_Node *anode ) 283 { 284 FTC_BasicQueryRec query; 285 FTC_Node node = 0; /* make compiler happy */ 286 FT_Error error; 287 FT_PtrDist hash; 288 289 290 /* some argument checks are delayed to FTC_Cache_Lookup */ 291 if ( !aglyph ) 292 { 293 error = FT_THROW( Invalid_Argument ); 294 goto Exit; 295 } 296 297 *aglyph = NULL; 298 if ( anode ) 299 *anode = NULL; 300 301 { 302 if ( (FT_ULong)(type->flags - FT_INT_MIN) > FT_UINT_MAX ) 303 { 304 FT_TRACE1(( "FTC_ImageCache_Lookup: higher bits in load_flags" )); 305 FT_TRACE1(( "0x%x are dropped\n", (type->flags & ~((FT_ULong)FT_UINT_MAX)) )); 306 } 307 308 query.attrs.scaler.face_id = type->face_id; 309 query.attrs.scaler.width = type->width; 310 query.attrs.scaler.height = type->height; 311 query.attrs.load_flags = (FT_UInt)type->flags; 312 } 313 314 query.attrs.scaler.pixel = 1; 315 query.attrs.scaler.x_res = 0; /* make compilers happy */ 316 query.attrs.scaler.y_res = 0; 317 318 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; 319 320 #if 1 /* inlining is about 50% faster! */ 321 FTC_GCACHE_LOOKUP_CMP( cache, 322 ftc_basic_family_compare, 323 FTC_GNode_Compare, 324 hash, gindex, 325 &query, 326 node, 327 error ); 328 #else 329 error = FTC_GCache_Lookup( FTC_GCACHE( cache ), 330 hash, gindex, 331 FTC_GQUERY( &query ), 332 &node ); 333 #endif 334 if ( !error ) 335 { 336 *aglyph = FTC_INODE( node )->glyph; 337 338 if ( anode ) 339 { 340 *anode = node; 341 node->ref_count++; 342 } 343 } 344 345 Exit: 346 return error; 347 } 348 349 350 /* documentation is in ftcache.h */ 351 352 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)353 FTC_ImageCache_LookupScaler( FTC_ImageCache cache, 354 FTC_Scaler scaler, 355 FT_ULong load_flags, 356 FT_UInt gindex, 357 FT_Glyph *aglyph, 358 FTC_Node *anode ) 359 { 360 FTC_BasicQueryRec query; 361 FTC_Node node = 0; /* make compiler happy */ 362 FT_Error error; 363 FT_PtrDist hash; 364 365 366 /* some argument checks are delayed to FTC_Cache_Lookup */ 367 if ( !aglyph || !scaler ) 368 { 369 error = FT_THROW( Invalid_Argument ); 370 goto Exit; 371 } 372 373 *aglyph = NULL; 374 if ( anode ) 375 *anode = NULL; 376 377 /* FT_Load_Glyph(), FT_Load_Char() take FT_UInt flags */ 378 if ( load_flags > FT_UINT_MAX ) 379 { 380 FT_TRACE1(( "FTC_ImageCache_LookupScaler: higher bits in load_flags" )); 381 FT_TRACE1(( "0x%x are dropped\n", (load_flags & ~((FT_ULong)FT_UINT_MAX)) )); 382 } 383 384 query.attrs.scaler = scaler[0]; 385 query.attrs.load_flags = (FT_UInt)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 Exit: 408 return error; 409 } 410 411 412 /* 413 * 414 * basic small bitmap cache 415 * 416 */ 417 418 static 419 const FTC_SFamilyClassRec ftc_basic_sbit_family_class = 420 { 421 { 422 sizeof ( FTC_BasicFamilyRec ), 423 ftc_basic_family_compare, 424 ftc_basic_family_init, 425 0, /* FTC_MruNode_ResetFunc */ 426 0 /* FTC_MruNode_DoneFunc */ 427 }, 428 ftc_basic_family_get_count, 429 ftc_basic_family_load_bitmap 430 }; 431 432 433 static 434 const FTC_GCacheClassRec ftc_basic_sbit_cache_class = 435 { 436 { 437 ftc_snode_new, 438 ftc_snode_weight, 439 ftc_snode_compare, 440 ftc_basic_gnode_compare_faceid, 441 ftc_snode_free, 442 443 sizeof ( FTC_GCacheRec ), 444 ftc_gcache_init, 445 ftc_gcache_done 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 ) FTC_SBitCache_New(FTC_Manager manager,FTC_SBitCache * acache)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 ) FTC_SBitCache_Lookup(FTC_SBitCache cache,FTC_ImageType type,FT_UInt gindex,FTC_SBit * ansbit,FTC_Node * anode)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 = 0; /* make compiler happy */ 474 FT_PtrDist hash; 475 476 477 if ( anode ) 478 *anode = NULL; 479 480 /* other argument checks delayed to FTC_Cache_Lookup */ 481 if ( !ansbit ) 482 return FT_THROW( Invalid_Argument ); 483 484 *ansbit = NULL; 485 486 { 487 if ( (FT_ULong)(type->flags - FT_INT_MIN) > FT_UINT_MAX ) 488 { 489 FT_TRACE1(( "FTC_ImageCache_Lookup: higher bits in load_flags" )); 490 FT_TRACE1(( "0x%x are dropped\n", (type->flags & ~((FT_ULong)FT_UINT_MAX)) )); 491 } 492 493 query.attrs.scaler.face_id = type->face_id; 494 query.attrs.scaler.width = type->width; 495 query.attrs.scaler.height = type->height; 496 query.attrs.load_flags = (FT_UInt)type->flags; 497 } 498 499 query.attrs.scaler.pixel = 1; 500 query.attrs.scaler.x_res = 0; /* make compilers happy */ 501 query.attrs.scaler.y_res = 0; 502 503 /* beware, the hash must be the same for all glyph ranges! */ 504 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + 505 gindex / FTC_SBIT_ITEMS_PER_NODE; 506 507 #if 1 /* inlining is about 50% faster! */ 508 FTC_GCACHE_LOOKUP_CMP( cache, 509 ftc_basic_family_compare, 510 FTC_SNode_Compare, 511 hash, gindex, 512 &query, 513 node, 514 error ); 515 #else 516 error = FTC_GCache_Lookup( FTC_GCACHE( cache ), 517 hash, 518 gindex, 519 FTC_GQUERY( &query ), 520 &node ); 521 #endif 522 if ( error ) 523 goto Exit; 524 525 *ansbit = FTC_SNODE( node )->sbits + 526 ( gindex - FTC_GNODE( node )->gindex ); 527 528 if ( anode ) 529 { 530 *anode = node; 531 node->ref_count++; 532 } 533 534 Exit: 535 return error; 536 } 537 538 539 /* documentation is in ftcache.h */ 540 541 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)542 FTC_SBitCache_LookupScaler( FTC_SBitCache cache, 543 FTC_Scaler scaler, 544 FT_ULong load_flags, 545 FT_UInt gindex, 546 FTC_SBit *ansbit, 547 FTC_Node *anode ) 548 { 549 FT_Error error; 550 FTC_BasicQueryRec query; 551 FTC_Node node = 0; /* make compiler happy */ 552 FT_PtrDist hash; 553 554 555 if ( anode ) 556 *anode = NULL; 557 558 /* other argument checks delayed to FTC_Cache_Lookup */ 559 if ( !ansbit || !scaler ) 560 return FT_THROW( Invalid_Argument ); 561 562 *ansbit = NULL; 563 564 /* FT_Load_Glyph(), FT_Load_Char() take FT_UInt flags */ 565 if ( load_flags > FT_UINT_MAX ) 566 { 567 FT_TRACE1(( "FTC_ImageCache_LookupScaler: higher bits in load_flags" )); 568 FT_TRACE1(( "0x%x are dropped\n", (load_flags & ~((FT_ULong)FT_UINT_MAX)) )); 569 } 570 571 query.attrs.scaler = scaler[0]; 572 query.attrs.load_flags = (FT_UInt)load_flags; 573 574 /* beware, the hash must be the same for all glyph ranges! */ 575 hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + 576 gindex / FTC_SBIT_ITEMS_PER_NODE; 577 578 FTC_GCACHE_LOOKUP_CMP( cache, 579 ftc_basic_family_compare, 580 FTC_SNode_Compare, 581 hash, gindex, 582 &query, 583 node, 584 error ); 585 if ( error ) 586 goto Exit; 587 588 *ansbit = FTC_SNODE( node )->sbits + 589 ( gindex - FTC_GNODE( node )->gindex ); 590 591 if ( anode ) 592 { 593 *anode = node; 594 node->ref_count++; 595 } 596 597 Exit: 598 return error; 599 } 600 601 602 /* END */ 603