41a0ce97dd729937a692b15132bfa62d36a31a30
[reactos.git] / reactos / sdk / lib / 3rdparty / freetype / src / cache / ftccmap.c
1 /***************************************************************************/
2 /* */
3 /* ftccmap.c */
4 /* */
5 /* FreeType CharMap cache (body) */
6 /* */
7 /* Copyright 2000-2016 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_OBJECTS_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 /*************************************************************************/
35 /* */
36 /* Each FTC_CMapNode contains a simple array to map a range of character */
37 /* codes to equivalent glyph indices. */
38 /* */
39 /* For now, the implementation is very basic: Each node maps a range of */
40 /* 128 consecutive character codes to their corresponding glyph indices. */
41 /* */
42 /* We could do more complex things, but I don't think it is really very */
43 /* useful. */
44 /* */
45 /*************************************************************************/
46
47
48 /* number of glyph indices / character code per node */
49 #define FTC_CMAP_INDICES_MAX 128
50
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 ) )
55
56 /* the charmap query */
57 typedef struct FTC_CMapQueryRec_
58 {
59 FTC_FaceID face_id;
60 FT_UInt cmap_index;
61 FT_UInt32 char_code;
62
63 } FTC_CMapQueryRec, *FTC_CMapQuery;
64
65 #define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x))
66
67 /* the cmap cache node */
68 typedef struct FTC_CMapNodeRec_
69 {
70 FTC_NodeRec node;
71 FTC_FaceID face_id;
72 FT_UInt cmap_index;
73 FT_UInt32 first; /* first character in node */
74 FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
75
76 } FTC_CMapNodeRec, *FTC_CMapNode;
77
78 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
79
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
83
84
85 /*************************************************************************/
86 /*************************************************************************/
87 /***** *****/
88 /***** CHARMAP NODES *****/
89 /***** *****/
90 /*************************************************************************/
91 /*************************************************************************/
92
93
94 FT_CALLBACK_DEF( void )
95 ftc_cmap_node_free( FTC_Node ftcnode,
96 FTC_Cache cache )
97 {
98 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
99 FT_Memory memory = cache->memory;
100
101
102 FT_FREE( node );
103 }
104
105
106 /* initialize a new cmap node */
107 FT_CALLBACK_DEF( FT_Error )
108 ftc_cmap_node_new( FTC_Node *ftcanode,
109 FT_Pointer ftcquery,
110 FTC_Cache cache )
111 {
112 FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode;
113 FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
114 FT_Error error;
115 FT_Memory memory = cache->memory;
116 FTC_CMapNode node = NULL;
117 FT_UInt nn;
118
119
120 if ( !FT_NEW( node ) )
121 {
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;
126
127 for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
128 node->indices[nn] = FTC_CMAP_UNKNOWN;
129 }
130
131 *anode = node;
132 return error;
133 }
134
135
136 /* compute the weight of a given cmap node */
137 FT_CALLBACK_DEF( FT_Offset )
138 ftc_cmap_node_weight( FTC_Node cnode,
139 FTC_Cache cache )
140 {
141 FT_UNUSED( cnode );
142 FT_UNUSED( cache );
143
144 return sizeof ( *cnode );
145 }
146
147
148 /* compare a cmap node to a given query */
149 FT_CALLBACK_DEF( FT_Bool )
150 ftc_cmap_node_compare( FTC_Node ftcnode,
151 FT_Pointer ftcquery,
152 FTC_Cache cache,
153 FT_Bool* list_changed )
154 {
155 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
156 FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
157 FT_UNUSED( cache );
158
159
160 if ( list_changed )
161 *list_changed = FALSE;
162 if ( node->face_id == query->face_id &&
163 node->cmap_index == query->cmap_index )
164 {
165 FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first );
166
167
168 return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
169 }
170
171 return 0;
172 }
173
174
175 FT_CALLBACK_DEF( FT_Bool )
176 ftc_cmap_node_remove_faceid( FTC_Node ftcnode,
177 FT_Pointer ftcface_id,
178 FTC_Cache cache,
179 FT_Bool* list_changed )
180 {
181 FTC_CMapNode node = (FTC_CMapNode)ftcnode;
182 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
183 FT_UNUSED( cache );
184
185
186 if ( list_changed )
187 *list_changed = FALSE;
188 return FT_BOOL( node->face_id == face_id );
189 }
190
191
192 /*************************************************************************/
193 /*************************************************************************/
194 /***** *****/
195 /***** GLYPH IMAGE CACHE *****/
196 /***** *****/
197 /*************************************************************************/
198 /*************************************************************************/
199
200
201 static
202 const FTC_CacheClassRec ftc_cmap_cache_class =
203 {
204 ftc_cmap_node_new,
205 ftc_cmap_node_weight,
206 ftc_cmap_node_compare,
207 ftc_cmap_node_remove_faceid,
208 ftc_cmap_node_free,
209
210 sizeof ( FTC_CacheRec ),
211 ftc_cache_init,
212 ftc_cache_done,
213 };
214
215
216 /* documentation is in ftcache.h */
217
218 FT_EXPORT_DEF( FT_Error )
219 FTC_CMapCache_New( FTC_Manager manager,
220 FTC_CMapCache *acache )
221 {
222 return FTC_Manager_RegisterCache( manager,
223 &ftc_cmap_cache_class,
224 FTC_CACHE_P( acache ) );
225 }
226
227
228 /* documentation is in ftcache.h */
229
230 FT_EXPORT_DEF( FT_UInt )
231 FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache,
232 FTC_FaceID face_id,
233 FT_Int cmap_index,
234 FT_UInt32 char_code )
235 {
236 FTC_Cache cache = FTC_CACHE( cmap_cache );
237 FTC_CMapQueryRec query;
238 FTC_Node node;
239 FT_Error error;
240 FT_UInt gindex = 0;
241 FT_Offset hash;
242 FT_Int no_cmap_change = 0;
243
244
245 if ( cmap_index < 0 )
246 {
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. */
251
252 no_cmap_change = 1;
253 cmap_index = 0;
254 }
255
256 if ( !cache )
257 {
258 FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
259 return 0;
260 }
261
262 query.face_id = face_id;
263 query.cmap_index = (FT_UInt)cmap_index;
264 query.char_code = char_code;
265
266 hash = FTC_CMAP_HASH( face_id, (FT_UInt)cmap_index, char_code );
267
268 #if 1
269 FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
270 node, error );
271 #else
272 error = FTC_Cache_Lookup( cache, hash, &query, &node );
273 #endif
274 if ( error )
275 goto Exit;
276
277 FT_ASSERT( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first ) <
278 FTC_CMAP_INDICES_MAX );
279
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 */
284
285 gindex = FTC_CMAP_NODE( node )->indices[char_code -
286 FTC_CMAP_NODE( node )->first];
287 if ( gindex == FTC_CMAP_UNKNOWN )
288 {
289 FT_Face face;
290
291
292 gindex = 0;
293
294 error = FTC_Manager_LookupFace( cache->manager,
295 FTC_CMAP_NODE( node )->face_id,
296 &face );
297 if ( error )
298 goto Exit;
299
300 if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
301 {
302 FT_CharMap old, cmap = NULL;
303
304
305 old = face->charmap;
306 cmap = face->charmaps[cmap_index];
307
308 if ( old != cmap && !no_cmap_change )
309 FT_Set_Charmap( face, cmap );
310
311 gindex = FT_Get_Char_Index( face, char_code );
312
313 if ( old != cmap && !no_cmap_change )
314 FT_Set_Charmap( face, old );
315 }
316
317 FTC_CMAP_NODE( node )->indices[char_code -
318 FTC_CMAP_NODE( node )->first]
319 = (FT_UShort)gindex;
320 }
321
322 Exit:
323 return gindex;
324 }
325
326
327 /* END */