Merge 25584, 25588.
[reactos.git] / reactos / dll / 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 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
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. */
15 /* */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_FREETYPE_H
21 #include FT_CACHE_H
22 #include "ftcmanag.h"
23 #include FT_INTERNAL_MEMORY_H
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_TRUETYPE_IDS_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 ( (char_code) / 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;
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_ULong )
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_CMapNode node;
288 FT_Error error;
289 FT_UInt gindex = 0;
290 FT_UInt32 hash;
291
292
293 if ( !cache )
294 {
295 FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
296 return 0;
297 }
298
299 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
300
301 /*
302 * Detect a call from a rogue client that thinks it is linking
303 * to FreeType 2.1.7. This is possible because the third parameter
304 * is then a character code, and we have never seen any font with
305 * more than a few charmaps, so if the index is very large...
306 *
307 * It is also very unlikely that a rogue client is interested
308 * in Unicode values 0 to 15.
309 *
310 * NOTE: The original threshold was 4, but we found a font from the
311 * Adobe Acrobat Reader Pack, named `KozMinProVI-Regular.otf',
312 * which contains more than 5 charmaps.
313 */
314 if ( cmap_index >= 16 )
315 {
316 FTC_OldCMapDesc desc = (FTC_OldCMapDesc) face_id;
317
318
319 char_code = (FT_UInt32)cmap_index;
320 query.face_id = desc->face_id;
321
322
323 switch ( desc->type )
324 {
325 case FTC_OLD_CMAP_BY_INDEX:
326 query.cmap_index = desc->u.index;
327 query.char_code = (FT_UInt32)cmap_index;
328 break;
329
330 case FTC_OLD_CMAP_BY_ENCODING:
331 {
332 FT_Face face;
333
334
335 error = FTC_Manager_LookupFace( cache->manager, desc->face_id,
336 &face );
337 if ( error )
338 return 0;
339
340 FT_Select_Charmap( face, desc->u.encoding );
341
342 return FT_Get_Char_Index( face, char_code );
343 }
344 break;
345
346 default:
347 return 0;
348 }
349 }
350 else
351
352 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
353
354 {
355 query.face_id = face_id;
356 query.cmap_index = (FT_UInt)cmap_index;
357 query.char_code = char_code;
358 }
359
360 hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
361
362 #if 1
363 FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
364 node, error );
365 #else
366 error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node );
367 #endif
368 if ( error )
369 goto Exit;
370
371 FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX );
372
373 /* something rotten can happen with rogue clients */
374 if ( (FT_UInt)( char_code - node->first >= FTC_CMAP_INDICES_MAX ) )
375 return 0;
376
377 gindex = node->indices[char_code - node->first];
378 if ( gindex == FTC_CMAP_UNKNOWN )
379 {
380 FT_Face face;
381
382
383 gindex = 0;
384
385 error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face );
386 if ( error )
387 goto Exit;
388
389 if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
390 {
391 FT_CharMap old, cmap = NULL;
392
393
394 old = face->charmap;
395 cmap = face->charmaps[cmap_index];
396
397 if ( old != cmap )
398 FT_Set_Charmap( face, cmap );
399
400 gindex = FT_Get_Char_Index( face, char_code );
401
402 if ( old != cmap )
403 FT_Set_Charmap( face, old );
404 }
405
406 node->indices[char_code - node->first] = (FT_UShort)gindex;
407 }
408
409 Exit:
410 return gindex;
411 }
412
413
414 /* END */