1 /***************************************************************************/
5 /* FreeType CharMap cache (body) */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
17 /***************************************************************************/
21 #include FT_FREETYPE_H
24 #include FT_INTERNAL_MEMORY_H
25 #include FT_INTERNAL_DEBUG_H
31 #define FT_COMPONENT trace_cache
34 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
36 typedef enum FTC_OldCMapType_
38 FTC_OLD_CMAP_BY_INDEX
= 0,
39 FTC_OLD_CMAP_BY_ENCODING
= 1,
40 FTC_OLD_CMAP_BY_ID
= 2
45 typedef struct FTC_OldCMapIdRec_
50 } FTC_OldCMapIdRec
, *FTC_OldCMapId
;
53 typedef struct FTC_OldCMapDescRec_
66 } FTC_OldCMapDescRec
, *FTC_OldCMapDesc
;
68 #endif /* FT_CONFIG_OLD_INTERNALS */
71 /*************************************************************************/
73 /* Each FTC_CMapNode contains a simple array to map a range of character */
74 /* codes to equivalent glyph indices. */
76 /* For now, the implementation is very basic: Each node maps a range of */
77 /* 128 consecutive character codes to their corresponding glyph indices. */
79 /* We could do more complex things, but I don't think it is really very */
82 /*************************************************************************/
85 /* number of glyph indices / character code per node */
86 #define FTC_CMAP_INDICES_MAX 128
88 /* compute a query/node hash */
89 #define FTC_CMAP_HASH( faceid, index, charcode ) \
90 ( _FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \
91 ( (charcode) / FTC_CMAP_INDICES_MAX ) )
93 /* the charmap query */
94 typedef struct FTC_CMapQueryRec_
100 } FTC_CMapQueryRec
, *FTC_CMapQuery
;
102 #define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x))
103 #define FTC_CMAP_QUERY_HASH( x ) \
104 FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code )
106 /* the cmap cache node */
107 typedef struct FTC_CMapNodeRec_
112 FT_UInt32 first
; /* first character in node */
113 FT_UInt16 indices
[FTC_CMAP_INDICES_MAX
]; /* array of glyph indices */
115 } FTC_CMapNodeRec
, *FTC_CMapNode
;
117 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
118 #define FTC_CMAP_NODE_HASH( x ) \
119 FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first )
121 /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
122 /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
123 #define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 )
126 /*************************************************************************/
127 /*************************************************************************/
129 /***** CHARMAP NODES *****/
131 /*************************************************************************/
132 /*************************************************************************/
135 FT_CALLBACK_DEF( void )
136 ftc_cmap_node_free( FTC_Node ftcnode
,
139 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
140 FT_Memory memory
= cache
->memory
;
147 /* initialize a new cmap node */
148 FT_CALLBACK_DEF( FT_Error
)
149 ftc_cmap_node_new( FTC_Node
*ftcanode
,
153 FTC_CMapNode
*anode
= (FTC_CMapNode
*)ftcanode
;
154 FTC_CMapQuery query
= (FTC_CMapQuery
)ftcquery
;
156 FT_Memory memory
= cache
->memory
;
157 FTC_CMapNode node
= NULL
;
161 if ( !FT_NEW( node
) )
163 node
->face_id
= query
->face_id
;
164 node
->cmap_index
= query
->cmap_index
;
165 node
->first
= (query
->char_code
/ FTC_CMAP_INDICES_MAX
) *
166 FTC_CMAP_INDICES_MAX
;
168 for ( nn
= 0; nn
< FTC_CMAP_INDICES_MAX
; nn
++ )
169 node
->indices
[nn
] = FTC_CMAP_UNKNOWN
;
177 /* compute the weight of a given cmap node */
178 FT_CALLBACK_DEF( FT_Offset
)
179 ftc_cmap_node_weight( FTC_Node cnode
,
185 return sizeof ( *cnode
);
189 /* compare a cmap node to a given query */
190 FT_CALLBACK_DEF( FT_Bool
)
191 ftc_cmap_node_compare( FTC_Node ftcnode
,
195 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
196 FTC_CMapQuery query
= (FTC_CMapQuery
)ftcquery
;
200 if ( node
->face_id
== query
->face_id
&&
201 node
->cmap_index
== query
->cmap_index
)
203 FT_UInt32 offset
= (FT_UInt32
)( query
->char_code
- node
->first
);
206 return FT_BOOL( offset
< FTC_CMAP_INDICES_MAX
);
213 FT_CALLBACK_DEF( FT_Bool
)
214 ftc_cmap_node_remove_faceid( FTC_Node ftcnode
,
215 FT_Pointer ftcface_id
,
218 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
219 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
222 return FT_BOOL( node
->face_id
== face_id
);
226 /*************************************************************************/
227 /*************************************************************************/
229 /***** GLYPH IMAGE CACHE *****/
231 /*************************************************************************/
232 /*************************************************************************/
235 FT_CALLBACK_TABLE_DEF
236 const FTC_CacheClassRec ftc_cmap_cache_class
=
239 ftc_cmap_node_weight
,
240 ftc_cmap_node_compare
,
241 ftc_cmap_node_remove_faceid
,
244 sizeof ( FTC_CacheRec
),
250 /* documentation is in ftcache.h */
252 FT_EXPORT_DEF( FT_Error
)
253 FTC_CMapCache_New( FTC_Manager manager
,
254 FTC_CMapCache
*acache
)
256 return FTC_Manager_RegisterCache( manager
,
257 &ftc_cmap_cache_class
,
258 FTC_CACHE_P( acache
) );
262 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
265 * Unfortunately, it is not possible to support binary backwards
266 * compatibility in the cmap cache. The FTC_CMapCache_Lookup signature
267 * changes were too deep, and there is no clever hackish way to detect
268 * what kind of structure we are being passed.
270 * On the other hand it seems that no production code is using this
271 * function on Unix distributions.
277 /* documentation is in ftcache.h */
279 FT_EXPORT_DEF( FT_UInt
)
280 FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache
,
283 FT_UInt32 char_code
)
285 FTC_Cache cache
= FTC_CACHE( cmap_cache
);
286 FTC_CMapQueryRec query
;
291 FT_Int no_cmap_change
= 0;
294 if ( cmap_index
< 0 )
296 /* Treat a negative cmap index as a special value, meaning that you */
297 /* don't want to change the FT_Face's character map through this */
298 /* call. This can be useful if the face requester callback already */
299 /* sets the face's charmap to the appropriate value. */
307 FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
311 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
314 * If cmap_index is greater than the maximum number of cachable
315 * charmaps, we assume the request is from a legacy rogue client
316 * using old internal header. See include/config/ftoption.h.
318 if ( cmap_index
> FT_MAX_CHARMAP_CACHEABLE
&& !no_cmap_change
)
320 FTC_OldCMapDesc desc
= (FTC_OldCMapDesc
) face_id
;
323 char_code
= (FT_UInt32
)cmap_index
;
324 query
.face_id
= desc
->face_id
;
327 switch ( desc
->type
)
329 case FTC_OLD_CMAP_BY_INDEX
:
330 query
.cmap_index
= desc
->u
.index
;
331 query
.char_code
= (FT_UInt32
)cmap_index
;
334 case FTC_OLD_CMAP_BY_ENCODING
:
339 error
= FTC_Manager_LookupFace( cache
->manager
, desc
->face_id
,
344 FT_Select_Charmap( face
, desc
->u
.encoding
);
346 return FT_Get_Char_Index( face
, char_code
);
355 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
358 query
.face_id
= face_id
;
359 query
.cmap_index
= (FT_UInt
)cmap_index
;
360 query
.char_code
= char_code
;
363 hash
= FTC_CMAP_HASH( face_id
, cmap_index
, char_code
);
366 FTC_CACHE_LOOKUP_CMP( cache
, ftc_cmap_node_compare
, hash
, &query
,
369 error
= FTC_Cache_Lookup( cache
, hash
, &query
, &node
);
374 FT_ASSERT( (FT_UInt
)( char_code
- FTC_CMAP_NODE( node
)->first
) <
375 FTC_CMAP_INDICES_MAX
);
377 /* something rotten can happen with rogue clients */
378 if ( (FT_UInt
)( char_code
- FTC_CMAP_NODE( node
)->first
>=
379 FTC_CMAP_INDICES_MAX
) )
380 return 0; /* XXX: should return appropriate error */
382 gindex
= FTC_CMAP_NODE( node
)->indices
[char_code
-
383 FTC_CMAP_NODE( node
)->first
];
384 if ( gindex
== FTC_CMAP_UNKNOWN
)
391 error
= FTC_Manager_LookupFace( cache
->manager
,
392 FTC_CMAP_NODE( node
)->face_id
,
397 #ifdef FT_MAX_CHARMAP_CACHEABLE
398 /* something rotten can happen with rogue clients */
399 if ( cmap_index
> FT_MAX_CHARMAP_CACHEABLE
)
400 return 0; /* XXX: should return appropriate error */
403 if ( (FT_UInt
)cmap_index
< (FT_UInt
)face
->num_charmaps
)
405 FT_CharMap old
, cmap
= NULL
;
409 cmap
= face
->charmaps
[cmap_index
];
411 if ( old
!= cmap
&& !no_cmap_change
)
412 FT_Set_Charmap( face
, cmap
);
414 gindex
= FT_Get_Char_Index( face
, char_code
);
416 if ( old
!= cmap
&& !no_cmap_change
)
417 FT_Set_Charmap( face
, old
);
420 FTC_CMAP_NODE( node
)->indices
[char_code
-
421 FTC_CMAP_NODE( node
)->first
]