1 /***************************************************************************/
5 /* FreeType CharMap cache (body) */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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
23 #include FT_INTERNAL_MEMORY_H
24 #include FT_INTERNAL_DEBUG_H
30 #define FT_COMPONENT trace_cache
33 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
35 typedef enum FTC_OldCMapType_
37 FTC_OLD_CMAP_BY_INDEX
= 0,
38 FTC_OLD_CMAP_BY_ENCODING
= 1,
39 FTC_OLD_CMAP_BY_ID
= 2
44 typedef struct FTC_OldCMapIdRec_
49 } FTC_OldCMapIdRec
, *FTC_OldCMapId
;
52 typedef struct FTC_OldCMapDescRec_
65 } FTC_OldCMapDescRec
, *FTC_OldCMapDesc
;
67 #endif /* FT_CONFIG_OLD_INTERNALS */
70 /*************************************************************************/
72 /* Each FTC_CMapNode contains a simple array to map a range of character */
73 /* codes to equivalent glyph indices. */
75 /* For now, the implementation is very basic: Each node maps a range of */
76 /* 128 consecutive character codes to their corresponding glyph indices. */
78 /* We could do more complex things, but I don't think it is really very */
81 /*************************************************************************/
84 /* number of glyph indices / character code per node */
85 #define FTC_CMAP_INDICES_MAX 128
87 /* compute a query/node hash */
88 #define FTC_CMAP_HASH( faceid, index, charcode ) \
89 ( FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \
90 ( (charcode) / FTC_CMAP_INDICES_MAX ) )
92 /* the charmap query */
93 typedef struct FTC_CMapQueryRec_
99 } FTC_CMapQueryRec
, *FTC_CMapQuery
;
101 #define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x))
102 #define FTC_CMAP_QUERY_HASH( x ) \
103 FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code )
105 /* the cmap cache node */
106 typedef struct FTC_CMapNodeRec_
111 FT_UInt32 first
; /* first character in node */
112 FT_UInt16 indices
[FTC_CMAP_INDICES_MAX
]; /* array of glyph indices */
114 } FTC_CMapNodeRec
, *FTC_CMapNode
;
116 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
117 #define FTC_CMAP_NODE_HASH( x ) \
118 FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first )
120 /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
121 /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
122 #define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 )
125 /*************************************************************************/
126 /*************************************************************************/
128 /***** CHARMAP NODES *****/
130 /*************************************************************************/
131 /*************************************************************************/
134 FT_CALLBACK_DEF( void )
135 ftc_cmap_node_free( FTC_Node ftcnode
,
138 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
139 FT_Memory memory
= cache
->memory
;
146 /* initialize a new cmap node */
147 FT_CALLBACK_DEF( FT_Error
)
148 ftc_cmap_node_new( FTC_Node
*ftcanode
,
152 FTC_CMapNode
*anode
= (FTC_CMapNode
*)ftcanode
;
153 FTC_CMapQuery query
= (FTC_CMapQuery
)ftcquery
;
155 FT_Memory memory
= cache
->memory
;
160 if ( !FT_NEW( node
) )
162 node
->face_id
= query
->face_id
;
163 node
->cmap_index
= query
->cmap_index
;
164 node
->first
= (query
->char_code
/ FTC_CMAP_INDICES_MAX
) *
165 FTC_CMAP_INDICES_MAX
;
167 for ( nn
= 0; nn
< FTC_CMAP_INDICES_MAX
; nn
++ )
168 node
->indices
[nn
] = FTC_CMAP_UNKNOWN
;
176 /* compute the weight of a given cmap node */
177 FT_CALLBACK_DEF( FT_Offset
)
178 ftc_cmap_node_weight( FTC_Node cnode
,
184 return sizeof ( *cnode
);
188 /* compare a cmap node to a given query */
189 FT_CALLBACK_DEF( FT_Bool
)
190 ftc_cmap_node_compare( FTC_Node ftcnode
,
194 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
195 FTC_CMapQuery query
= (FTC_CMapQuery
)ftcquery
;
199 if ( node
->face_id
== query
->face_id
&&
200 node
->cmap_index
== query
->cmap_index
)
202 FT_UInt32 offset
= (FT_UInt32
)( query
->char_code
- node
->first
);
205 return FT_BOOL( offset
< FTC_CMAP_INDICES_MAX
);
212 FT_CALLBACK_DEF( FT_Bool
)
213 ftc_cmap_node_remove_faceid( FTC_Node ftcnode
,
214 FT_Pointer ftcface_id
,
217 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
218 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
221 return FT_BOOL( node
->face_id
== face_id
);
225 /*************************************************************************/
226 /*************************************************************************/
228 /***** GLYPH IMAGE CACHE *****/
230 /*************************************************************************/
231 /*************************************************************************/
234 FT_CALLBACK_TABLE_DEF
235 const FTC_CacheClassRec ftc_cmap_cache_class
=
238 ftc_cmap_node_weight
,
239 ftc_cmap_node_compare
,
240 ftc_cmap_node_remove_faceid
,
243 sizeof ( FTC_CacheRec
),
249 /* documentation is in ftcache.h */
251 FT_EXPORT_DEF( FT_Error
)
252 FTC_CMapCache_New( FTC_Manager manager
,
253 FTC_CMapCache
*acache
)
255 return FTC_Manager_RegisterCache( manager
,
256 &ftc_cmap_cache_class
,
257 FTC_CACHE_P( acache
) );
261 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
264 * Unfortunately, it is not possible to support binary backwards
265 * compatibility in the cmap cache. The FTC_CMapCache_Lookup signature
266 * changes were too deep, and there is no clever hackish way to detect
267 * what kind of structure we are being passed.
269 * On the other hand it seems that no production code is using this
270 * function on Unix distributions.
276 /* documentation is in ftcache.h */
278 FT_EXPORT_DEF( FT_UInt
)
279 FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache
,
282 FT_UInt32 char_code
)
284 FTC_Cache cache
= FTC_CACHE( cmap_cache
);
285 FTC_CMapQueryRec query
;
290 FT_Int no_cmap_change
= 0;
293 if ( cmap_index
< 0 )
295 /* Treat a negative cmap index as a special value, meaning that you */
296 /* don't want to change the FT_Face's character map through this */
297 /* call. This can be useful if the face requester callback already */
298 /* sets the face's charmap to the appropriate value. */
306 FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
310 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
313 * Detect a call from a rogue client that thinks it is linking
314 * to FreeType 2.1.7. This is possible because the third parameter
315 * is then a character code, and we have never seen any font with
316 * more than a few charmaps, so if the index is very large...
318 * It is also very unlikely that a rogue client is interested
319 * in Unicode values 0 to 15.
321 * NOTE: The original threshold was 4, but we found a font from the
322 * Adobe Acrobat Reader Pack, named `KozMinProVI-Regular.otf',
323 * which contains more than 5 charmaps.
325 if ( cmap_index
>= 16 && !no_cmap_change
)
327 FTC_OldCMapDesc desc
= (FTC_OldCMapDesc
) face_id
;
330 char_code
= (FT_UInt32
)cmap_index
;
331 query
.face_id
= desc
->face_id
;
334 switch ( desc
->type
)
336 case FTC_OLD_CMAP_BY_INDEX
:
337 query
.cmap_index
= desc
->u
.index
;
338 query
.char_code
= (FT_UInt32
)cmap_index
;
341 case FTC_OLD_CMAP_BY_ENCODING
:
346 error
= FTC_Manager_LookupFace( cache
->manager
, desc
->face_id
,
351 FT_Select_Charmap( face
, desc
->u
.encoding
);
353 return FT_Get_Char_Index( face
, char_code
);
362 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
365 query
.face_id
= face_id
;
366 query
.cmap_index
= (FT_UInt
)cmap_index
;
367 query
.char_code
= char_code
;
370 hash
= FTC_CMAP_HASH( face_id
, cmap_index
, char_code
);
373 FTC_CACHE_LOOKUP_CMP( cache
, ftc_cmap_node_compare
, hash
, &query
,
376 error
= FTC_Cache_Lookup( cache
, hash
, &query
, &node
);
381 FT_ASSERT( (FT_UInt
)( char_code
- FTC_CMAP_NODE( node
)->first
) <
382 FTC_CMAP_INDICES_MAX
);
384 /* something rotten can happen with rogue clients */
385 if ( (FT_UInt
)( char_code
- FTC_CMAP_NODE( node
)->first
>=
386 FTC_CMAP_INDICES_MAX
) )
389 gindex
= FTC_CMAP_NODE( node
)->indices
[char_code
-
390 FTC_CMAP_NODE( node
)->first
];
391 if ( gindex
== FTC_CMAP_UNKNOWN
)
398 error
= FTC_Manager_LookupFace( cache
->manager
,
399 FTC_CMAP_NODE( node
)->face_id
,
404 if ( (FT_UInt
)cmap_index
< (FT_UInt
)face
->num_charmaps
)
406 FT_CharMap old
, cmap
= NULL
;
410 cmap
= face
->charmaps
[cmap_index
];
412 if ( old
!= cmap
&& !no_cmap_change
)
413 FT_Set_Charmap( face
, cmap
);
415 gindex
= FT_Get_Char_Index( face
, char_code
);
417 if ( old
!= cmap
&& !no_cmap_change
)
418 FT_Set_Charmap( face
, old
);
421 FTC_CMAP_NODE( node
)->indices
[char_code
-
422 FTC_CMAP_NODE( node
)->first
]