Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  ftcmanag.c                                                             */
  4. /*                                                                         */
  5. /*    FreeType Cache Manager (body).                                       */
  6. /*                                                                         */
  7. /*  Copyright 2000-2006, 2008-2010, 2013 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 FT_THROW( Invalid_Argument );
  191.  
  192.     *asize = NULL;
  193.  
  194.     if ( !manager )
  195.       return FT_THROW( 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 FT_THROW( Invalid_Argument );
  318.  
  319.     *aface = NULL;
  320.  
  321.     if ( !manager )
  322.       return FT_THROW( 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 FT_THROW( 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.  
  460.     FTC_Manager_FlushN( manager, manager->num_nodes );
  461.   }
  462.  
  463.  
  464. #ifdef FT_DEBUG_ERROR
  465.  
  466.   static void
  467.   FTC_Manager_Check( FTC_Manager  manager )
  468.   {
  469.     FTC_Node  node, first;
  470.  
  471.  
  472.     first = manager->nodes_list;
  473.  
  474.     /* check node weights */
  475.     if ( first )
  476.     {
  477.       FT_Offset  weight = 0;
  478.  
  479.  
  480.       node = first;
  481.  
  482.       do
  483.       {
  484.         FTC_Cache  cache = manager->caches[node->cache_index];
  485.  
  486.  
  487.         if ( (FT_UInt)node->cache_index >= manager->num_caches )
  488.           FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
  489.                       node->cache_index ));
  490.         else
  491.           weight += cache->clazz.node_weight( node, cache );
  492.  
  493.         node = FTC_NODE__NEXT( node );
  494.  
  495.       } while ( node != first );
  496.  
  497.       if ( weight != manager->cur_weight )
  498.         FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
  499.                     manager->cur_weight, weight ));
  500.     }
  501.  
  502.     /* check circular list */
  503.     if ( first )
  504.     {
  505.       FT_UFast  count = 0;
  506.  
  507.  
  508.       node = first;
  509.       do
  510.       {
  511.         count++;
  512.         node = FTC_NODE__NEXT( node );
  513.  
  514.       } while ( node != first );
  515.  
  516.       if ( count != manager->num_nodes )
  517.         FT_TRACE0(( "FTC_Manager_Check:"
  518.                     " invalid cache node count %d instead of %d\n",
  519.                     manager->num_nodes, count ));
  520.     }
  521.   }
  522.  
  523. #endif /* FT_DEBUG_ERROR */
  524.  
  525.  
  526.   /* `Compress' the manager's data, i.e., get rid of old cache nodes */
  527.   /* that are not referenced anymore in order to limit the total     */
  528.   /* memory used by the cache.                                       */
  529.  
  530.   /* documentation is in ftcmanag.h */
  531.  
  532.   FT_LOCAL_DEF( void )
  533.   FTC_Manager_Compress( FTC_Manager  manager )
  534.   {
  535.     FTC_Node   node, first;
  536.  
  537.  
  538.     if ( !manager )
  539.       return;
  540.  
  541.     first = manager->nodes_list;
  542.  
  543. #ifdef FT_DEBUG_ERROR
  544.     FTC_Manager_Check( manager );
  545.  
  546.     FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
  547.                 manager->cur_weight, manager->max_weight,
  548.                 manager->num_nodes ));
  549. #endif
  550.  
  551.     if ( manager->cur_weight < manager->max_weight || first == NULL )
  552.       return;
  553.  
  554.     /* go to last node -- it's a circular list */
  555.     node = FTC_NODE__PREV( first );
  556.     do
  557.     {
  558.       FTC_Node  prev;
  559.  
  560.  
  561.       prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );
  562.  
  563.       if ( node->ref_count <= 0 )
  564.         ftc_node_destroy( node, manager );
  565.  
  566.       node = prev;
  567.  
  568.     } while ( node && manager->cur_weight > manager->max_weight );
  569.   }
  570.  
  571.  
  572.   /* documentation is in ftcmanag.h */
  573.  
  574.   FT_LOCAL_DEF( FT_Error )
  575.   FTC_Manager_RegisterCache( FTC_Manager      manager,
  576.                              FTC_CacheClass   clazz,
  577.                              FTC_Cache       *acache )
  578.   {
  579.     FT_Error   error = FT_ERR( Invalid_Argument );
  580.     FTC_Cache  cache = NULL;
  581.  
  582.  
  583.     if ( manager && clazz && acache )
  584.     {
  585.       FT_Memory  memory = manager->memory;
  586.  
  587.  
  588.       if ( manager->num_caches >= FTC_MAX_CACHES )
  589.       {
  590.         error = FT_THROW( Too_Many_Caches );
  591.         FT_ERROR(( "FTC_Manager_RegisterCache:"
  592.                    " too many registered caches\n" ));
  593.         goto Exit;
  594.       }
  595.  
  596.       if ( !FT_ALLOC( cache, clazz->cache_size ) )
  597.       {
  598.         cache->manager   = manager;
  599.         cache->memory    = memory;
  600.         cache->clazz     = clazz[0];
  601.         cache->org_class = clazz;
  602.  
  603.         /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
  604.         /* IF IT IS NOT SET CORRECTLY                          */
  605.         cache->index = manager->num_caches;
  606.  
  607.         error = clazz->cache_init( cache );
  608.         if ( error )
  609.         {
  610.           clazz->cache_done( cache );
  611.           FT_FREE( cache );
  612.           goto Exit;
  613.         }
  614.  
  615.         manager->caches[manager->num_caches++] = cache;
  616.       }
  617.     }
  618.  
  619.   Exit:
  620.     if ( acache )
  621.       *acache = cache;
  622.     return error;
  623.   }
  624.  
  625.  
  626.   FT_LOCAL_DEF( FT_UInt )
  627.   FTC_Manager_FlushN( FTC_Manager  manager,
  628.                       FT_UInt      count )
  629.   {
  630.     FTC_Node  first = manager->nodes_list;
  631.     FTC_Node  node;
  632.     FT_UInt   result;
  633.  
  634.  
  635.     /* try to remove `count' nodes from the list */
  636.     if ( first == NULL )  /* empty list! */
  637.       return 0;
  638.  
  639.     /* go to last node - it's a circular list */
  640.     node = FTC_NODE__PREV(first);
  641.     for ( result = 0; result < count; )
  642.     {
  643.       FTC_Node  prev = FTC_NODE__PREV( node );
  644.  
  645.  
  646.       /* don't touch locked nodes */
  647.       if ( node->ref_count <= 0 )
  648.       {
  649.         ftc_node_destroy( node, manager );
  650.         result++;
  651.       }
  652.  
  653.       if ( node == first )
  654.         break;
  655.  
  656.       node = prev;
  657.     }
  658.     return  result;
  659.   }
  660.  
  661.  
  662.   /* documentation is in ftcache.h */
  663.  
  664.   FT_EXPORT_DEF( void )
  665.   FTC_Manager_RemoveFaceID( FTC_Manager  manager,
  666.                             FTC_FaceID   face_id )
  667.   {
  668.     FT_UInt  nn;
  669.  
  670.     /* this will remove all FTC_SizeNode that correspond to
  671.      * the face_id as well
  672.      */
  673.     FTC_MruList_RemoveSelection( &manager->faces,
  674.                                  ftc_face_node_compare,
  675.                                  face_id );
  676.  
  677.     for ( nn = 0; nn < manager->num_caches; nn++ )
  678.       FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
  679.   }
  680.  
  681.  
  682.   /* documentation is in ftcache.h */
  683.  
  684.   FT_EXPORT_DEF( void )
  685.   FTC_Node_Unref( FTC_Node     node,
  686.                   FTC_Manager  manager )
  687.   {
  688.     if ( node && (FT_UInt)node->cache_index < manager->num_caches )
  689.       node->ref_count--;
  690.   }
  691.  
  692.  
  693. /* END */
  694.