1 /***************************************************************************/
5 /* FreeType CharMap cache (body) */
7 /* Copyright 2000-2018 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_OBJECTS_H
25 #include FT_INTERNAL_DEBUG_H
31 #define FT_COMPONENT trace_cache
34 /*************************************************************************/
36 /* Each FTC_CMapNode contains a simple array to map a range of character */
37 /* codes to equivalent glyph indices. */
39 /* For now, the implementation is very basic: Each node maps a range of */
40 /* 128 consecutive character codes to their corresponding glyph indices. */
42 /* We could do more complex things, but I don't think it is really very */
45 /*************************************************************************/
48 /* number of glyph indices / character code per node */
49 #define FTC_CMAP_INDICES_MAX 128
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 ) )
56 /* the charmap query */
57 typedef struct FTC_CMapQueryRec_
63 } FTC_CMapQueryRec
, *FTC_CMapQuery
;
65 #define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x))
67 /* the cmap cache node */
68 typedef struct FTC_CMapNodeRec_
73 FT_UInt32 first
; /* first character in node */
74 FT_UInt16 indices
[FTC_CMAP_INDICES_MAX
]; /* array of glyph indices */
76 } FTC_CMapNodeRec
, *FTC_CMapNode
;
78 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
80 /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
81 /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
82 #define FTC_CMAP_UNKNOWN (FT_UInt16)~0
85 /*************************************************************************/
86 /*************************************************************************/
88 /***** CHARMAP NODES *****/
90 /*************************************************************************/
91 /*************************************************************************/
94 FT_CALLBACK_DEF( void )
95 ftc_cmap_node_free( FTC_Node ftcnode
,
98 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
99 FT_Memory memory
= cache
->memory
;
106 /* initialize a new cmap node */
107 FT_CALLBACK_DEF( FT_Error
)
108 ftc_cmap_node_new( FTC_Node
*ftcanode
,
112 FTC_CMapNode
*anode
= (FTC_CMapNode
*)ftcanode
;
113 FTC_CMapQuery query
= (FTC_CMapQuery
)ftcquery
;
115 FT_Memory memory
= cache
->memory
;
116 FTC_CMapNode node
= NULL
;
120 if ( !FT_NEW( node
) )
122 node
->face_id
= query
->face_id
;
123 node
->cmap_index
= query
->cmap_index
;
124 node
->first
= (query
->char_code
/ FTC_CMAP_INDICES_MAX
) *
125 FTC_CMAP_INDICES_MAX
;
127 for ( nn
= 0; nn
< FTC_CMAP_INDICES_MAX
; nn
++ )
128 node
->indices
[nn
] = FTC_CMAP_UNKNOWN
;
136 /* compute the weight of a given cmap node */
137 FT_CALLBACK_DEF( FT_Offset
)
138 ftc_cmap_node_weight( FTC_Node cnode
,
144 return sizeof ( *cnode
);
148 /* compare a cmap node to a given query */
149 FT_CALLBACK_DEF( FT_Bool
)
150 ftc_cmap_node_compare( FTC_Node ftcnode
,
153 FT_Bool
* list_changed
)
155 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
156 FTC_CMapQuery query
= (FTC_CMapQuery
)ftcquery
;
161 *list_changed
= FALSE
;
162 if ( node
->face_id
== query
->face_id
&&
163 node
->cmap_index
== query
->cmap_index
)
165 FT_UInt32 offset
= (FT_UInt32
)( query
->char_code
- node
->first
);
168 return FT_BOOL( offset
< FTC_CMAP_INDICES_MAX
);
175 FT_CALLBACK_DEF( FT_Bool
)
176 ftc_cmap_node_remove_faceid( FTC_Node ftcnode
,
177 FT_Pointer ftcface_id
,
179 FT_Bool
* list_changed
)
181 FTC_CMapNode node
= (FTC_CMapNode
)ftcnode
;
182 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
187 *list_changed
= FALSE
;
188 return FT_BOOL( node
->face_id
== face_id
);
192 /*************************************************************************/
193 /*************************************************************************/
195 /***** GLYPH IMAGE CACHE *****/
197 /*************************************************************************/
198 /*************************************************************************/
202 const FTC_CacheClassRec ftc_cmap_cache_class
=
204 ftc_cmap_node_new
, /* FTC_Node_NewFunc node_new */
205 ftc_cmap_node_weight
, /* FTC_Node_WeightFunc node_weight */
206 ftc_cmap_node_compare
, /* FTC_Node_CompareFunc node_compare */
207 ftc_cmap_node_remove_faceid
, /* FTC_Node_CompareFunc node_remove_faceid */
208 ftc_cmap_node_free
, /* FTC_Node_FreeFunc node_free */
210 sizeof ( FTC_CacheRec
),
211 ftc_cache_init
, /* FTC_Cache_InitFunc cache_init */
212 ftc_cache_done
, /* FTC_Cache_DoneFunc cache_done */
216 /* documentation is in ftcache.h */
218 FT_EXPORT_DEF( FT_Error
)
219 FTC_CMapCache_New( FTC_Manager manager
,
220 FTC_CMapCache
*acache
)
222 return FTC_Manager_RegisterCache( manager
,
223 &ftc_cmap_cache_class
,
224 FTC_CACHE_P( acache
) );
228 /* documentation is in ftcache.h */
230 FT_EXPORT_DEF( FT_UInt
)
231 FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache
,
234 FT_UInt32 char_code
)
236 FTC_Cache cache
= FTC_CACHE( cmap_cache
);
237 FTC_CMapQueryRec query
;
242 FT_Int no_cmap_change
= 0;
245 if ( cmap_index
< 0 )
247 /* Treat a negative cmap index as a special value, meaning that you */
248 /* don't want to change the FT_Face's character map through this */
249 /* call. This can be useful if the face requester callback already */
250 /* sets the face's charmap to the appropriate value. */
258 FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
262 query
.face_id
= face_id
;
263 query
.cmap_index
= (FT_UInt
)cmap_index
;
264 query
.char_code
= char_code
;
266 hash
= FTC_CMAP_HASH( face_id
, (FT_UInt
)cmap_index
, char_code
);
269 FTC_CACHE_LOOKUP_CMP( cache
, ftc_cmap_node_compare
, hash
, &query
,
272 error
= FTC_Cache_Lookup( cache
, hash
, &query
, &node
);
277 FT_ASSERT( (FT_UInt
)( char_code
- FTC_CMAP_NODE( node
)->first
) <
278 FTC_CMAP_INDICES_MAX
);
280 /* something rotten can happen with rogue clients */
281 if ( (FT_UInt
)( char_code
- FTC_CMAP_NODE( node
)->first
>=
282 FTC_CMAP_INDICES_MAX
) )
283 return 0; /* XXX: should return appropriate error */
285 gindex
= FTC_CMAP_NODE( node
)->indices
[char_code
-
286 FTC_CMAP_NODE( node
)->first
];
287 if ( gindex
== FTC_CMAP_UNKNOWN
)
294 error
= FTC_Manager_LookupFace( cache
->manager
,
295 FTC_CMAP_NODE( node
)->face_id
,
300 if ( (FT_UInt
)cmap_index
< (FT_UInt
)face
->num_charmaps
)
302 FT_CharMap old
, cmap
= NULL
;
306 cmap
= face
->charmaps
[cmap_index
];
308 if ( old
!= cmap
&& !no_cmap_change
)
309 FT_Set_Charmap( face
, cmap
);
311 gindex
= FT_Get_Char_Index( face
, char_code
);
313 if ( old
!= cmap
&& !no_cmap_change
)
314 FT_Set_Charmap( face
, old
);
317 FTC_CMAP_NODE( node
)->indices
[char_code
-
318 FTC_CMAP_NODE( node
)->first
]