(root)/
freetype-2.13.2/
src/
cache/
ftccmap.c
       1  /****************************************************************************
       2   *
       3   * ftccmap.c
       4   *
       5   *   FreeType CharMap cache (body)
       6   *
       7   * Copyright (C) 2000-2023 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  #if 1
     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 */