ftccmap.c 13 KB

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