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