/modules/freetype2/src/cache/ftccmap.c

http://github.com/zpao/v8monkey · C · 430 lines · 249 code · 106 blank · 75 comment · 25 complexity · 2835e7f54b7ddf52e7b85d7a451731d5 MD5 · raw file

  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. #include <ft2build.h>
  19. #include FT_FREETYPE_H
  20. #include FT_CACHE_H
  21. #include "ftcmanag.h"
  22. #include FT_INTERNAL_MEMORY_H
  23. #include FT_INTERNAL_DEBUG_H
  24. #include "ftccback.h"
  25. #include "ftcerror.h"
  26. #undef FT_COMPONENT
  27. #define FT_COMPONENT trace_cache
  28. #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
  29. typedef enum FTC_OldCMapType_
  30. {
  31. FTC_OLD_CMAP_BY_INDEX = 0,
  32. FTC_OLD_CMAP_BY_ENCODING = 1,
  33. FTC_OLD_CMAP_BY_ID = 2
  34. } FTC_OldCMapType;
  35. typedef struct FTC_OldCMapIdRec_
  36. {
  37. FT_UInt platform;
  38. FT_UInt encoding;
  39. } FTC_OldCMapIdRec, *FTC_OldCMapId;
  40. typedef struct FTC_OldCMapDescRec_
  41. {
  42. FTC_FaceID face_id;
  43. FTC_OldCMapType type;
  44. union
  45. {
  46. FT_UInt index;
  47. FT_Encoding encoding;
  48. FTC_OldCMapIdRec id;
  49. } u;
  50. } FTC_OldCMapDescRec, *FTC_OldCMapDesc;
  51. #endif /* FT_CONFIG_OLD_INTERNALS */
  52. /*************************************************************************/
  53. /* */
  54. /* Each FTC_CMapNode contains a simple array to map a range of character */
  55. /* codes to equivalent glyph indices. */
  56. /* */
  57. /* For now, the implementation is very basic: Each node maps a range of */
  58. /* 128 consecutive character codes to their corresponding glyph indices. */
  59. /* */
  60. /* We could do more complex things, but I don't think it is really very */
  61. /* useful. */
  62. /* */
  63. /*************************************************************************/
  64. /* number of glyph indices / character code per node */
  65. #define FTC_CMAP_INDICES_MAX 128
  66. /* compute a query/node hash */
  67. #define FTC_CMAP_HASH( faceid, index, charcode ) \
  68. ( FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \
  69. ( (charcode) / FTC_CMAP_INDICES_MAX ) )
  70. /* the charmap query */
  71. typedef struct FTC_CMapQueryRec_
  72. {
  73. FTC_FaceID face_id;
  74. FT_UInt cmap_index;
  75. FT_UInt32 char_code;
  76. } FTC_CMapQueryRec, *FTC_CMapQuery;
  77. #define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x))
  78. #define FTC_CMAP_QUERY_HASH( x ) \
  79. FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code )
  80. /* the cmap cache node */
  81. typedef struct FTC_CMapNodeRec_
  82. {
  83. FTC_NodeRec node;
  84. FTC_FaceID face_id;
  85. FT_UInt cmap_index;
  86. FT_UInt32 first; /* first character in node */
  87. FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
  88. } FTC_CMapNodeRec, *FTC_CMapNode;
  89. #define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
  90. #define FTC_CMAP_NODE_HASH( x ) \
  91. FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first )
  92. /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
  93. /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
  94. #define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 )
  95. /*************************************************************************/
  96. /*************************************************************************/
  97. /***** *****/
  98. /***** CHARMAP NODES *****/
  99. /***** *****/
  100. /*************************************************************************/
  101. /*************************************************************************/
  102. FT_CALLBACK_DEF( void )
  103. ftc_cmap_node_free( FTC_Node ftcnode,
  104. FTC_Cache cache )
  105. {
  106. FTC_CMapNode node = (FTC_CMapNode)ftcnode;
  107. FT_Memory memory = cache->memory;
  108. FT_FREE( node );
  109. }
  110. /* initialize a new cmap node */
  111. FT_CALLBACK_DEF( FT_Error )
  112. ftc_cmap_node_new( FTC_Node *ftcanode,
  113. FT_Pointer ftcquery,
  114. FTC_Cache cache )
  115. {
  116. FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode;
  117. FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
  118. FT_Error error;
  119. FT_Memory memory = cache->memory;
  120. FTC_CMapNode node = NULL;
  121. FT_UInt nn;
  122. if ( !FT_NEW( node ) )
  123. {
  124. node->face_id = query->face_id;
  125. node->cmap_index = query->cmap_index;
  126. node->first = (query->char_code / FTC_CMAP_INDICES_MAX) *
  127. FTC_CMAP_INDICES_MAX;
  128. for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
  129. node->indices[nn] = FTC_CMAP_UNKNOWN;
  130. }
  131. *anode = node;
  132. return error;
  133. }
  134. /* compute the weight of a given cmap node */
  135. FT_CALLBACK_DEF( FT_Offset )
  136. ftc_cmap_node_weight( FTC_Node cnode,
  137. FTC_Cache cache )
  138. {
  139. FT_UNUSED( cnode );
  140. FT_UNUSED( cache );
  141. return sizeof ( *cnode );
  142. }
  143. /* compare a cmap node to a given query */
  144. FT_CALLBACK_DEF( FT_Bool )
  145. ftc_cmap_node_compare( FTC_Node ftcnode,
  146. FT_Pointer ftcquery,
  147. FTC_Cache cache )
  148. {
  149. FTC_CMapNode node = (FTC_CMapNode)ftcnode;
  150. FTC_CMapQuery query = (FTC_CMapQuery)ftcquery;
  151. FT_UNUSED( cache );
  152. if ( node->face_id == query->face_id &&
  153. node->cmap_index == query->cmap_index )
  154. {
  155. FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first );
  156. return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
  157. }
  158. return 0;
  159. }
  160. FT_CALLBACK_DEF( FT_Bool )
  161. ftc_cmap_node_remove_faceid( FTC_Node ftcnode,
  162. FT_Pointer ftcface_id,
  163. FTC_Cache cache )
  164. {
  165. FTC_CMapNode node = (FTC_CMapNode)ftcnode;
  166. FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
  167. FT_UNUSED( cache );
  168. return FT_BOOL( node->face_id == face_id );
  169. }
  170. /*************************************************************************/
  171. /*************************************************************************/
  172. /***** *****/
  173. /***** GLYPH IMAGE CACHE *****/
  174. /***** *****/
  175. /*************************************************************************/
  176. /*************************************************************************/
  177. FT_CALLBACK_TABLE_DEF
  178. const FTC_CacheClassRec ftc_cmap_cache_class =
  179. {
  180. ftc_cmap_node_new,
  181. ftc_cmap_node_weight,
  182. ftc_cmap_node_compare,
  183. ftc_cmap_node_remove_faceid,
  184. ftc_cmap_node_free,
  185. sizeof ( FTC_CacheRec ),
  186. ftc_cache_init,
  187. ftc_cache_done,
  188. };
  189. /* documentation is in ftcache.h */
  190. FT_EXPORT_DEF( FT_Error )
  191. FTC_CMapCache_New( FTC_Manager manager,
  192. FTC_CMapCache *acache )
  193. {
  194. return FTC_Manager_RegisterCache( manager,
  195. &ftc_cmap_cache_class,
  196. FTC_CACHE_P( acache ) );
  197. }
  198. #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
  199. /*
  200. * Unfortunately, it is not possible to support binary backwards
  201. * compatibility in the cmap cache. The FTC_CMapCache_Lookup signature
  202. * changes were too deep, and there is no clever hackish way to detect
  203. * what kind of structure we are being passed.
  204. *
  205. * On the other hand it seems that no production code is using this
  206. * function on Unix distributions.
  207. */
  208. #endif
  209. /* documentation is in ftcache.h */
  210. FT_EXPORT_DEF( FT_UInt )
  211. FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache,
  212. FTC_FaceID face_id,
  213. FT_Int cmap_index,
  214. FT_UInt32 char_code )
  215. {
  216. FTC_Cache cache = FTC_CACHE( cmap_cache );
  217. FTC_CMapQueryRec query;
  218. FTC_Node node;
  219. FT_Error error;
  220. FT_UInt gindex = 0;
  221. FT_UInt32 hash;
  222. FT_Int no_cmap_change = 0;
  223. if ( cmap_index < 0 )
  224. {
  225. /* Treat a negative cmap index as a special value, meaning that you */
  226. /* don't want to change the FT_Face's character map through this */
  227. /* call. This can be useful if the face requester callback already */
  228. /* sets the face's charmap to the appropriate value. */
  229. no_cmap_change = 1;
  230. cmap_index = 0;
  231. }
  232. if ( !cache )
  233. {
  234. FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" ));
  235. return 0;
  236. }
  237. #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
  238. /*
  239. * If cmap_index is greater than the maximum number of cachable
  240. * charmaps, we assume the request is from a legacy rogue client
  241. * using old internal header. See include/config/ftoption.h.
  242. */
  243. if ( cmap_index > FT_MAX_CHARMAP_CACHEABLE && !no_cmap_change )
  244. {
  245. FTC_OldCMapDesc desc = (FTC_OldCMapDesc) face_id;
  246. char_code = (FT_UInt32)cmap_index;
  247. query.face_id = desc->face_id;
  248. switch ( desc->type )
  249. {
  250. case FTC_OLD_CMAP_BY_INDEX:
  251. query.cmap_index = desc->u.index;
  252. query.char_code = (FT_UInt32)cmap_index;
  253. break;
  254. case FTC_OLD_CMAP_BY_ENCODING:
  255. {
  256. FT_Face face;
  257. error = FTC_Manager_LookupFace( cache->manager, desc->face_id,
  258. &face );
  259. if ( error )
  260. return 0;
  261. FT_Select_Charmap( face, desc->u.encoding );
  262. return FT_Get_Char_Index( face, char_code );
  263. }
  264. default:
  265. return 0;
  266. }
  267. }
  268. else
  269. #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
  270. {
  271. query.face_id = face_id;
  272. query.cmap_index = (FT_UInt)cmap_index;
  273. query.char_code = char_code;
  274. }
  275. hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
  276. #if 1
  277. FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
  278. node, error );
  279. #else
  280. error = FTC_Cache_Lookup( cache, hash, &query, &node );
  281. #endif
  282. if ( error )
  283. goto Exit;
  284. FT_ASSERT( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first ) <
  285. FTC_CMAP_INDICES_MAX );
  286. /* something rotten can happen with rogue clients */
  287. if ( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first >=
  288. FTC_CMAP_INDICES_MAX ) )
  289. return 0; /* XXX: should return appropriate error */
  290. gindex = FTC_CMAP_NODE( node )->indices[char_code -
  291. FTC_CMAP_NODE( node )->first];
  292. if ( gindex == FTC_CMAP_UNKNOWN )
  293. {
  294. FT_Face face;
  295. gindex = 0;
  296. error = FTC_Manager_LookupFace( cache->manager,
  297. FTC_CMAP_NODE( node )->face_id,
  298. &face );
  299. if ( error )
  300. goto Exit;
  301. #ifdef FT_MAX_CHARMAP_CACHEABLE
  302. /* something rotten can happen with rogue clients */
  303. if ( cmap_index > FT_MAX_CHARMAP_CACHEABLE )
  304. return 0; /* XXX: should return appropriate error */
  305. #endif
  306. if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
  307. {
  308. FT_CharMap old, cmap = NULL;
  309. old = face->charmap;
  310. cmap = face->charmaps[cmap_index];
  311. if ( old != cmap && !no_cmap_change )
  312. FT_Set_Charmap( face, cmap );
  313. gindex = FT_Get_Char_Index( face, char_code );
  314. if ( old != cmap && !no_cmap_change )
  315. FT_Set_Charmap( face, old );
  316. }
  317. FTC_CMAP_NODE( node )->indices[char_code -
  318. FTC_CMAP_NODE( node )->first]
  319. = (FT_UShort)gindex;
  320. }
  321. Exit:
  322. return gindex;
  323. }
  324. /* END */