xref: /inferno-os/libfreetype/ftccmap.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftccmap.c                                                              */
4 /*                                                                         */
5 /*    FreeType CharMap cache (body)                                        */
6 /*                                                                         */
7 /*  Copyright 2000-2001, 2002 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 FT_CACHE_CHARMAP_H
23 #include FT_CACHE_MANAGER_H
24 #include FT_INTERNAL_MEMORY_H
25 #include FT_INTERNAL_DEBUG_H
26 
27 #include "ftcerror.h"
28 
29   /*************************************************************************/
30   /*                                                                       */
31   /* Each FTC_CMapNode contains a simple array to map a range of character */
32   /* codes to equivalent glyph indices.                                    */
33   /*                                                                       */
34   /* For now, the implementation is very basic: Each node maps a range of  */
35   /* 128 consecutive character codes to their corresponding glyph indices. */
36   /*                                                                       */
37   /* We could do more complex things, but I don't think it is really very  */
38   /* useful.                                                               */
39   /*                                                                       */
40   /*************************************************************************/
41 
42 
43   /* number of glyph indices / character code per node */
44 #define FTC_CMAP_INDICES_MAX  128
45 
46 
47   typedef struct  FTC_CMapNodeRec_
48   {
49     FTC_NodeRec  node;
50     FT_UInt32    first;                         /* first character in node */
51     FT_UInt16    indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices  */
52 
53   } FTC_CMapNodeRec, *FTC_CMapNode;
54 
55 
56 #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
57 
58 
59   /* compute node hash value from cmap family and "requested" glyph index */
60 #define FTC_CMAP_HASH( cfam, cquery )                                       \
61           ( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) )
62 
63   /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
64   /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet   */
65 #define FTC_CMAP_UNKNOWN  ( (FT_UInt16)-1 )
66 
67 
68   /* the charmap query */
69   typedef struct  FTC_CMapQueryRec_
70   {
71     FTC_QueryRec  query;
72     FTC_CMapDesc  desc;
73     FT_UInt32     char_code;
74 
75   } FTC_CMapQueryRec, *FTC_CMapQuery;
76 
77 
78 #define FTC_CMAP_QUERY( x )  ( (FTC_CMapQuery)( x ) )
79 
80 
81   /* the charmap family */
82   typedef struct FTC_CMapFamilyRec_
83   {
84     FTC_FamilyRec    family;
85     FT_UInt32        hash;
86     FTC_CMapDescRec  desc;
87     FT_UInt          index;
88 
89   } FTC_CMapFamilyRec, *FTC_CMapFamily;
90 
91 
92 #define FTC_CMAP_FAMILY( x )         ( (FTC_CMapFamily)( x ) )
93 #define FTC_CMAP_FAMILY_MEMORY( x )  FTC_FAMILY( x )->memory
94 
95 
96   /*************************************************************************/
97   /*************************************************************************/
98   /*****                                                               *****/
99   /*****                        CHARMAP NODES                          *****/
100   /*****                                                               *****/
101   /*************************************************************************/
102   /*************************************************************************/
103 
104 
105   /* no need for specific finalizer; we use "ftc_node_done" directly */
106 
107   /* initialize a new cmap node */
108   FT_CALLBACK_DEF( FT_Error )
ftc_cmap_node_init(FTC_CMapNode cnode,FTC_CMapQuery cquery,FTC_Cache cache)109   ftc_cmap_node_init( FTC_CMapNode   cnode,
110                       FTC_CMapQuery  cquery,
111                       FTC_Cache      cache )
112   {
113     FT_UInt32  first;
114     FT_UInt    n;
115     FT_UNUSED( cache );
116 
117 
118     first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) *
119             FTC_CMAP_INDICES_MAX;
120 
121     cnode->first = first;
122     for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
123       cnode->indices[n] = FTC_CMAP_UNKNOWN;
124 
125     return 0;
126   }
127 
128 
129   /* compute the weight of a given cmap node */
130   FT_CALLBACK_DEF( FT_ULong )
ftc_cmap_node_weight(FTC_CMapNode cnode)131   ftc_cmap_node_weight( FTC_CMapNode  cnode )
132   {
133     FT_UNUSED( cnode );
134 
135     return sizeof ( *cnode );
136   }
137 
138 
139   /* compare a cmap node to a given query */
140   FT_CALLBACK_DEF( FT_Bool )
ftc_cmap_node_compare(FTC_CMapNode cnode,FTC_CMapQuery cquery)141   ftc_cmap_node_compare( FTC_CMapNode   cnode,
142                          FTC_CMapQuery  cquery )
143   {
144     FT_UInt32  offset = (FT_UInt32)( cquery->char_code - cnode->first );
145 
146 
147     return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
148   }
149 
150 
151   /*************************************************************************/
152   /*************************************************************************/
153   /*****                                                               *****/
154   /*****                    CHARMAP FAMILY                             *****/
155   /*****                                                               *****/
156   /*************************************************************************/
157   /*************************************************************************/
158 
159 
160   FT_CALLBACK_DEF( FT_Error )
ftc_cmap_family_init(FTC_CMapFamily cfam,FTC_CMapQuery cquery,FTC_Cache cache)161   ftc_cmap_family_init( FTC_CMapFamily  cfam,
162                         FTC_CMapQuery   cquery,
163                         FTC_Cache       cache )
164   {
165     FTC_Manager   manager = cache->manager;
166     FTC_CMapDesc  desc = cquery->desc;
167     FT_UInt32     hash = 0;
168     FT_Error      error;
169     FT_Face       face;
170 
171 
172     /* setup charmap descriptor */
173     cfam->desc = *desc;
174 
175     /* let's see whether the rest is correct too */
176     error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face );
177     if ( !error )
178     {
179       FT_UInt      count = face->num_charmaps;
180       FT_UInt      idx   = count;
181       FT_CharMap*  cur   = face->charmaps;
182 
183 
184       switch ( desc->type )
185       {
186       case FTC_CMAP_BY_INDEX:
187         idx  = desc->u.index;
188         hash = idx * 33;
189         break;
190 
191       case FTC_CMAP_BY_ENCODING:
192         for ( idx = 0; idx < count; idx++, cur++ )
193           if ( cur[0]->encoding == desc->u.encoding )
194             break;
195 
196         hash = idx * 67;
197         break;
198 
199       case FTC_CMAP_BY_ID:
200         for ( idx = 0; idx < count; idx++, cur++ )
201         {
202           if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform &&
203                (FT_UInt)cur[0]->encoding_id == desc->u.id.encoding )
204           {
205             hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7;
206             break;
207           }
208         }
209         break;
210 
211       default:
212         ;
213       }
214 
215       if ( idx >= count )
216         goto Bad_Descriptor;
217 
218       /* compute hash value, both in family and query */
219       cfam->index               = idx;
220       cfam->hash                = hash ^ FTC_FACE_ID_HASH( desc->face_id );
221       FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
222 
223       error = ftc_family_init( FTC_FAMILY( cfam ),
224                                FTC_QUERY( cquery ), cache );
225     }
226 
227     return error;
228 
229   Bad_Descriptor:
230     FT_ERROR(( "ftp_cmap_family_init: invalid charmap descriptor\n" ));
231     return FTC_Err_Invalid_Argument;
232   }
233 
234 
235   FT_CALLBACK_DEF( FT_Bool )
ftc_cmap_family_compare(FTC_CMapFamily cfam,FTC_CMapQuery cquery)236   ftc_cmap_family_compare( FTC_CMapFamily  cfam,
237                            FTC_CMapQuery   cquery )
238   {
239     FT_Int  result = 0;
240 
241 
242     /* first, compare face id and type */
243     if ( cfam->desc.face_id != cquery->desc->face_id ||
244          cfam->desc.type    != cquery->desc->type    )
245       goto Exit;
246 
247     switch ( cfam->desc.type )
248     {
249     case FTC_CMAP_BY_INDEX:
250       result = ( cfam->desc.u.index == cquery->desc->u.index );
251       break;
252 
253     case FTC_CMAP_BY_ENCODING:
254       result = ( cfam->desc.u.encoding == cquery->desc->u.encoding );
255       break;
256 
257     case FTC_CMAP_BY_ID:
258       result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform &&
259                  cfam->desc.u.id.encoding == cquery->desc->u.id.encoding );
260       break;
261 
262     default:
263       ;
264     }
265 
266     if ( result )
267     {
268       /* when found, update the 'family' and 'hash' field of the query */
269       FTC_QUERY( cquery )->family = FTC_FAMILY( cfam );
270       FTC_QUERY( cquery )->hash   = FTC_CMAP_HASH( cfam, cquery );
271     }
272 
273   Exit:
274     return FT_BOOL( result );
275   }
276 
277 
278   /*************************************************************************/
279   /*************************************************************************/
280   /*****                                                               *****/
281   /*****                    GLYPH IMAGE CACHE                          *****/
282   /*****                                                               *****/
283   /*************************************************************************/
284   /*************************************************************************/
285 
286 
287   FT_CALLBACK_TABLE_DEF
288   const FTC_Cache_ClassRec  ftc_cmap_cache_class =
289   {
290     sizeof ( FTC_CacheRec ),
291     (FTC_Cache_InitFunc) ftc_cache_init,
292     (FTC_Cache_ClearFunc)ftc_cache_clear,
293     (FTC_Cache_DoneFunc) ftc_cache_done,
294 
295     sizeof ( FTC_CMapFamilyRec ),
296     (FTC_Family_InitFunc)   ftc_cmap_family_init,
297     (FTC_Family_CompareFunc)ftc_cmap_family_compare,
298     (FTC_Family_DoneFunc)   ftc_family_done,
299 
300     sizeof ( FTC_CMapNodeRec ),
301     (FTC_Node_InitFunc)   ftc_cmap_node_init,
302     (FTC_Node_WeightFunc) ftc_cmap_node_weight,
303     (FTC_Node_CompareFunc)ftc_cmap_node_compare,
304     (FTC_Node_DoneFunc)   ftc_node_done
305   };
306 
307 
308   /* documentation is in ftccmap.h */
309 
310   FT_EXPORT_DEF( FT_Error )
FTC_CMapCache_New(FTC_Manager manager,FTC_CMapCache * acache)311   FTC_CMapCache_New( FTC_Manager     manager,
312                      FTC_CMapCache  *acache )
313   {
314     return FTC_Manager_Register_Cache(
315              manager,
316              (FTC_Cache_Class)&ftc_cmap_cache_class,
317              FTC_CACHE_P( acache ) );
318   }
319 
320 
321 #ifdef FTC_CACHE_USE_INLINE
322 
323 #define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
324           ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) )
325 
326 #define GEN_CACHE_NODE_COMPARE( n, q, c ) \
327           ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) )
328 
329 #define GEN_CACHE_LOOKUP  ftc_cmap_cache_lookup
330 
331 #include "ftccache.i"
332 
333 #else  /* !FTC_CACHE_USE_INLINE */
334 
335 #define ftc_cmap_cache_lookup  ftc_cache_lookup
336 
337 #endif /* !FTC_CACHE_USE_INLINE */
338 
339 
340   /* documentation is in ftccmap.h */
341 
342   FT_EXPORT_DEF( FT_UInt )
FTC_CMapCache_Lookup(FTC_CMapCache cache,FTC_CMapDesc desc,FT_UInt32 char_code)343   FTC_CMapCache_Lookup( FTC_CMapCache  cache,
344                         FTC_CMapDesc   desc,
345                         FT_UInt32      char_code )
346   {
347     FTC_CMapQueryRec  cquery;
348     FTC_CMapNode      node;
349     FT_Error          error;
350     FT_UInt           gindex = 0;
351 
352 
353     if ( !cache || !desc )
354     {
355       FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
356       return 0;
357     }
358 
359     cquery.desc      = desc;
360     cquery.char_code = char_code;
361 
362     error = ftc_cmap_cache_lookup( FTC_CACHE( cache ),
363                                    FTC_QUERY( &cquery ),
364                                    (FTC_Node*)&node );
365     if ( !error )
366     {
367       FT_UInt  offset = (FT_UInt)( char_code - node->first );
368 
369 
370       FT_ASSERT( offset < FTC_CMAP_INDICES_MAX );
371 
372       gindex = node->indices[offset];
373       if ( gindex == FTC_CMAP_UNKNOWN )
374       {
375         FT_Face  face;
376 
377 
378         /* we need to use FT_Get_Char_Index */
379         gindex = 0;
380 
381         error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager,
382                                          desc->face_id,
383                                          &face );
384         if ( !error )
385         {
386           FT_CharMap  old, cmap  = NULL;
387           FT_UInt     cmap_index;
388 
389 
390           /* save old charmap, select new one */
391           old        = face->charmap;
392           cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index;
393           cmap       = face->charmaps[cmap_index];
394 
395           FT_Set_Charmap( face, cmap );
396 
397           /* perform lookup */
398           gindex                = FT_Get_Char_Index( face, char_code );
399           node->indices[offset] = (FT_UInt16)gindex;
400 
401           /* restore old charmap */
402           FT_Set_Charmap( face, old );
403         }
404       }
405     }
406 
407     return gindex;
408   }
409 
410 
411 /* END */
412