tor-browser

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

ftccmap.c (9723B)


      1 /****************************************************************************
      2 *
      3 * ftccmap.c
      4 *
      5 *   FreeType CharMap cache (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/freetype.h>
     20 #include <freetype/ftcache.h>
     21 #include "ftcmanag.h"
     22 #include <freetype/internal/ftmemory.h>
     23 #include <freetype/internal/ftobjs.h>
     24 #include <freetype/internal/ftdebug.h>
     25 
     26 #include "ftccback.h"
     27 #include "ftcerror.h"
     28 
     29 #undef  FT_COMPONENT
     30 #define FT_COMPONENT  cache
     31 
     32 
     33  /**************************************************************************
     34   *
     35   * Each FTC_CMapNode contains a simple array to map a range of character
     36   * codes to equivalent glyph indices.
     37   *
     38   * For now, the implementation is very basic: Each node maps a range of
     39   * 128 consecutive character codes to their corresponding glyph indices.
     40   *
     41   * We could do more complex things, but I don't think it is really very
     42   * useful.
     43   *
     44   */
     45 
     46 
     47  /* number of glyph indices / character code per node */
     48 #define FTC_CMAP_INDICES_MAX  128
     49 
     50  /* compute a query/node hash */
     51 #define FTC_CMAP_HASH( faceid, index, charcode )         \
     52          ( FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \
     53            ( (charcode) / FTC_CMAP_INDICES_MAX )      )
     54 
     55  /* the charmap query */
     56  typedef struct  FTC_CMapQueryRec_
     57  {
     58    FTC_FaceID  face_id;
     59    FT_UInt     cmap_index;
     60    FT_UInt32   char_code;
     61 
     62  } FTC_CMapQueryRec, *FTC_CMapQuery;
     63 
     64 #define FTC_CMAP_QUERY( x )  ((FTC_CMapQuery)(x))
     65 
     66  /* the cmap cache node */
     67  typedef struct  FTC_CMapNodeRec_
     68  {
     69    FTC_NodeRec  node;
     70    FTC_FaceID   face_id;
     71    FT_UInt      cmap_index;
     72    FT_UInt32    first;                         /* first character in node */
     73    FT_UInt16    indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices  */
     74 
     75  } FTC_CMapNodeRec, *FTC_CMapNode;
     76 
     77 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
     78 
     79  /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
     80  /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet   */
     81 #define FTC_CMAP_UNKNOWN  (FT_UInt16)~0
     82 
     83 
     84  /*************************************************************************/
     85  /*************************************************************************/
     86  /*****                                                               *****/
     87  /*****                        CHARMAP NODES                          *****/
     88  /*****                                                               *****/
     89  /*************************************************************************/
     90  /*************************************************************************/
     91 
     92 
     93  FT_CALLBACK_DEF( void )
     94  ftc_cmap_node_free( FTC_Node   ftcnode,
     95                      FTC_Cache  cache )
     96  {
     97    FTC_CMapNode  node   = (FTC_CMapNode)ftcnode;
     98    FT_Memory     memory = cache->memory;
     99 
    100 
    101    FT_FREE( node );
    102  }
    103 
    104 
    105  /* initialize a new cmap node */
    106  FT_CALLBACK_DEF( FT_Error )
    107  ftc_cmap_node_new( FTC_Node   *ftcanode,
    108                     FT_Pointer  ftcquery,
    109                     FTC_Cache   cache )
    110  {
    111    FTC_CMapNode  *anode  = (FTC_CMapNode*)ftcanode;
    112    FTC_CMapQuery  query  = (FTC_CMapQuery)ftcquery;
    113    FT_Error       error;
    114    FT_Memory      memory = cache->memory;
    115    FTC_CMapNode   node   = NULL;
    116    FT_UInt        nn;
    117 
    118 
    119    if ( !FT_QNEW( node ) )
    120    {
    121      node->face_id    = query->face_id;
    122      node->cmap_index = query->cmap_index;
    123      node->first      = (query->char_code / FTC_CMAP_INDICES_MAX) *
    124                         FTC_CMAP_INDICES_MAX;
    125 
    126      for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
    127        node->indices[nn] = FTC_CMAP_UNKNOWN;
    128    }
    129 
    130    *anode = node;
    131    return error;
    132  }
    133 
    134 
    135  /* compute the weight of a given cmap node */
    136  FT_CALLBACK_DEF( FT_Offset )
    137  ftc_cmap_node_weight( FTC_Node   cnode,
    138                        FTC_Cache  cache )
    139  {
    140    FT_UNUSED( cnode );
    141    FT_UNUSED( cache );
    142 
    143    return sizeof ( *cnode );
    144  }
    145 
    146 
    147  /* compare a cmap node to a given query */
    148  FT_CALLBACK_DEF( FT_Bool )
    149  ftc_cmap_node_compare( FTC_Node    ftcnode,
    150                         FT_Pointer  ftcquery,
    151                         FTC_Cache   cache,
    152                         FT_Bool*    list_changed )
    153  {
    154    FTC_CMapNode   node  = (FTC_CMapNode)ftcnode;
    155    FTC_CMapQuery  query = (FTC_CMapQuery)ftcquery;
    156    FT_UNUSED( cache );
    157 
    158 
    159    if ( list_changed )
    160      *list_changed = FALSE;
    161    if ( node->face_id    == query->face_id    &&
    162         node->cmap_index == query->cmap_index )
    163    {
    164      FT_UInt32  offset = (FT_UInt32)( query->char_code - node->first );
    165 
    166 
    167      return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
    168    }
    169 
    170    return 0;
    171  }
    172 
    173 
    174  FT_CALLBACK_DEF( FT_Bool )
    175  ftc_cmap_node_remove_faceid( FTC_Node    ftcnode,
    176                               FT_Pointer  ftcface_id,
    177                               FTC_Cache   cache,
    178                               FT_Bool*    list_changed )
    179  {
    180    FTC_CMapNode  node    = (FTC_CMapNode)ftcnode;
    181    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
    182    FT_UNUSED( cache );
    183 
    184 
    185    if ( list_changed )
    186      *list_changed = FALSE;
    187    return FT_BOOL( node->face_id == face_id );
    188  }
    189 
    190 
    191  /*************************************************************************/
    192  /*************************************************************************/
    193  /*****                                                               *****/
    194  /*****                    GLYPH IMAGE CACHE                          *****/
    195  /*****                                                               *****/
    196  /*************************************************************************/
    197  /*************************************************************************/
    198 
    199 
    200  static
    201  const FTC_CacheClassRec  ftc_cmap_cache_class =
    202  {
    203    ftc_cmap_node_new,           /* FTC_Node_NewFunc      node_new           */
    204    ftc_cmap_node_weight,        /* FTC_Node_WeightFunc   node_weight        */
    205    ftc_cmap_node_compare,       /* FTC_Node_CompareFunc  node_compare       */
    206    ftc_cmap_node_remove_faceid, /* FTC_Node_CompareFunc  node_remove_faceid */
    207    ftc_cmap_node_free,          /* FTC_Node_FreeFunc     node_free          */
    208 
    209    sizeof ( FTC_CacheRec ),
    210    ftc_cache_init,              /* FTC_Cache_InitFunc    cache_init         */
    211    ftc_cache_done,              /* FTC_Cache_DoneFunc    cache_done         */
    212  };
    213 
    214 
    215  /* documentation is in ftcache.h */
    216 
    217  FT_EXPORT_DEF( FT_Error )
    218  FTC_CMapCache_New( FTC_Manager     manager,
    219                     FTC_CMapCache  *acache )
    220  {
    221    return FTC_Manager_RegisterCache( manager,
    222                                      &ftc_cmap_cache_class,
    223                                      FTC_CACHE_P( acache ) );
    224  }
    225 
    226 
    227  /* documentation is in ftcache.h */
    228 
    229  FT_EXPORT_DEF( FT_UInt )
    230  FTC_CMapCache_Lookup( FTC_CMapCache  cmap_cache,
    231                        FTC_FaceID     face_id,
    232                        FT_Int         cmap_index,
    233                        FT_UInt32      char_code )
    234  {
    235    FTC_Cache         cache = FTC_CACHE( cmap_cache );
    236    FTC_CMapQueryRec  query;
    237    FTC_Node          node;
    238    FT_Error          error;
    239    FT_UInt           gindex = 0;
    240    FT_Offset         hash;
    241    FT_Int            no_cmap_change = 0;
    242 
    243 
    244    if ( cmap_index < 0 )
    245    {
    246      /* Treat a negative cmap index as a special value, meaning that you */
    247      /* don't want to change the FT_Face's character map through this    */
    248      /* call.  This can be useful if the face requester callback already */
    249      /* sets the face's charmap to the appropriate value.                */
    250 
    251      no_cmap_change = 1;
    252      cmap_index     = 0;
    253    }
    254 
    255    if ( !cache )
    256    {
    257      FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
    258      return 0;
    259    }
    260 
    261    query.face_id    = face_id;
    262    query.cmap_index = (FT_UInt)cmap_index;
    263    query.char_code  = char_code;
    264 
    265    hash = FTC_CMAP_HASH( face_id, (FT_UInt)cmap_index, char_code );
    266 
    267 #ifdef FTC_INLINE
    268    FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
    269                          node, error );
    270 #else
    271    error = FTC_Cache_Lookup( cache, hash, &query, &node );
    272 #endif
    273    if ( error )
    274      goto Exit;
    275 
    276    FT_ASSERT( char_code - FTC_CMAP_NODE( node )->first <
    277               FTC_CMAP_INDICES_MAX );
    278 
    279    /* something rotten can happen with rogue clients */
    280    if ( char_code - FTC_CMAP_NODE( node )->first >= FTC_CMAP_INDICES_MAX )
    281      return 0; /* XXX: should return appropriate error */
    282 
    283    gindex = FTC_CMAP_NODE( node )->indices[char_code -
    284                                            FTC_CMAP_NODE( node )->first];
    285    if ( gindex == FTC_CMAP_UNKNOWN )
    286    {
    287      FT_Face  face;
    288 
    289 
    290      gindex = 0;
    291 
    292      error = FTC_Manager_LookupFace( cache->manager,
    293                                      FTC_CMAP_NODE( node )->face_id,
    294                                      &face );
    295      if ( error )
    296        goto Exit;
    297 
    298      if ( cmap_index < face->num_charmaps )
    299      {
    300        FT_CharMap  old  = face->charmap;
    301        FT_CharMap  cmap = face->charmaps[cmap_index];
    302 
    303 
    304        if ( !no_cmap_change )
    305          face->charmap = cmap;
    306 
    307        gindex = FT_Get_Char_Index( face, char_code );
    308 
    309        if ( !no_cmap_change )
    310          face->charmap = old;
    311      }
    312 
    313      FTC_CMAP_NODE( node )->indices[char_code -
    314                                     FTC_CMAP_NODE( node )->first]
    315        = (FT_UShort)gindex;
    316    }
    317 
    318  Exit:
    319    return gindex;
    320  }
    321 
    322 
    323 /* END */