ftcmanag.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftcmanag.c                                                             */
00004 /*                                                                         */
00005 /*    FreeType Cache Manager (body).                                       */
00006 /*                                                                         */
00007 /*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 by       */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
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   /* helper function used by ftc_face_node_done */
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   /* documentation is in ftcache.h */
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   /*****                    FACE MRU IMPLEMENTATION                    *****/
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       /* destroy initial size object; it will be re-created later */
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     /* we must begin by removing all scalers for the target face */
00269     /* from the manager's list                                   */
00270     FTC_MruList_RemoveSelection( &manager->sizes,
00271                                  ftc_size_node_compare_faceid,
00272                                  node->face_id );
00273 
00274     /* all right, we can discard the face now */
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,                          /* FTC_MruNode_ResetFunc */
00301     ftc_face_node_done
00302   };
00303 
00304 
00305   /* documentation is in ftcache.h */
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     /* we break encapsulation for the sake of speed */
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   /*****                    CACHE MANAGER ROUTINES                     *****/
00345   /*****                                                               *****/
00346   /*************************************************************************/
00347   /*************************************************************************/
00348 
00349 
00350   /* documentation is in ftcache.h */
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   /* documentation is in ftcache.h */
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     /* now discard all caches */
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     /* discard faces and sizes */
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   /* documentation is in ftcache.h */
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     /* XXX: FIXME: flush the caches? */
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     /* check node weights */
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     /* check circular list */
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 /* FT_DEBUG_ERROR */
00523 
00524 
00525   /* `Compress' the manager's data, i.e., get rid of old cache nodes */
00526   /* that are not referenced anymore in order to limit the total     */
00527   /* memory used by the cache.                                       */
00528 
00529   /* documentation is in ftcmanag.h */
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     /* go to last node -- it's a circular list */
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   /* documentation is in ftcmanag.h */
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         /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
00603         /* IF IT IS NOT SET CORRECTLY                          */
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     /* try to remove `count' nodes from the list */
00635     if ( first == NULL )  /* empty list! */
00636       return 0;
00637 
00638     /* go to last node - it's a circular list */
00639     node = FTC_NODE__PREV(first);
00640     for ( result = 0; result < count; )
00641     {
00642       FTC_Node  prev = FTC_NODE__PREV( node );
00643 
00644 
00645       /* don't touch locked nodes */
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   /* documentation is in ftcache.h */
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     /* this will remove all FTC_SizeNode that correspond to
00670      * the face_id as well
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   /* documentation is in ftcache.h */
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 /* FT_CONFIG_OPTION_OLD_INTERNALS */
00741 
00742 
00743 /* END */

Generated on Tue Jul 5 14:13:45 2011 for ROOT_528-00b_version by  doxygen 1.5.1