tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ftcmanag.c (16615B)


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