/src/freetype/src/cache/ftcmanag.c
C | 743 lines | 477 code | 203 blank | 63 comment | 69 complexity | 4a46c24e598c9aea5976cc2de6740743 MD5 | raw file
1/***************************************************************************/ 2/* */ 3/* ftcmanag.c */ 4/* */ 5/* FreeType Cache Manager (body). */ 6/* */ 7/* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 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_CACHE_H 21#include "ftcmanag.h" 22#include FT_INTERNAL_OBJECTS_H 23#include FT_INTERNAL_DEBUG_H 24#include FT_SIZES_H 25 26#include "ftccback.h" 27#include "ftcerror.h" 28 29#ifdef FT_CONFIG_OPTION_PIC 30#error "cache system does not support PIC yet" 31#endif 32 33 34#undef FT_COMPONENT 35#define FT_COMPONENT trace_cache 36 37#define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data ) 38 39 40 static FT_Error 41 ftc_scaler_lookup_size( FTC_Manager manager, 42 FTC_Scaler scaler, 43 FT_Size *asize ) 44 { 45 FT_Face face; 46 FT_Size size = NULL; 47 FT_Error error; 48 49 50 error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); 51 if ( error ) 52 goto Exit; 53 54 error = FT_New_Size( face, &size ); 55 if ( error ) 56 goto Exit; 57 58 FT_Activate_Size( size ); 59 60 if ( scaler->pixel ) 61 error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); 62 else 63 error = FT_Set_Char_Size( face, scaler->width, scaler->height, 64 scaler->x_res, scaler->y_res ); 65 if ( error ) 66 { 67 FT_Done_Size( size ); 68 size = NULL; 69 } 70 71 Exit: 72 *asize = size; 73 return error; 74 } 75 76 77 typedef struct FTC_SizeNodeRec_ 78 { 79 FTC_MruNodeRec node; 80 FT_Size size; 81 FTC_ScalerRec scaler; 82 83 } FTC_SizeNodeRec, *FTC_SizeNode; 84 85#define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) ) 86 87 88 FT_CALLBACK_DEF( void ) 89 ftc_size_node_done( FTC_MruNode ftcnode, 90 FT_Pointer data ) 91 { 92 FTC_SizeNode node = (FTC_SizeNode)ftcnode; 93 FT_Size size = node->size; 94 FT_UNUSED( data ); 95 96 97 if ( size ) 98 FT_Done_Size( size ); 99 } 100 101 102 FT_CALLBACK_DEF( FT_Bool ) 103 ftc_size_node_compare( FTC_MruNode ftcnode, 104 FT_Pointer ftcscaler ) 105 { 106 FTC_SizeNode node = (FTC_SizeNode)ftcnode; 107 FTC_Scaler scaler = (FTC_Scaler)ftcscaler; 108 FTC_Scaler scaler0 = &node->scaler; 109 110 111 if ( FTC_SCALER_COMPARE( scaler0, scaler ) ) 112 { 113 FT_Activate_Size( node->size ); 114 return 1; 115 } 116 return 0; 117 } 118 119 120 FT_CALLBACK_DEF( FT_Error ) 121 ftc_size_node_init( FTC_MruNode ftcnode, 122 FT_Pointer ftcscaler, 123 FT_Pointer ftcmanager ) 124 { 125 FTC_SizeNode node = (FTC_SizeNode)ftcnode; 126 FTC_Scaler scaler = (FTC_Scaler)ftcscaler; 127 FTC_Manager manager = (FTC_Manager)ftcmanager; 128 129 130 node->scaler = scaler[0]; 131 132 return ftc_scaler_lookup_size( manager, scaler, &node->size ); 133 } 134 135 136 FT_CALLBACK_DEF( FT_Error ) 137 ftc_size_node_reset( FTC_MruNode ftcnode, 138 FT_Pointer ftcscaler, 139 FT_Pointer ftcmanager ) 140 { 141 FTC_SizeNode node = (FTC_SizeNode)ftcnode; 142 FTC_Scaler scaler = (FTC_Scaler)ftcscaler; 143 FTC_Manager manager = (FTC_Manager)ftcmanager; 144 145 146 FT_Done_Size( node->size ); 147 148 node->scaler = scaler[0]; 149 150 return ftc_scaler_lookup_size( manager, scaler, &node->size ); 151 } 152 153 154 FT_CALLBACK_TABLE_DEF 155 const FTC_MruListClassRec ftc_size_list_class = 156 { 157 sizeof ( FTC_SizeNodeRec ), 158 ftc_size_node_compare, 159 ftc_size_node_init, 160 ftc_size_node_reset, 161 ftc_size_node_done 162 }; 163 164 165 /* helper function used by ftc_face_node_done */ 166 static FT_Bool 167 ftc_size_node_compare_faceid( FTC_MruNode ftcnode, 168 FT_Pointer ftcface_id ) 169 { 170 FTC_SizeNode node = (FTC_SizeNode)ftcnode; 171 FTC_FaceID face_id = (FTC_FaceID)ftcface_id; 172 173 174 return FT_BOOL( node->scaler.face_id == face_id ); 175 } 176 177 178 /* documentation is in ftcache.h */ 179 180 FT_EXPORT_DEF( FT_Error ) 181 FTC_Manager_LookupSize( FTC_Manager manager, 182 FTC_Scaler scaler, 183 FT_Size *asize ) 184 { 185 FT_Error error; 186 FTC_MruNode mrunode; 187 188 189 if ( asize == NULL ) 190 return FTC_Err_Invalid_Argument; 191 192 *asize = NULL; 193 194 if ( !manager ) 195 return FTC_Err_Invalid_Cache_Handle; 196 197#ifdef FTC_INLINE 198 199 FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare, 200 mrunode, error ); 201 202#else 203 error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode ); 204#endif 205 206 if ( !error ) 207 *asize = FTC_SIZE_NODE( mrunode )->size; 208 209 return error; 210 } 211 212 213 /*************************************************************************/ 214 /*************************************************************************/ 215 /***** *****/ 216 /***** FACE MRU IMPLEMENTATION *****/ 217 /***** *****/ 218 /*************************************************************************/ 219 /*************************************************************************/ 220 221 typedef struct FTC_FaceNodeRec_ 222 { 223 FTC_MruNodeRec node; 224 FTC_FaceID face_id; 225 FT_Face face; 226 227 } FTC_FaceNodeRec, *FTC_FaceNode; 228 229#define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) ) 230 231 232 FT_CALLBACK_DEF( FT_Error ) 233 ftc_face_node_init( FTC_MruNode ftcnode, 234 FT_Pointer ftcface_id, 235 FT_Pointer ftcmanager ) 236 { 237 FTC_FaceNode node = (FTC_FaceNode)ftcnode; 238 FTC_FaceID face_id = (FTC_FaceID)ftcface_id; 239 FTC_Manager manager = (FTC_Manager)ftcmanager; 240 FT_Error error; 241 242 243 node->face_id = face_id; 244 245 error = manager->request_face( face_id, 246 manager->library, 247 manager->request_data, 248 &node->face ); 249 if ( !error ) 250 { 251 /* destroy initial size object; it will be re-created later */ 252 if ( node->face->size ) 253 FT_Done_Size( node->face->size ); 254 } 255 256 return error; 257 } 258 259 260 FT_CALLBACK_DEF( void ) 261 ftc_face_node_done( FTC_MruNode ftcnode, 262 FT_Pointer ftcmanager ) 263 { 264 FTC_FaceNode node = (FTC_FaceNode)ftcnode; 265 FTC_Manager manager = (FTC_Manager)ftcmanager; 266 267 268 /* we must begin by removing all scalers for the target face */ 269 /* from the manager's list */ 270 FTC_MruList_RemoveSelection( &manager->sizes, 271 ftc_size_node_compare_faceid, 272 node->face_id ); 273 274 /* all right, we can discard the face now */ 275 FT_Done_Face( node->face ); 276 node->face = NULL; 277 node->face_id = NULL; 278 } 279 280 281 FT_CALLBACK_DEF( FT_Bool ) 282 ftc_face_node_compare( FTC_MruNode ftcnode, 283 FT_Pointer ftcface_id ) 284 { 285 FTC_FaceNode node = (FTC_FaceNode)ftcnode; 286 FTC_FaceID face_id = (FTC_FaceID)ftcface_id; 287 288 289 return FT_BOOL( node->face_id == face_id ); 290 } 291 292 293 FT_CALLBACK_TABLE_DEF 294 const FTC_MruListClassRec ftc_face_list_class = 295 { 296 sizeof ( FTC_FaceNodeRec), 297 298 ftc_face_node_compare, 299 ftc_face_node_init, 300 0, /* FTC_MruNode_ResetFunc */ 301 ftc_face_node_done 302 }; 303 304 305 /* documentation is in ftcache.h */ 306 307 FT_EXPORT_DEF( FT_Error ) 308 FTC_Manager_LookupFace( FTC_Manager manager, 309 FTC_FaceID face_id, 310 FT_Face *aface ) 311 { 312 FT_Error error; 313 FTC_MruNode mrunode; 314 315 316 if ( aface == NULL ) 317 return FTC_Err_Invalid_Argument; 318 319 *aface = NULL; 320 321 if ( !manager ) 322 return FTC_Err_Invalid_Cache_Handle; 323 324 /* we break encapsulation for the sake of speed */ 325#ifdef FTC_INLINE 326 327 FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare, 328 mrunode, error ); 329 330#else 331 error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode ); 332#endif 333 334 if ( !error ) 335 *aface = FTC_FACE_NODE( mrunode )->face; 336 337 return error; 338 } 339 340 341 /*************************************************************************/ 342 /*************************************************************************/ 343 /***** *****/ 344 /***** CACHE MANAGER ROUTINES *****/ 345 /***** *****/ 346 /*************************************************************************/ 347 /*************************************************************************/ 348 349 350 /* documentation is in ftcache.h */ 351 352 FT_EXPORT_DEF( FT_Error ) 353 FTC_Manager_New( FT_Library library, 354 FT_UInt max_faces, 355 FT_UInt max_sizes, 356 FT_ULong max_bytes, 357 FTC_Face_Requester requester, 358 FT_Pointer req_data, 359 FTC_Manager *amanager ) 360 { 361 FT_Error error; 362 FT_Memory memory; 363 FTC_Manager manager = 0; 364 365 366 if ( !library ) 367 return FTC_Err_Invalid_Library_Handle; 368 369 memory = library->memory; 370 371 if ( FT_NEW( manager ) ) 372 goto Exit; 373 374 if ( max_faces == 0 ) 375 max_faces = FTC_MAX_FACES_DEFAULT; 376 377 if ( max_sizes == 0 ) 378 max_sizes = FTC_MAX_SIZES_DEFAULT; 379 380 if ( max_bytes == 0 ) 381 max_bytes = FTC_MAX_BYTES_DEFAULT; 382 383 manager->library = library; 384 manager->memory = memory; 385 manager->max_weight = max_bytes; 386 387 manager->request_face = requester; 388 manager->request_data = req_data; 389 390 FTC_MruList_Init( &manager->faces, 391 &ftc_face_list_class, 392 max_faces, 393 manager, 394 memory ); 395 396 FTC_MruList_Init( &manager->sizes, 397 &ftc_size_list_class, 398 max_sizes, 399 manager, 400 memory ); 401 402 *amanager = manager; 403 404 Exit: 405 return error; 406 } 407 408 409 /* documentation is in ftcache.h */ 410 411 FT_EXPORT_DEF( void ) 412 FTC_Manager_Done( FTC_Manager manager ) 413 { 414 FT_Memory memory; 415 FT_UInt idx; 416 417 418 if ( !manager || !manager->library ) 419 return; 420 421 memory = manager->memory; 422 423 /* now discard all caches */ 424 for (idx = manager->num_caches; idx-- > 0; ) 425 { 426 FTC_Cache cache = manager->caches[idx]; 427 428 429 if ( cache ) 430 { 431 cache->clazz.cache_done( cache ); 432 FT_FREE( cache ); 433 manager->caches[idx] = NULL; 434 } 435 } 436 manager->num_caches = 0; 437 438 /* discard faces and sizes */ 439 FTC_MruList_Done( &manager->sizes ); 440 FTC_MruList_Done( &manager->faces ); 441 442 manager->library = NULL; 443 manager->memory = NULL; 444 445 FT_FREE( manager ); 446 } 447 448 449 /* documentation is in ftcache.h */ 450 451 FT_EXPORT_DEF( void ) 452 FTC_Manager_Reset( FTC_Manager manager ) 453 { 454 if ( manager ) 455 { 456 FTC_MruList_Reset( &manager->sizes ); 457 FTC_MruList_Reset( &manager->faces ); 458 } 459 /* XXX: FIXME: flush the caches? */ 460 } 461 462 463#ifdef FT_DEBUG_ERROR 464 465 static void 466 FTC_Manager_Check( FTC_Manager manager ) 467 { 468 FTC_Node node, first; 469 470 471 first = manager->nodes_list; 472 473 /* check node weights */ 474 if ( first ) 475 { 476 FT_ULong weight = 0; 477 478 479 node = first; 480 481 do 482 { 483 FTC_Cache cache = manager->caches[node->cache_index]; 484 485 486 if ( (FT_UInt)node->cache_index >= manager->num_caches ) 487 FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n", 488 node->cache_index )); 489 else 490 weight += cache->clazz.node_weight( node, cache ); 491 492 node = FTC_NODE__NEXT( node ); 493 494 } while ( node != first ); 495 496 if ( weight != manager->cur_weight ) 497 FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n", 498 manager->cur_weight, weight )); 499 } 500 501 /* check circular list */ 502 if ( first ) 503 { 504 FT_UFast count = 0; 505 506 507 node = first; 508 do 509 { 510 count++; 511 node = FTC_NODE__NEXT( node ); 512 513 } while ( node != first ); 514 515 if ( count != manager->num_nodes ) 516 FT_TRACE0(( "FTC_Manager_Check:" 517 " invalid cache node count %d instead of %d\n", 518 manager->num_nodes, count )); 519 } 520 } 521 522#endif /* FT_DEBUG_ERROR */ 523 524 525 /* `Compress' the manager's data, i.e., get rid of old cache nodes */ 526 /* that are not referenced anymore in order to limit the total */ 527 /* memory used by the cache. */ 528 529 /* documentation is in ftcmanag.h */ 530 531 FT_LOCAL_DEF( void ) 532 FTC_Manager_Compress( FTC_Manager manager ) 533 { 534 FTC_Node node, first; 535 536 537 if ( !manager ) 538 return; 539 540 first = manager->nodes_list; 541 542#ifdef FT_DEBUG_ERROR 543 FTC_Manager_Check( manager ); 544 545 FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n", 546 manager->cur_weight, manager->max_weight, 547 manager->num_nodes )); 548#endif 549 550 if ( manager->cur_weight < manager->max_weight || first == NULL ) 551 return; 552 553 /* go to last node -- it's a circular list */ 554 node = FTC_NODE__PREV( first ); 555 do 556 { 557 FTC_Node prev; 558 559 560 prev = ( node == first ) ? NULL : FTC_NODE__PREV( node ); 561 562 if ( node->ref_count <= 0 ) 563 ftc_node_destroy( node, manager ); 564 565 node = prev; 566 567 } while ( node && manager->cur_weight > manager->max_weight ); 568 } 569 570 571 /* documentation is in ftcmanag.h */ 572 573 FT_LOCAL_DEF( FT_Error ) 574 FTC_Manager_RegisterCache( FTC_Manager manager, 575 FTC_CacheClass clazz, 576 FTC_Cache *acache ) 577 { 578 FT_Error error = FTC_Err_Invalid_Argument; 579 FTC_Cache cache = NULL; 580 581 582 if ( manager && clazz && acache ) 583 { 584 FT_Memory memory = manager->memory; 585 586 587 if ( manager->num_caches >= FTC_MAX_CACHES ) 588 { 589 error = FTC_Err_Too_Many_Caches; 590 FT_ERROR(( "FTC_Manager_RegisterCache:" 591 " too many registered caches\n" )); 592 goto Exit; 593 } 594 595 if ( !FT_ALLOC( cache, clazz->cache_size ) ) 596 { 597 cache->manager = manager; 598 cache->memory = memory; 599 cache->clazz = clazz[0]; 600 cache->org_class = clazz; 601 602 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */ 603 /* IF IT IS NOT SET CORRECTLY */ 604 cache->index = manager->num_caches; 605 606 error = clazz->cache_init( cache ); 607 if ( error ) 608 { 609 clazz->cache_done( cache ); 610 FT_FREE( cache ); 611 goto Exit; 612 } 613 614 manager->caches[manager->num_caches++] = cache; 615 } 616 } 617 618 Exit: 619 if ( acache ) 620 *acache = cache; 621 return error; 622 } 623 624 625 FT_LOCAL_DEF( FT_UInt ) 626 FTC_Manager_FlushN( FTC_Manager manager, 627 FT_UInt count ) 628 { 629 FTC_Node first = manager->nodes_list; 630 FTC_Node node; 631 FT_UInt result; 632 633 634 /* try to remove `count' nodes from the list */ 635 if ( first == NULL ) /* empty list! */ 636 return 0; 637 638 /* go to last node - it's a circular list */ 639 node = FTC_NODE__PREV(first); 640 for ( result = 0; result < count; ) 641 { 642 FTC_Node prev = FTC_NODE__PREV( node ); 643 644 645 /* don't touch locked nodes */ 646 if ( node->ref_count <= 0 ) 647 { 648 ftc_node_destroy( node, manager ); 649 result++; 650 } 651 652 if ( node == first ) 653 break; 654 655 node = prev; 656 } 657 return result; 658 } 659 660 661 /* documentation is in ftcache.h */ 662 663 FT_EXPORT_DEF( void ) 664 FTC_Manager_RemoveFaceID( FTC_Manager manager, 665 FTC_FaceID face_id ) 666 { 667 FT_UInt nn; 668 669 /* this will remove all FTC_SizeNode that correspond to 670 * the face_id as well 671 */ 672 FTC_MruList_RemoveSelection( &manager->faces, 673 ftc_face_node_compare, 674 face_id ); 675 676 for ( nn = 0; nn < manager->num_caches; nn++ ) 677 FTC_Cache_RemoveFaceID( manager->caches[nn], face_id ); 678 } 679 680 681 /* documentation is in ftcache.h */ 682 683 FT_EXPORT_DEF( void ) 684 FTC_Node_Unref( FTC_Node node, 685 FTC_Manager manager ) 686 { 687 if ( node && (FT_UInt)node->cache_index < manager->num_caches ) 688 node->ref_count--; 689 } 690 691 692#ifdef FT_CONFIG_OPTION_OLD_INTERNALS 693 694 FT_EXPORT_DEF( FT_Error ) 695 FTC_Manager_Lookup_Face( FTC_Manager manager, 696 FTC_FaceID face_id, 697 FT_Face *aface ) 698 { 699 return FTC_Manager_LookupFace( manager, face_id, aface ); 700 } 701 702 703 FT_EXPORT( FT_Error ) 704 FTC_Manager_Lookup_Size( FTC_Manager manager, 705 FTC_Font font, 706 FT_Face *aface, 707 FT_Size *asize ) 708 { 709 FTC_ScalerRec scaler; 710 FT_Error error; 711 FT_Size size; 712 FT_Face face; 713 714 715 scaler.face_id = font->face_id; 716 scaler.width = font->pix_width; 717 scaler.height = font->pix_height; 718 scaler.pixel = TRUE; 719 scaler.x_res = 0; 720 scaler.y_res = 0; 721 722 error = FTC_Manager_LookupSize( manager, &scaler, &size ); 723 if ( error ) 724 { 725 face = NULL; 726 size = NULL; 727 } 728 else 729 face = size->face; 730 731 if ( aface ) 732 *aface = face; 733 734 if ( asize ) 735 *asize = size; 736 737 return error; 738 } 739 740#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ 741 742 743/* END */