ftccmap.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftccmap.c                                                              */
00004 /*                                                                         */
00005 /*    FreeType CharMap cache (body)                                        */
00006 /*                                                                         */
00007 /*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_FREETYPE_H
00021 #include FT_CACHE_H
00022 #include "ftcmanag.h"
00023 #include FT_INTERNAL_MEMORY_H
00024 #include FT_INTERNAL_DEBUG_H
00025 
00026 #include "ftccback.h"
00027 #include "ftcerror.h"
00028 
00029 #undef  FT_COMPONENT
00030 #define FT_COMPONENT  trace_cache
00031 
00032 
00033 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
00034 
00035   typedef enum  FTC_OldCMapType_
00036   {
00037     FTC_OLD_CMAP_BY_INDEX    = 0,
00038     FTC_OLD_CMAP_BY_ENCODING = 1,
00039     FTC_OLD_CMAP_BY_ID       = 2
00040 
00041   } FTC_OldCMapType;
00042 
00043 
00044   typedef struct  FTC_OldCMapIdRec_
00045   {
00046     FT_UInt  platform;
00047     FT_UInt  encoding;
00048 
00049   } FTC_OldCMapIdRec, *FTC_OldCMapId;
00050 
00051 
00052   typedef struct  FTC_OldCMapDescRec_
00053   {
00054     FTC_FaceID       face_id;
00055     FTC_OldCMapType  type;
00056 
00057     union
00058     {
00059       FT_UInt           index;
00060       FT_Encoding       encoding;
00061       FTC_OldCMapIdRec  id;
00062 
00063     } u;
00064 
00065   } FTC_OldCMapDescRec, *FTC_OldCMapDesc;
00066 
00067 #endif /* FT_CONFIG_OLD_INTERNALS */
00068 
00069 
00070   /*************************************************************************/
00071   /*                                                                       */
00072   /* Each FTC_CMapNode contains a simple array to map a range of character */
00073   /* codes to equivalent glyph indices.                                    */
00074   /*                                                                       */
00075   /* For now, the implementation is very basic: Each node maps a range of  */
00076   /* 128 consecutive character codes to their corresponding glyph indices. */
00077   /*                                                                       */
00078   /* We could do more complex things, but I don't think it is really very  */
00079   /* useful.                                                               */
00080   /*                                                                       */
00081   /*************************************************************************/
00082 
00083 
00084   /* number of glyph indices / character code per node */
00085 #define FTC_CMAP_INDICES_MAX  128
00086 
00087   /* compute a query/node hash */
00088 #define FTC_CMAP_HASH( faceid, index, charcode )         \
00089           ( FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \
00090             ( (charcode) / FTC_CMAP_INDICES_MAX )      )
00091 
00092   /* the charmap query */
00093   typedef struct  FTC_CMapQueryRec_
00094   {
00095     FTC_FaceID  face_id;
00096     FT_UInt     cmap_index;
00097     FT_UInt32   char_code;
00098 
00099   } FTC_CMapQueryRec, *FTC_CMapQuery;
00100 
00101 #define FTC_CMAP_QUERY( x )  ((FTC_CMapQuery)(x))
00102 #define FTC_CMAP_QUERY_HASH( x )                                         \
00103           FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code )
00104 
00105   /* the cmap cache node */
00106   typedef struct  FTC_CMapNodeRec_
00107   {
00108     FTC_NodeRec  node;
00109     FTC_FaceID   face_id;
00110     FT_UInt      cmap_index;
00111     FT_UInt32    first;                         /* first character in node */
00112     FT_UInt16    indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices  */
00113 
00114   } FTC_CMapNodeRec, *FTC_CMapNode;
00115 
00116 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
00117 #define FTC_CMAP_NODE_HASH( x )                                      \
00118           FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first )
00119 
00120   /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
00121   /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet   */
00122 #define FTC_CMAP_UNKNOWN  ( (FT_UInt16)-1 )
00123 
00124 
00125   /*************************************************************************/
00126   /*************************************************************************/
00127   /*****                                                               *****/
00128   /*****                        CHARMAP NODES                          *****/
00129   /*****                                                               *****/
00130   /*************************************************************************/
00131   /*************************************************************************/
00132 
00133 
00134   FT_CALLBACK_DEF( void )
00135   ftc_cmap_node_free( FTC_Node   ftcnode,
00136                       FTC_Cache  cache )
00137   {
00138     FTC_CMapNode  node   = (FTC_CMapNode)ftcnode;
00139     FT_Memory     memory = cache->memory;
00140 
00141 
00142     FT_FREE( node );
00143   }
00144 
00145 
00146   /* initialize a new cmap node */
00147   FT_CALLBACK_DEF( FT_Error )
00148   ftc_cmap_node_new( FTC_Node   *ftcanode,
00149                      FT_Pointer  ftcquery,
00150                      FTC_Cache   cache )
00151   {
00152     FTC_CMapNode  *anode  = (FTC_CMapNode*)ftcanode;
00153     FTC_CMapQuery  query  = (FTC_CMapQuery)ftcquery;
00154     FT_Error       error;
00155     FT_Memory      memory = cache->memory;
00156     FTC_CMapNode   node;
00157     FT_UInt        nn;
00158 
00159 
00160     if ( !FT_NEW( node ) )
00161     {
00162       node->face_id    = query->face_id;
00163       node->cmap_index = query->cmap_index;
00164       node->first      = (query->char_code / FTC_CMAP_INDICES_MAX) *
00165                          FTC_CMAP_INDICES_MAX;
00166 
00167       for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
00168         node->indices[nn] = FTC_CMAP_UNKNOWN;
00169     }
00170 
00171     *anode = node;
00172     return error;
00173   }
00174 
00175 
00176   /* compute the weight of a given cmap node */
00177   FT_CALLBACK_DEF( FT_Offset )
00178   ftc_cmap_node_weight( FTC_Node   cnode,
00179                         FTC_Cache  cache )
00180   {
00181     FT_UNUSED( cnode );
00182     FT_UNUSED( cache );
00183 
00184     return sizeof ( *cnode );
00185   }
00186 
00187 
00188   /* compare a cmap node to a given query */
00189   FT_CALLBACK_DEF( FT_Bool )
00190   ftc_cmap_node_compare( FTC_Node    ftcnode,
00191                          FT_Pointer  ftcquery,
00192                          FTC_Cache   cache )
00193   {
00194     FTC_CMapNode   node  = (FTC_CMapNode)ftcnode;
00195     FTC_CMapQuery  query = (FTC_CMapQuery)ftcquery;
00196     FT_UNUSED( cache );
00197 
00198 
00199     if ( node->face_id    == query->face_id    &&
00200          node->cmap_index == query->cmap_index )
00201     {
00202       FT_UInt32  offset = (FT_UInt32)( query->char_code - node->first );
00203 
00204 
00205       return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
00206     }
00207 
00208     return 0;
00209   }
00210 
00211 
00212   FT_CALLBACK_DEF( FT_Bool )
00213   ftc_cmap_node_remove_faceid( FTC_Node    ftcnode,
00214                                FT_Pointer  ftcface_id,
00215                                FTC_Cache   cache )
00216   {
00217     FTC_CMapNode  node    = (FTC_CMapNode)ftcnode;
00218     FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
00219     FT_UNUSED( cache );
00220 
00221     return FT_BOOL( node->face_id == face_id );
00222   }
00223 
00224 
00225   /*************************************************************************/
00226   /*************************************************************************/
00227   /*****                                                               *****/
00228   /*****                    GLYPH IMAGE CACHE                          *****/
00229   /*****                                                               *****/
00230   /*************************************************************************/
00231   /*************************************************************************/
00232 
00233 
00234   FT_CALLBACK_TABLE_DEF
00235   const FTC_CacheClassRec  ftc_cmap_cache_class =
00236   {
00237     ftc_cmap_node_new,
00238     ftc_cmap_node_weight,
00239     ftc_cmap_node_compare,
00240     ftc_cmap_node_remove_faceid,
00241     ftc_cmap_node_free,
00242 
00243     sizeof ( FTC_CacheRec ),
00244     ftc_cache_init,
00245     ftc_cache_done,
00246   };
00247 
00248 
00249   /* documentation is in ftcache.h */
00250 
00251   FT_EXPORT_DEF( FT_Error )
00252   FTC_CMapCache_New( FTC_Manager     manager,
00253                      FTC_CMapCache  *acache )
00254   {
00255     return FTC_Manager_RegisterCache( manager,
00256                                       &ftc_cmap_cache_class,
00257                                       FTC_CACHE_P( acache ) );
00258   }
00259 
00260 
00261 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
00262 
00263   /*
00264    *  Unfortunately, it is not possible to support binary backwards
00265    *  compatibility in the cmap cache.  The FTC_CMapCache_Lookup signature
00266    *  changes were too deep, and there is no clever hackish way to detect
00267    *  what kind of structure we are being passed.
00268    *
00269    *  On the other hand it seems that no production code is using this
00270    *  function on Unix distributions.
00271    */
00272 
00273 #endif
00274 
00275 
00276   /* documentation is in ftcache.h */
00277 
00278   FT_EXPORT_DEF( FT_UInt )
00279   FTC_CMapCache_Lookup( FTC_CMapCache  cmap_cache,
00280                         FTC_FaceID     face_id,
00281                         FT_Int         cmap_index,
00282                         FT_UInt32      char_code )
00283   {
00284     FTC_Cache         cache = FTC_CACHE( cmap_cache );
00285     FTC_CMapQueryRec  query;
00286     FTC_Node          node;
00287     FT_Error          error;
00288     FT_UInt           gindex = 0;
00289     FT_UInt32         hash;
00290     FT_Int            no_cmap_change = 0;
00291 
00292 
00293     if ( cmap_index < 0 )
00294     {
00295       /* Treat a negative cmap index as a special value, meaning that you */
00296       /* don't want to change the FT_Face's character map through this    */
00297       /* call.  This can be useful if the face requester callback already */
00298       /* sets the face's charmap to the appropriate value.                */
00299 
00300       no_cmap_change = 1;
00301       cmap_index     = 0;
00302     }
00303 
00304     if ( !cache )
00305     {
00306       FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
00307       return 0;
00308     }
00309 
00310 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
00311 
00312     /*
00313      *  Detect a call from a rogue client that thinks it is linking
00314      *  to FreeType 2.1.7.  This is possible because the third parameter
00315      *  is then a character code, and we have never seen any font with
00316      *  more than a few charmaps, so if the index is very large...
00317      *
00318      *  It is also very unlikely that a rogue client is interested
00319      *  in Unicode values 0 to 15.
00320      *
00321      *  NOTE: The original threshold was 4, but we found a font from the
00322      *        Adobe Acrobat Reader Pack, named `KozMinProVI-Regular.otf',
00323      *        which contains more than 5 charmaps.
00324      */
00325     if ( cmap_index >= 16 && !no_cmap_change )
00326     {
00327       FTC_OldCMapDesc  desc = (FTC_OldCMapDesc) face_id;
00328 
00329 
00330       char_code     = (FT_UInt32)cmap_index;
00331       query.face_id = desc->face_id;
00332 
00333 
00334       switch ( desc->type )
00335       {
00336       case FTC_OLD_CMAP_BY_INDEX:
00337         query.cmap_index = desc->u.index;
00338         query.char_code  = (FT_UInt32)cmap_index;
00339         break;
00340 
00341       case FTC_OLD_CMAP_BY_ENCODING:
00342         {
00343           FT_Face  face;
00344 
00345 
00346           error = FTC_Manager_LookupFace( cache->manager, desc->face_id,
00347                                           &face );
00348           if ( error )
00349             return 0;
00350 
00351           FT_Select_Charmap( face, desc->u.encoding );
00352 
00353           return FT_Get_Char_Index( face, char_code );
00354         }
00355 
00356       default:
00357         return 0;
00358       }
00359     }
00360     else
00361 
00362 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
00363 
00364     {
00365       query.face_id    = face_id;
00366       query.cmap_index = (FT_UInt)cmap_index;
00367       query.char_code  = char_code;
00368     }
00369 
00370     hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
00371 
00372 #if 1
00373     FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
00374                           node, error );
00375 #else
00376     error = FTC_Cache_Lookup( cache, hash, &query, &node );
00377 #endif
00378     if ( error )
00379       goto Exit;
00380 
00381     FT_ASSERT( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first ) <
00382                 FTC_CMAP_INDICES_MAX );
00383 
00384     /* something rotten can happen with rogue clients */
00385     if ( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first >=
00386                     FTC_CMAP_INDICES_MAX ) )
00387       return 0;
00388 
00389     gindex = FTC_CMAP_NODE( node )->indices[char_code -
00390                                             FTC_CMAP_NODE( node )->first];
00391     if ( gindex == FTC_CMAP_UNKNOWN )
00392     {
00393       FT_Face  face;
00394 
00395 
00396       gindex = 0;
00397 
00398       error = FTC_Manager_LookupFace( cache->manager,
00399                                       FTC_CMAP_NODE( node )->face_id,
00400                                       &face );
00401       if ( error )
00402         goto Exit;
00403 
00404       if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
00405       {
00406         FT_CharMap  old, cmap  = NULL;
00407 
00408 
00409         old  = face->charmap;
00410         cmap = face->charmaps[cmap_index];
00411 
00412         if ( old != cmap && !no_cmap_change )
00413           FT_Set_Charmap( face, cmap );
00414 
00415         gindex = FT_Get_Char_Index( face, char_code );
00416 
00417         if ( old != cmap && !no_cmap_change )
00418           FT_Set_Charmap( face, old );
00419       }
00420 
00421       FTC_CMAP_NODE( node )->indices[char_code -
00422                                      FTC_CMAP_NODE( node )->first]
00423         = (FT_UShort)gindex;
00424     }
00425 
00426   Exit:
00427     return gindex;
00428   }
00429 
00430 
00431 /* END */

Generated on Tue Jul 5 14:13:45 2011 for ROOT_528-00b_version by  doxygen 1.5.1