1 /***************************************************************************/
5 /* FreeType CharMap cache (body) */
7 /* Copyright 2000-2001, 2002 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. */
16 /***************************************************************************/
20 #include FT_FREETYPE_H
22 #include FT_CACHE_CHARMAP_H
23 #include FT_CACHE_MANAGER_H
24 #include FT_INTERNAL_MEMORY_H
25 #include FT_INTERNAL_DEBUG_H
26 #include FT_TRUETYPE_IDS_H
31 #define FT_COMPONENT trace_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 */
44 /*************************************************************************/
47 /* number of glyph indices / character code per node */
48 #define FTC_CMAP_INDICES_MAX 128
51 typedef struct FTC_CMapNodeRec_
54 FT_UInt32 first; /* first character in node */
55 FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
57 } FTC_CMapNodeRec, *FTC_CMapNode;
60 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
63 /* compute node hash value from cmap family and "requested" glyph index */
64 #define FTC_CMAP_HASH( cfam, cquery ) \
65 ( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) )
67 /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
68 /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
69 #define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 )
72 /* the charmap query */
73 typedef struct FTC_CMapQueryRec_
79 } FTC_CMapQueryRec, *FTC_CMapQuery;
82 #define FTC_CMAP_QUERY( x ) ( (FTC_CMapQuery)( x ) )
85 /* the charmap family */
86 typedef struct FTC_CMapFamilyRec_
93 } FTC_CMapFamilyRec, *FTC_CMapFamily;
96 #define FTC_CMAP_FAMILY( x ) ( (FTC_CMapFamily)( x ) )
97 #define FTC_CMAP_FAMILY_MEMORY( x ) FTC_FAMILY( x )->memory
100 /*************************************************************************/
101 /*************************************************************************/
103 /***** CHARMAP NODES *****/
105 /*************************************************************************/
106 /*************************************************************************/
109 /* no need for specific finalizer; we use "ftc_node_done" directly */
111 /* initialize a new cmap node */
112 FT_CALLBACK_DEF( FT_Error )
113 ftc_cmap_node_init( FTC_CMapNode cnode,
114 FTC_CMapQuery cquery,
122 first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) *
123 FTC_CMAP_INDICES_MAX;
125 cnode->first = first;
126 for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
127 cnode->indices[n] = FTC_CMAP_UNKNOWN;
133 /* compute the weight of a given cmap node */
134 FT_CALLBACK_DEF( FT_ULong )
135 ftc_cmap_node_weight( FTC_CMapNode cnode )
139 return sizeof ( *cnode );
143 /* compare a cmap node to a given query */
144 FT_CALLBACK_DEF( FT_Bool )
145 ftc_cmap_node_compare( FTC_CMapNode cnode,
146 FTC_CMapQuery cquery )
148 FT_UInt32 offset = (FT_UInt32)( cquery->char_code - cnode->first );
151 return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
155 /*************************************************************************/
156 /*************************************************************************/
158 /***** CHARMAP FAMILY *****/
160 /*************************************************************************/
161 /*************************************************************************/
164 FT_CALLBACK_DEF( FT_Error )
165 ftc_cmap_family_init( FTC_CMapFamily cfam,
166 FTC_CMapQuery cquery,
169 FTC_Manager manager = cache->manager;
170 FTC_CMapDesc desc = cquery->desc;
176 /* setup charmap descriptor */
179 /* let's see whether the rest is correct too */
180 error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face );
183 FT_UInt count = face->num_charmaps;
185 FT_CharMap* cur = face->charmaps;
188 switch ( desc->type )
190 case FTC_CMAP_BY_INDEX:
195 case FTC_CMAP_BY_ENCODING:
196 if (desc->u.encoding == FT_ENCODING_UNICODE)
198 /* since the `interesting' table, with id's 3,10, is normally the
199 * last one, we loop backwards. This looses with type1 fonts with
200 * non-BMP characters (<.0001%), this wins with .ttf with non-BMP
201 * chars (.01% ?), and this is the same about 99.99% of the time!
204 FT_UInt unicmap_idx = count; /* some UCS-2 map, if we found it */
208 for ( idx = 0; idx < count; idx++, cur-- )
210 if ( cur[0]->encoding == FT_ENCODING_UNICODE )
212 unicmap_idx = idx; /* record we found a Unicode charmap */
214 /* XXX If some new encodings to represent UCS-4 are added,
215 * they should be added here.
217 if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
218 cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
219 ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
220 cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
222 /* Hurray! We found a UCS-4 charmap. We can stop the scan! */
224 idx = count - 1 - idx;
225 goto Found_idx_for_FTC_CMAP_BY_ENCODING;
230 /* We do not have any UCS-4 charmap. Sigh.
231 * Let's see if we have some other kind of Unicode charmap, though.
233 if ( unicmap_idx < count )
234 idx = count - 1 - unicmap_idx;
238 for ( idx = 0; idx < count; idx++, cur++ )
239 if ( cur[0]->encoding == desc->u.encoding )
243 Found_idx_for_FTC_CMAP_BY_ENCODING:
248 for ( idx = 0; idx < count; idx++, cur++ )
250 if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform &&
251 (FT_UInt)cur[0]->encoding_id == desc->u.id.encoding )
253 hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7;
266 /* compute hash value, both in family and query */
268 cfam->hash = hash ^ FTC_FACE_ID_HASH( desc->face_id );
269 FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
271 error = ftc_family_init( FTC_FAMILY( cfam ),
272 FTC_QUERY( cquery ), cache );
278 FT_TRACE1(( "ftp_cmap_family_init: invalid charmap descriptor\n" ));
279 return FTC_Err_Invalid_Argument;
283 FT_CALLBACK_DEF( FT_Bool )
284 ftc_cmap_family_compare( FTC_CMapFamily cfam,
285 FTC_CMapQuery cquery )
290 /* first, compare face id and type */
291 if ( cfam->desc.face_id != cquery->desc->face_id ||
292 cfam->desc.type != cquery->desc->type )
295 switch ( cfam->desc.type )
297 case FTC_CMAP_BY_INDEX:
298 result = ( cfam->desc.u.index == cquery->desc->u.index );
301 case FTC_CMAP_BY_ENCODING:
302 result = ( cfam->desc.u.encoding == cquery->desc->u.encoding );
306 result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform &&
307 cfam->desc.u.id.encoding == cquery->desc->u.id.encoding );
316 /* when found, update the 'family' and 'hash' field of the query */
317 FTC_QUERY( cquery )->family = FTC_FAMILY( cfam );
318 FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
322 return FT_BOOL( result );
326 /*************************************************************************/
327 /*************************************************************************/
329 /***** GLYPH IMAGE CACHE *****/
331 /*************************************************************************/
332 /*************************************************************************/
335 FT_CALLBACK_TABLE_DEF
336 const FTC_Cache_ClassRec ftc_cmap_cache_class =
338 sizeof ( FTC_CacheRec ),
339 (FTC_Cache_InitFunc) ftc_cache_init,
340 (FTC_Cache_ClearFunc)ftc_cache_clear,
341 (FTC_Cache_DoneFunc) ftc_cache_done,
343 sizeof ( FTC_CMapFamilyRec ),
344 (FTC_Family_InitFunc) ftc_cmap_family_init,
345 (FTC_Family_CompareFunc)ftc_cmap_family_compare,
346 (FTC_Family_DoneFunc) ftc_family_done,
348 sizeof ( FTC_CMapNodeRec ),
349 (FTC_Node_InitFunc) ftc_cmap_node_init,
350 (FTC_Node_WeightFunc) ftc_cmap_node_weight,
351 (FTC_Node_CompareFunc)ftc_cmap_node_compare,
352 (FTC_Node_DoneFunc) ftc_node_done
356 /* documentation is in ftccmap.h */
358 FT_EXPORT_DEF( FT_Error )
359 FTC_CMapCache_New( FTC_Manager manager,
360 FTC_CMapCache *acache )
362 return FTC_Manager_Register_Cache(
364 (FTC_Cache_Class)&ftc_cmap_cache_class,
365 FTC_CACHE_P( acache ) );
369 #ifdef FTC_CACHE_USE_INLINE
371 #define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
372 ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) )
374 #define GEN_CACHE_NODE_COMPARE( n, q, c ) \
375 ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) )
377 #define GEN_CACHE_LOOKUP ftc_cmap_cache_lookup
379 #include "ftccache.i"
381 #else /* !FTC_CACHE_USE_INLINE */
383 #define ftc_cmap_cache_lookup ftc_cache_lookup
385 #endif /* !FTC_CACHE_USE_INLINE */
388 /* documentation is in ftccmap.h */
390 FT_EXPORT_DEF( FT_UInt )
391 FTC_CMapCache_Lookup( FTC_CMapCache cache,
393 FT_UInt32 char_code )
395 FTC_CMapQueryRec cquery;
401 if ( !cache || !desc )
403 FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
408 cquery.char_code = char_code;
410 error = ftc_cmap_cache_lookup( FTC_CACHE( cache ),
411 FTC_QUERY( &cquery ),
415 FT_UInt offset = (FT_UInt)( char_code - node->first );
418 FT_ASSERT( offset < FTC_CMAP_INDICES_MAX );
420 gindex = node->indices[offset];
421 if ( gindex == FTC_CMAP_UNKNOWN )
426 /* we need to use FT_Get_Char_Index */
429 error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager,
434 FT_CharMap old, cmap = NULL;
438 /* save old charmap, select new one */
440 cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index;
441 cmap = face->charmaps[cmap_index];
443 FT_Set_Charmap( face, cmap );
446 gindex = FT_Get_Char_Index( face, char_code );
447 node->indices[offset] = (FT_UInt16)gindex;
449 /* restore old charmap */
450 FT_Set_Charmap( face, old );