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