1 /****************************************************************************
5 * FreeType CharMap cache (body)
7 * Copyright (C) 2000-2023 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
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.
19 #include <freetype/freetype.h>
20 #include <freetype/ftcache.h>
22 #include <freetype/internal/ftmemory.h>
23 #include <freetype/internal/ftobjs.h>
24 #include <freetype/internal/ftdebug.h>
30 #define FT_COMPONENT cache
33 /**************************************************************************
35 * Each FTC_CMapNode contains a simple array to map a range of character
36 * codes to equivalent glyph indices.
38 * For now, the implementation is very basic: Each node maps a range of
39 * 128 consecutive character codes to their corresponding glyph indices.
41 * We could do more complex things, but I don't think it is really very
47 /* number of glyph indices / character code per node */
48 #define FTC_CMAP_INDICES_MAX 128
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 ) )
55 /* the charmap query */
56 typedef struct FTC_CMapQueryRec_
62 } FTC_CMapQueryRec, *FTC_CMapQuery;
64 #define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x))
66 /* the cmap cache node */
67 typedef struct FTC_CMapNodeRec_
72 FT_UInt32 first; /* first character in node */
73 FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
75 } FTC_CMapNodeRec, *FTC_CMapNode;
77 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
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
84 /*************************************************************************/
85 /*************************************************************************/
87 /***** CHARMAP NODES *****/
89 /*************************************************************************/
90 /*************************************************************************/
93 FT_CALLBACK_DEF( void )
94 ftc_cmap_node_free( FTC_Node ftcnode,
97 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
98 FT_Memory memory = cache->memory;
105 /* initialize a new cmap node */
106 FT_CALLBACK_DEF( FT_Error )
107 ftc_cmap_node_new( FTC_Node *ftcanode,
111 FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode;
112 FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
114 FT_Memory memory = cache->memory;
115 FTC_CMapNode node = NULL;
119 if ( !FT_QNEW( node ) )
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;
126 for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
127 node->indices[nn] = FTC_CMAP_UNKNOWN;
135 /* compute the weight of a given cmap node */
136 FT_CALLBACK_DEF( FT_Offset )
137 ftc_cmap_node_weight( FTC_Node cnode,
143 return sizeof ( *cnode );
147 /* compare a cmap node to a given query */
148 FT_CALLBACK_DEF( FT_Bool )
149 ftc_cmap_node_compare( FTC_Node ftcnode,
152 FT_Bool* list_changed )
154 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
155 FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
160 *list_changed = FALSE;
161 if ( node->face_id == query->face_id &&
162 node->cmap_index == query->cmap_index )
164 FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first );
167 return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
174 FT_CALLBACK_DEF( FT_Bool )
175 ftc_cmap_node_remove_faceid( FTC_Node ftcnode,
176 FT_Pointer ftcface_id,
178 FT_Bool* list_changed )
180 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
181 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
186 *list_changed = FALSE;
187 return FT_BOOL( node->face_id == face_id );
191 /*************************************************************************/
192 /*************************************************************************/
194 /***** GLYPH IMAGE CACHE *****/
196 /*************************************************************************/
197 /*************************************************************************/
201 const FTC_CacheClassRec ftc_cmap_cache_class =
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 */
209 sizeof ( FTC_CacheRec ),
210 ftc_cache_init, /* FTC_Cache_InitFunc cache_init */
211 ftc_cache_done, /* FTC_Cache_DoneFunc cache_done */
215 /* documentation is in ftcache.h */
217 FT_EXPORT_DEF( FT_Error )
218 FTC_CMapCache_New( FTC_Manager manager,
219 FTC_CMapCache *acache )
221 return FTC_Manager_RegisterCache( manager,
222 &ftc_cmap_cache_class,
223 FTC_CACHE_P( acache ) );
227 /* documentation is in ftcache.h */
229 FT_EXPORT_DEF( FT_UInt )
230 FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache,
233 FT_UInt32 char_code )
235 FTC_Cache cache = FTC_CACHE( cmap_cache );
236 FTC_CMapQueryRec query;
241 FT_Int no_cmap_change = 0;
244 if ( cmap_index < 0 )
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. */
257 FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
261 query.face_id = face_id;
262 query.cmap_index = (FT_UInt)cmap_index;
263 query.char_code = char_code;
265 hash = FTC_CMAP_HASH( face_id, (FT_UInt)cmap_index, char_code );
268 FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
271 error = FTC_Cache_Lookup( cache, hash, &query, &node );
276 FT_ASSERT( char_code - FTC_CMAP_NODE( node )->first <
277 FTC_CMAP_INDICES_MAX );
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 */
283 gindex = FTC_CMAP_NODE( node )->indices[char_code -
284 FTC_CMAP_NODE( node )->first];
285 if ( gindex == FTC_CMAP_UNKNOWN )
292 error = FTC_Manager_LookupFace( cache->manager,
293 FTC_CMAP_NODE( node )->face_id,
298 if ( cmap_index < face->num_charmaps )
300 FT_CharMap old = face->charmap;
301 FT_CharMap cmap = face->charmaps[cmap_index];
304 if ( !no_cmap_change )
305 face->charmap = cmap;
307 gindex = FT_Get_Char_Index( face, char_code );
309 if ( !no_cmap_change )
313 FTC_CMAP_NODE( node )->indices[char_code -
314 FTC_CMAP_NODE( node )->first]