15060baf76a49cab708e391ff692fc03b5a280c4
[reactos.git] / reactos / lib / 3rdparty / freetype / src / cache / ftccmap.c
1 /***************************************************************************/
2 /* */
3 /* ftccmap.c */
4 /* */
5 /* FreeType CharMap cache (body) */
6 /* */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */
8 /* 2010 by */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* */
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. */
16 /* */
17 /***************************************************************************/
18
19
20 #include <ft2build.h>
21 #include FT_FREETYPE_H
22 #include FT_CACHE_H
23 #include "ftcmanag.h"
24 #include FT_INTERNAL_MEMORY_H
25 #include FT_INTERNAL_DEBUG_H
26
27 #include "ftccback.h"
28 #include "ftcerror.h"
29
30 #undef FT_COMPONENT
31 #define FT_COMPONENT trace_cache
32
33
34 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
35
36 typedef enum FTC_OldCMapType_
37 {
38 FTC_OLD_CMAP_BY_INDEX = 0,
39 FTC_OLD_CMAP_BY_ENCODING = 1,
40 FTC_OLD_CMAP_BY_ID = 2
41
42 } FTC_OldCMapType;
43
44
45 typedef struct FTC_OldCMapIdRec_
46 {
47 FT_UInt platform;
48 FT_UInt encoding;
49
50 } FTC_OldCMapIdRec, *FTC_OldCMapId;
51
52
53 typedef struct FTC_OldCMapDescRec_
54 {
55 FTC_FaceID face_id;
56 FTC_OldCMapType type;
57
58 union
59 {
60 FT_UInt index;
61 FT_Encoding encoding;
62 FTC_OldCMapIdRec id;
63
64 } u;
65
66 } FTC_OldCMapDescRec, *FTC_OldCMapDesc;
67
68 #endif /* FT_CONFIG_OLD_INTERNALS */
69
70
71 /*************************************************************************/
72 /* */
73 /* Each FTC_CMapNode contains a simple array to map a range of character */
74 /* codes to equivalent glyph indices. */
75 /* */
76 /* For now, the implementation is very basic: Each node maps a range of */
77 /* 128 consecutive character codes to their corresponding glyph indices. */
78 /* */
79 /* We could do more complex things, but I don't think it is really very */
80 /* useful. */
81 /* */
82 /*************************************************************************/
83
84
85 /* number of glyph indices / character code per node */
86 #define FTC_CMAP_INDICES_MAX 128
87
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 ) )
92
93 /* the charmap query */
94 typedef struct FTC_CMapQueryRec_
95 {
96 FTC_FaceID face_id;
97 FT_UInt cmap_index;
98 FT_UInt32 char_code;
99
100 } FTC_CMapQueryRec, *FTC_CMapQuery;
101
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 )
105
106 /* the cmap cache node */
107 typedef struct FTC_CMapNodeRec_
108 {
109 FTC_NodeRec node;
110 FTC_FaceID face_id;
111 FT_UInt cmap_index;
112 FT_UInt32 first; /* first character in node */
113 FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
114
115 } FTC_CMapNodeRec, *FTC_CMapNode;
116
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 )
120
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 )
124
125
126 /*************************************************************************/
127 /*************************************************************************/
128 /***** *****/
129 /***** CHARMAP NODES *****/
130 /***** *****/
131 /*************************************************************************/
132 /*************************************************************************/
133
134
135 FT_CALLBACK_DEF( void )
136 ftc_cmap_node_free( FTC_Node ftcnode,
137 FTC_Cache cache )
138 {
139 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
140 FT_Memory memory = cache->memory;
141
142
143 FT_FREE( node );
144 }
145
146
147 /* initialize a new cmap node */
148 FT_CALLBACK_DEF( FT_Error )
149 ftc_cmap_node_new( FTC_Node *ftcanode,
150 FT_Pointer ftcquery,
151 FTC_Cache cache )
152 {
153 FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode;
154 FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
155 FT_Error error;
156 FT_Memory memory = cache->memory;
157 FTC_CMapNode node = NULL;
158 FT_UInt nn;
159
160
161 if ( !FT_NEW( node ) )
162 {
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;
167
168 for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
169 node->indices[nn] = FTC_CMAP_UNKNOWN;
170 }
171
172 *anode = node;
173 return error;
174 }
175
176
177 /* compute the weight of a given cmap node */
178 FT_CALLBACK_DEF( FT_Offset )
179 ftc_cmap_node_weight( FTC_Node cnode,
180 FTC_Cache cache )
181 {
182 FT_UNUSED( cnode );
183 FT_UNUSED( cache );
184
185 return sizeof ( *cnode );
186 }
187
188
189 /* compare a cmap node to a given query */
190 FT_CALLBACK_DEF( FT_Bool )
191 ftc_cmap_node_compare( FTC_Node ftcnode,
192 FT_Pointer ftcquery,
193 FTC_Cache cache )
194 {
195 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
196 FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
197 FT_UNUSED( cache );
198
199
200 if ( node->face_id == query->face_id &&
201 node->cmap_index == query->cmap_index )
202 {
203 FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first );
204
205
206 return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
207 }
208
209 return 0;
210 }
211
212
213 FT_CALLBACK_DEF( FT_Bool )
214 ftc_cmap_node_remove_faceid( FTC_Node ftcnode,
215 FT_Pointer ftcface_id,
216 FTC_Cache cache )
217 {
218 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
219 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
220 FT_UNUSED( cache );
221
222 return FT_BOOL( node->face_id == face_id );
223 }
224
225
226 /*************************************************************************/
227 /*************************************************************************/
228 /***** *****/
229 /***** GLYPH IMAGE CACHE *****/
230 /***** *****/
231 /*************************************************************************/
232 /*************************************************************************/
233
234
235 FT_CALLBACK_TABLE_DEF
236 const FTC_CacheClassRec ftc_cmap_cache_class =
237 {
238 ftc_cmap_node_new,
239 ftc_cmap_node_weight,
240 ftc_cmap_node_compare,
241 ftc_cmap_node_remove_faceid,
242 ftc_cmap_node_free,
243
244 sizeof ( FTC_CacheRec ),
245 ftc_cache_init,
246 ftc_cache_done,
247 };
248
249
250 /* documentation is in ftcache.h */
251
252 FT_EXPORT_DEF( FT_Error )
253 FTC_CMapCache_New( FTC_Manager manager,
254 FTC_CMapCache *acache )
255 {
256 return FTC_Manager_RegisterCache( manager,
257 &ftc_cmap_cache_class,
258 FTC_CACHE_P( acache ) );
259 }
260
261
262 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
263
264 /*
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.
269 *
270 * On the other hand it seems that no production code is using this
271 * function on Unix distributions.
272 */
273
274 #endif
275
276
277 /* documentation is in ftcache.h */
278
279 FT_EXPORT_DEF( FT_UInt )
280 FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache,
281 FTC_FaceID face_id,
282 FT_Int cmap_index,
283 FT_UInt32 char_code )
284 {
285 FTC_Cache cache = FTC_CACHE( cmap_cache );
286 FTC_CMapQueryRec query;
287 FTC_Node node;
288 FT_Error error;
289 FT_UInt gindex = 0;
290 FT_PtrDist hash;
291 FT_Int no_cmap_change = 0;
292
293
294 if ( cmap_index < 0 )
295 {
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. */
300
301 no_cmap_change = 1;
302 cmap_index = 0;
303 }
304
305 if ( !cache )
306 {
307 FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
308 return 0;
309 }
310
311 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
312
313 /*
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.
317 */
318 if ( cmap_index > FT_MAX_CHARMAP_CACHEABLE && !no_cmap_change )
319 {
320 FTC_OldCMapDesc desc = (FTC_OldCMapDesc) face_id;
321
322
323 char_code = (FT_UInt32)cmap_index;
324 query.face_id = desc->face_id;
325
326
327 switch ( desc->type )
328 {
329 case FTC_OLD_CMAP_BY_INDEX:
330 query.cmap_index = desc->u.index;
331 query.char_code = (FT_UInt32)cmap_index;
332 break;
333
334 case FTC_OLD_CMAP_BY_ENCODING:
335 {
336 FT_Face face;
337
338
339 error = FTC_Manager_LookupFace( cache->manager, desc->face_id,
340 &face );
341 if ( error )
342 return 0;
343
344 FT_Select_Charmap( face, desc->u.encoding );
345
346 return FT_Get_Char_Index( face, char_code );
347 }
348
349 default:
350 return 0;
351 }
352 }
353 else
354
355 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
356
357 {
358 query.face_id = face_id;
359 query.cmap_index = (FT_UInt)cmap_index;
360 query.char_code = char_code;
361 }
362
363 hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
364
365 #if 1
366 FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
367 node, error );
368 #else
369 error = FTC_Cache_Lookup( cache, hash, &query, &node );
370 #endif
371 if ( error )
372 goto Exit;
373
374 FT_ASSERT( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first ) <
375 FTC_CMAP_INDICES_MAX );
376
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 */
381
382 gindex = FTC_CMAP_NODE( node )->indices[char_code -
383 FTC_CMAP_NODE( node )->first];
384 if ( gindex == FTC_CMAP_UNKNOWN )
385 {
386 FT_Face face;
387
388
389 gindex = 0;
390
391 error = FTC_Manager_LookupFace( cache->manager,
392 FTC_CMAP_NODE( node )->face_id,
393 &face );
394 if ( error )
395 goto Exit;
396
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 */
401 #endif
402
403 if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
404 {
405 FT_CharMap old, cmap = NULL;
406
407
408 old = face->charmap;
409 cmap = face->charmaps[cmap_index];
410
411 if ( old != cmap && !no_cmap_change )
412 FT_Set_Charmap( face, cmap );
413
414 gindex = FT_Get_Char_Index( face, char_code );
415
416 if ( old != cmap && !no_cmap_change )
417 FT_Set_Charmap( face, old );
418 }
419
420 FTC_CMAP_NODE( node )->indices[char_code -
421 FTC_CMAP_NODE( node )->first]
422 = (FT_UShort)gindex;
423 }
424
425 Exit:
426 return gindex;
427 }
428
429
430 /* END */