00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <ft2build.h>
00020 #include FT_CACHE_H
00021 #include "ftcmanag.h"
00022 #include FT_INTERNAL_OBJECTS_H
00023 #include FT_INTERNAL_DEBUG_H
00024 #include FT_SIZES_H
00025
00026 #include "ftccback.h"
00027 #include "ftcerror.h"
00028
00029 #ifdef FT_CONFIG_OPTION_PIC
00030 #error "cache system does not support PIC yet"
00031 #endif
00032
00033
00034 #undef FT_COMPONENT
00035 #define FT_COMPONENT trace_cache
00036
00037 #define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
00038
00039
00040 static FT_Error
00041 ftc_scaler_lookup_size( FTC_Manager manager,
00042 FTC_Scaler scaler,
00043 FT_Size *asize )
00044 {
00045 FT_Face face;
00046 FT_Size size = NULL;
00047 FT_Error error;
00048
00049
00050 error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
00051 if ( error )
00052 goto Exit;
00053
00054 error = FT_New_Size( face, &size );
00055 if ( error )
00056 goto Exit;
00057
00058 FT_Activate_Size( size );
00059
00060 if ( scaler->pixel )
00061 error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
00062 else
00063 error = FT_Set_Char_Size( face, scaler->width, scaler->height,
00064 scaler->x_res, scaler->y_res );
00065 if ( error )
00066 {
00067 FT_Done_Size( size );
00068 size = NULL;
00069 }
00070
00071 Exit:
00072 *asize = size;
00073 return error;
00074 }
00075
00076
00077 typedef struct FTC_SizeNodeRec_
00078 {
00079 FTC_MruNodeRec node;
00080 FT_Size size;
00081 FTC_ScalerRec scaler;
00082
00083 } FTC_SizeNodeRec, *FTC_SizeNode;
00084
00085 #define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )
00086
00087
00088 FT_CALLBACK_DEF( void )
00089 ftc_size_node_done( FTC_MruNode ftcnode,
00090 FT_Pointer data )
00091 {
00092 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
00093 FT_Size size = node->size;
00094 FT_UNUSED( data );
00095
00096
00097 if ( size )
00098 FT_Done_Size( size );
00099 }
00100
00101
00102 FT_CALLBACK_DEF( FT_Bool )
00103 ftc_size_node_compare( FTC_MruNode ftcnode,
00104 FT_Pointer ftcscaler )
00105 {
00106 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
00107 FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
00108 FTC_Scaler scaler0 = &node->scaler;
00109
00110
00111 if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
00112 {
00113 FT_Activate_Size( node->size );
00114 return 1;
00115 }
00116 return 0;
00117 }
00118
00119
00120 FT_CALLBACK_DEF( FT_Error )
00121 ftc_size_node_init( FTC_MruNode ftcnode,
00122 FT_Pointer ftcscaler,
00123 FT_Pointer ftcmanager )
00124 {
00125 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
00126 FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
00127 FTC_Manager manager = (FTC_Manager)ftcmanager;
00128
00129
00130 node->scaler = scaler[0];
00131
00132 return ftc_scaler_lookup_size( manager, scaler, &node->size );
00133 }
00134
00135
00136 FT_CALLBACK_DEF( FT_Error )
00137 ftc_size_node_reset( FTC_MruNode ftcnode,
00138 FT_Pointer ftcscaler,
00139 FT_Pointer ftcmanager )
00140 {
00141 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
00142 FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
00143 FTC_Manager manager = (FTC_Manager)ftcmanager;
00144
00145
00146 FT_Done_Size( node->size );
00147
00148 node->scaler = scaler[0];
00149
00150 return ftc_scaler_lookup_size( manager, scaler, &node->size );
00151 }
00152
00153
00154 FT_CALLBACK_TABLE_DEF
00155 const FTC_MruListClassRec ftc_size_list_class =
00156 {
00157 sizeof ( FTC_SizeNodeRec ),
00158 ftc_size_node_compare,
00159 ftc_size_node_init,
00160 ftc_size_node_reset,
00161 ftc_size_node_done
00162 };
00163
00164
00165
00166 static FT_Bool
00167 ftc_size_node_compare_faceid( FTC_MruNode ftcnode,
00168 FT_Pointer ftcface_id )
00169 {
00170 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
00171 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
00172
00173
00174 return FT_BOOL( node->scaler.face_id == face_id );
00175 }
00176
00177
00178
00179
00180 FT_EXPORT_DEF( FT_Error )
00181 FTC_Manager_LookupSize( FTC_Manager manager,
00182 FTC_Scaler scaler,
00183 FT_Size *asize )
00184 {
00185 FT_Error error;
00186 FTC_MruNode mrunode;
00187
00188
00189 if ( asize == NULL )
00190 return FTC_Err_Invalid_Argument;
00191
00192 *asize = NULL;
00193
00194 if ( !manager )
00195 return FTC_Err_Invalid_Cache_Handle;
00196
00197 #ifdef FTC_INLINE
00198
00199 FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
00200 mrunode, error );
00201
00202 #else
00203 error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode );
00204 #endif
00205
00206 if ( !error )
00207 *asize = FTC_SIZE_NODE( mrunode )->size;
00208
00209 return error;
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 typedef struct FTC_FaceNodeRec_
00222 {
00223 FTC_MruNodeRec node;
00224 FTC_FaceID face_id;
00225 FT_Face face;
00226
00227 } FTC_FaceNodeRec, *FTC_FaceNode;
00228
00229 #define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
00230
00231
00232 FT_CALLBACK_DEF( FT_Error )
00233 ftc_face_node_init( FTC_MruNode ftcnode,
00234 FT_Pointer ftcface_id,
00235 FT_Pointer ftcmanager )
00236 {
00237 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
00238 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
00239 FTC_Manager manager = (FTC_Manager)ftcmanager;
00240 FT_Error error;
00241
00242
00243 node->face_id = face_id;
00244
00245 error = manager->request_face( face_id,
00246 manager->library,
00247 manager->request_data,
00248 &node->face );
00249 if ( !error )
00250 {
00251
00252 if ( node->face->size )
00253 FT_Done_Size( node->face->size );
00254 }
00255
00256 return error;
00257 }
00258
00259
00260 FT_CALLBACK_DEF( void )
00261 ftc_face_node_done( FTC_MruNode ftcnode,
00262 FT_Pointer ftcmanager )
00263 {
00264 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
00265 FTC_Manager manager = (FTC_Manager)ftcmanager;
00266
00267
00268
00269
00270 FTC_MruList_RemoveSelection( &manager->sizes,
00271 ftc_size_node_compare_faceid,
00272 node->face_id );
00273
00274
00275 FT_Done_Face( node->face );
00276 node->face = NULL;
00277 node->face_id = NULL;
00278 }
00279
00280
00281 FT_CALLBACK_DEF( FT_Bool )
00282 ftc_face_node_compare( FTC_MruNode ftcnode,
00283 FT_Pointer ftcface_id )
00284 {
00285 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
00286 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
00287
00288
00289 return FT_BOOL( node->face_id == face_id );
00290 }
00291
00292
00293 FT_CALLBACK_TABLE_DEF
00294 const FTC_MruListClassRec ftc_face_list_class =
00295 {
00296 sizeof ( FTC_FaceNodeRec),
00297
00298 ftc_face_node_compare,
00299 ftc_face_node_init,
00300 0,
00301 ftc_face_node_done
00302 };
00303
00304
00305
00306
00307 FT_EXPORT_DEF( FT_Error )
00308 FTC_Manager_LookupFace( FTC_Manager manager,
00309 FTC_FaceID face_id,
00310 FT_Face *aface )
00311 {
00312 FT_Error error;
00313 FTC_MruNode mrunode;
00314
00315
00316 if ( aface == NULL )
00317 return FTC_Err_Invalid_Argument;
00318
00319 *aface = NULL;
00320
00321 if ( !manager )
00322 return FTC_Err_Invalid_Cache_Handle;
00323
00324
00325 #ifdef FTC_INLINE
00326
00327 FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
00328 mrunode, error );
00329
00330 #else
00331 error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode );
00332 #endif
00333
00334 if ( !error )
00335 *aface = FTC_FACE_NODE( mrunode )->face;
00336
00337 return error;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 FT_EXPORT_DEF( FT_Error )
00353 FTC_Manager_New( FT_Library library,
00354 FT_UInt max_faces,
00355 FT_UInt max_sizes,
00356 FT_ULong max_bytes,
00357 FTC_Face_Requester requester,
00358 FT_Pointer req_data,
00359 FTC_Manager *amanager )
00360 {
00361 FT_Error error;
00362 FT_Memory memory;
00363 FTC_Manager manager = 0;
00364
00365
00366 if ( !library )
00367 return FTC_Err_Invalid_Library_Handle;
00368
00369 memory = library->memory;
00370
00371 if ( FT_NEW( manager ) )
00372 goto Exit;
00373
00374 if ( max_faces == 0 )
00375 max_faces = FTC_MAX_FACES_DEFAULT;
00376
00377 if ( max_sizes == 0 )
00378 max_sizes = FTC_MAX_SIZES_DEFAULT;
00379
00380 if ( max_bytes == 0 )
00381 max_bytes = FTC_MAX_BYTES_DEFAULT;
00382
00383 manager->library = library;
00384 manager->memory = memory;
00385 manager->max_weight = max_bytes;
00386
00387 manager->request_face = requester;
00388 manager->request_data = req_data;
00389
00390 FTC_MruList_Init( &manager->faces,
00391 &ftc_face_list_class,
00392 max_faces,
00393 manager,
00394 memory );
00395
00396 FTC_MruList_Init( &manager->sizes,
00397 &ftc_size_list_class,
00398 max_sizes,
00399 manager,
00400 memory );
00401
00402 *amanager = manager;
00403
00404 Exit:
00405 return error;
00406 }
00407
00408
00409
00410
00411 FT_EXPORT_DEF( void )
00412 FTC_Manager_Done( FTC_Manager manager )
00413 {
00414 FT_Memory memory;
00415 FT_UInt idx;
00416
00417
00418 if ( !manager || !manager->library )
00419 return;
00420
00421 memory = manager->memory;
00422
00423
00424 for (idx = manager->num_caches; idx-- > 0; )
00425 {
00426 FTC_Cache cache = manager->caches[idx];
00427
00428
00429 if ( cache )
00430 {
00431 cache->clazz.cache_done( cache );
00432 FT_FREE( cache );
00433 manager->caches[idx] = NULL;
00434 }
00435 }
00436 manager->num_caches = 0;
00437
00438
00439 FTC_MruList_Done( &manager->sizes );
00440 FTC_MruList_Done( &manager->faces );
00441
00442 manager->library = NULL;
00443 manager->memory = NULL;
00444
00445 FT_FREE( manager );
00446 }
00447
00448
00449
00450
00451 FT_EXPORT_DEF( void )
00452 FTC_Manager_Reset( FTC_Manager manager )
00453 {
00454 if ( manager )
00455 {
00456 FTC_MruList_Reset( &manager->sizes );
00457 FTC_MruList_Reset( &manager->faces );
00458 }
00459
00460 }
00461
00462
00463 #ifdef FT_DEBUG_ERROR
00464
00465 static void
00466 FTC_Manager_Check( FTC_Manager manager )
00467 {
00468 FTC_Node node, first;
00469
00470
00471 first = manager->nodes_list;
00472
00473
00474 if ( first )
00475 {
00476 FT_ULong weight = 0;
00477
00478
00479 node = first;
00480
00481 do
00482 {
00483 FTC_Cache cache = manager->caches[node->cache_index];
00484
00485
00486 if ( (FT_UInt)node->cache_index >= manager->num_caches )
00487 FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
00488 node->cache_index ));
00489 else
00490 weight += cache->clazz.node_weight( node, cache );
00491
00492 node = FTC_NODE__NEXT( node );
00493
00494 } while ( node != first );
00495
00496 if ( weight != manager->cur_weight )
00497 FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
00498 manager->cur_weight, weight ));
00499 }
00500
00501
00502 if ( first )
00503 {
00504 FT_UFast count = 0;
00505
00506
00507 node = first;
00508 do
00509 {
00510 count++;
00511 node = FTC_NODE__NEXT( node );
00512
00513 } while ( node != first );
00514
00515 if ( count != manager->num_nodes )
00516 FT_TRACE0(( "FTC_Manager_Check:"
00517 " invalid cache node count %d instead of %d\n",
00518 manager->num_nodes, count ));
00519 }
00520 }
00521
00522 #endif
00523
00524
00525
00526
00527
00528
00529
00530
00531 FT_LOCAL_DEF( void )
00532 FTC_Manager_Compress( FTC_Manager manager )
00533 {
00534 FTC_Node node, first;
00535
00536
00537 if ( !manager )
00538 return;
00539
00540 first = manager->nodes_list;
00541
00542 #ifdef FT_DEBUG_ERROR
00543 FTC_Manager_Check( manager );
00544
00545 FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
00546 manager->cur_weight, manager->max_weight,
00547 manager->num_nodes ));
00548 #endif
00549
00550 if ( manager->cur_weight < manager->max_weight || first == NULL )
00551 return;
00552
00553
00554 node = FTC_NODE__PREV( first );
00555 do
00556 {
00557 FTC_Node prev;
00558
00559
00560 prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );
00561
00562 if ( node->ref_count <= 0 )
00563 ftc_node_destroy( node, manager );
00564
00565 node = prev;
00566
00567 } while ( node && manager->cur_weight > manager->max_weight );
00568 }
00569
00570
00571
00572
00573 FT_LOCAL_DEF( FT_Error )
00574 FTC_Manager_RegisterCache( FTC_Manager manager,
00575 FTC_CacheClass clazz,
00576 FTC_Cache *acache )
00577 {
00578 FT_Error error = FTC_Err_Invalid_Argument;
00579 FTC_Cache cache = NULL;
00580
00581
00582 if ( manager && clazz && acache )
00583 {
00584 FT_Memory memory = manager->memory;
00585
00586
00587 if ( manager->num_caches >= FTC_MAX_CACHES )
00588 {
00589 error = FTC_Err_Too_Many_Caches;
00590 FT_ERROR(( "FTC_Manager_RegisterCache:"
00591 " too many registered caches\n" ));
00592 goto Exit;
00593 }
00594
00595 if ( !FT_ALLOC( cache, clazz->cache_size ) )
00596 {
00597 cache->manager = manager;
00598 cache->memory = memory;
00599 cache->clazz = clazz[0];
00600 cache->org_class = clazz;
00601
00602
00603
00604 cache->index = manager->num_caches;
00605
00606 error = clazz->cache_init( cache );
00607 if ( error )
00608 {
00609 clazz->cache_done( cache );
00610 FT_FREE( cache );
00611 goto Exit;
00612 }
00613
00614 manager->caches[manager->num_caches++] = cache;
00615 }
00616 }
00617
00618 Exit:
00619 if ( acache )
00620 *acache = cache;
00621 return error;
00622 }
00623
00624
00625 FT_LOCAL_DEF( FT_UInt )
00626 FTC_Manager_FlushN( FTC_Manager manager,
00627 FT_UInt count )
00628 {
00629 FTC_Node first = manager->nodes_list;
00630 FTC_Node node;
00631 FT_UInt result;
00632
00633
00634
00635 if ( first == NULL )
00636 return 0;
00637
00638
00639 node = FTC_NODE__PREV(first);
00640 for ( result = 0; result < count; )
00641 {
00642 FTC_Node prev = FTC_NODE__PREV( node );
00643
00644
00645
00646 if ( node->ref_count <= 0 )
00647 {
00648 ftc_node_destroy( node, manager );
00649 result++;
00650 }
00651
00652 if ( node == first )
00653 break;
00654
00655 node = prev;
00656 }
00657 return result;
00658 }
00659
00660
00661
00662
00663 FT_EXPORT_DEF( void )
00664 FTC_Manager_RemoveFaceID( FTC_Manager manager,
00665 FTC_FaceID face_id )
00666 {
00667 FT_UInt nn;
00668
00669
00670
00671
00672 FTC_MruList_RemoveSelection( &manager->faces,
00673 (FTC_MruNode_CompareFunc)NULL,
00674 face_id );
00675
00676 for ( nn = 0; nn < manager->num_caches; nn++ )
00677 FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
00678 }
00679
00680
00681
00682
00683 FT_EXPORT_DEF( void )
00684 FTC_Node_Unref( FTC_Node node,
00685 FTC_Manager manager )
00686 {
00687 if ( node && (FT_UInt)node->cache_index < manager->num_caches )
00688 node->ref_count--;
00689 }
00690
00691
00692 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
00693
00694 FT_EXPORT_DEF( FT_Error )
00695 FTC_Manager_Lookup_Face( FTC_Manager manager,
00696 FTC_FaceID face_id,
00697 FT_Face *aface )
00698 {
00699 return FTC_Manager_LookupFace( manager, face_id, aface );
00700 }
00701
00702
00703 FT_EXPORT( FT_Error )
00704 FTC_Manager_Lookup_Size( FTC_Manager manager,
00705 FTC_Font font,
00706 FT_Face *aface,
00707 FT_Size *asize )
00708 {
00709 FTC_ScalerRec scaler;
00710 FT_Error error;
00711 FT_Size size;
00712 FT_Face face;
00713
00714
00715 scaler.face_id = font->face_id;
00716 scaler.width = font->pix_width;
00717 scaler.height = font->pix_height;
00718 scaler.pixel = TRUE;
00719 scaler.x_res = 0;
00720 scaler.y_res = 0;
00721
00722 error = FTC_Manager_LookupSize( manager, &scaler, &size );
00723 if ( error )
00724 {
00725 face = NULL;
00726 size = NULL;
00727 }
00728 else
00729 face = size->face;
00730
00731 if ( aface )
00732 *aface = face;
00733
00734 if ( asize )
00735 *asize = size;
00736
00737 return error;
00738 }
00739
00740 #endif
00741
00742
00743