OLD | NEW |
(Empty) | |
| 1 /***************************************************************************/ |
| 2 /* */ |
| 3 /* ftccmap.c */ |
| 4 /* */ |
| 5 /* FreeType CharMap cache (body) */ |
| 6 /* */ |
| 7 /* Copyright 2000-2013 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 FT_CALLBACK_TABLE_DEF |
| 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 */ |
OLD | NEW |