Index: src/cache/ftccmap.c |
diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..848349be2d1bd6b1f1e175091ea7299b89869b66 |
--- /dev/null |
+++ b/src/cache/ftccmap.c |
@@ -0,0 +1,337 @@ |
+/***************************************************************************/ |
+/* */ |
+/* ftccmap.c */ |
+/* */ |
+/* FreeType CharMap cache (body) */ |
+/* */ |
+/* Copyright 2000-2013 by */ |
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
+/* */ |
+/* This file is part of the FreeType project, and may only be used, */ |
+/* modified, and distributed under the terms of the FreeType project */ |
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
+/* this file you indicate that you have read the license and */ |
+/* understand and accept it fully. */ |
+/* */ |
+/***************************************************************************/ |
+ |
+ |
+#include <ft2build.h> |
+#include FT_FREETYPE_H |
+#include FT_CACHE_H |
+#include "ftcmanag.h" |
+#include FT_INTERNAL_MEMORY_H |
+#include FT_INTERNAL_OBJECTS_H |
+#include FT_INTERNAL_DEBUG_H |
+ |
+#include "ftccback.h" |
+#include "ftcerror.h" |
+ |
+#undef FT_COMPONENT |
+#define FT_COMPONENT trace_cache |
+ |
+ |
+ /*************************************************************************/ |
+ /* */ |
+ /* Each FTC_CMapNode contains a simple array to map a range of character */ |
+ /* codes to equivalent glyph indices. */ |
+ /* */ |
+ /* For now, the implementation is very basic: Each node maps a range of */ |
+ /* 128 consecutive character codes to their corresponding glyph indices. */ |
+ /* */ |
+ /* We could do more complex things, but I don't think it is really very */ |
+ /* useful. */ |
+ /* */ |
+ /*************************************************************************/ |
+ |
+ |
+ /* number of glyph indices / character code per node */ |
+#define FTC_CMAP_INDICES_MAX 128 |
+ |
+ /* compute a query/node hash */ |
+#define FTC_CMAP_HASH( faceid, index, charcode ) \ |
+ ( _FTC_FACE_ID_HASH( faceid ) + 211 * (index) + \ |
+ ( (charcode) / FTC_CMAP_INDICES_MAX ) ) |
+ |
+ /* the charmap query */ |
+ typedef struct FTC_CMapQueryRec_ |
+ { |
+ FTC_FaceID face_id; |
+ FT_UInt cmap_index; |
+ FT_UInt32 char_code; |
+ |
+ } FTC_CMapQueryRec, *FTC_CMapQuery; |
+ |
+#define FTC_CMAP_QUERY( x ) ((FTC_CMapQuery)(x)) |
+#define FTC_CMAP_QUERY_HASH( x ) \ |
+ FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code ) |
+ |
+ /* the cmap cache node */ |
+ typedef struct FTC_CMapNodeRec_ |
+ { |
+ FTC_NodeRec node; |
+ FTC_FaceID face_id; |
+ FT_UInt cmap_index; |
+ FT_UInt32 first; /* first character in node */ |
+ FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */ |
+ |
+ } FTC_CMapNodeRec, *FTC_CMapNode; |
+ |
+#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) ) |
+#define FTC_CMAP_NODE_HASH( x ) \ |
+ FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first ) |
+ |
+ /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */ |
+ /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */ |
+#define FTC_CMAP_UNKNOWN (FT_UInt16)~0 |
+ |
+ |
+ /*************************************************************************/ |
+ /*************************************************************************/ |
+ /***** *****/ |
+ /***** CHARMAP NODES *****/ |
+ /***** *****/ |
+ /*************************************************************************/ |
+ /*************************************************************************/ |
+ |
+ |
+ FT_CALLBACK_DEF( void ) |
+ ftc_cmap_node_free( FTC_Node ftcnode, |
+ FTC_Cache cache ) |
+ { |
+ FTC_CMapNode node = (FTC_CMapNode)ftcnode; |
+ FT_Memory memory = cache->memory; |
+ |
+ |
+ FT_FREE( node ); |
+ } |
+ |
+ |
+ /* initialize a new cmap node */ |
+ FT_CALLBACK_DEF( FT_Error ) |
+ ftc_cmap_node_new( FTC_Node *ftcanode, |
+ FT_Pointer ftcquery, |
+ FTC_Cache cache ) |
+ { |
+ FTC_CMapNode *anode = (FTC_CMapNode*)ftcanode; |
+ FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; |
+ FT_Error error; |
+ FT_Memory memory = cache->memory; |
+ FTC_CMapNode node = NULL; |
+ FT_UInt nn; |
+ |
+ |
+ if ( !FT_NEW( node ) ) |
+ { |
+ node->face_id = query->face_id; |
+ node->cmap_index = query->cmap_index; |
+ node->first = (query->char_code / FTC_CMAP_INDICES_MAX) * |
+ FTC_CMAP_INDICES_MAX; |
+ |
+ for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ ) |
+ node->indices[nn] = FTC_CMAP_UNKNOWN; |
+ } |
+ |
+ *anode = node; |
+ return error; |
+ } |
+ |
+ |
+ /* compute the weight of a given cmap node */ |
+ FT_CALLBACK_DEF( FT_Offset ) |
+ ftc_cmap_node_weight( FTC_Node cnode, |
+ FTC_Cache cache ) |
+ { |
+ FT_UNUSED( cnode ); |
+ FT_UNUSED( cache ); |
+ |
+ return sizeof ( *cnode ); |
+ } |
+ |
+ |
+ /* compare a cmap node to a given query */ |
+ FT_CALLBACK_DEF( FT_Bool ) |
+ ftc_cmap_node_compare( FTC_Node ftcnode, |
+ FT_Pointer ftcquery, |
+ FTC_Cache cache, |
+ FT_Bool* list_changed ) |
+ { |
+ FTC_CMapNode node = (FTC_CMapNode)ftcnode; |
+ FTC_CMapQuery query = (FTC_CMapQuery)ftcquery; |
+ FT_UNUSED( cache ); |
+ |
+ |
+ if ( list_changed ) |
+ *list_changed = FALSE; |
+ if ( node->face_id == query->face_id && |
+ node->cmap_index == query->cmap_index ) |
+ { |
+ FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); |
+ |
+ |
+ return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); |
+ } |
+ |
+ return 0; |
+ } |
+ |
+ |
+ FT_CALLBACK_DEF( FT_Bool ) |
+ ftc_cmap_node_remove_faceid( FTC_Node ftcnode, |
+ FT_Pointer ftcface_id, |
+ FTC_Cache cache, |
+ FT_Bool* list_changed ) |
+ { |
+ FTC_CMapNode node = (FTC_CMapNode)ftcnode; |
+ FTC_FaceID face_id = (FTC_FaceID)ftcface_id; |
+ FT_UNUSED( cache ); |
+ |
+ |
+ if ( list_changed ) |
+ *list_changed = FALSE; |
+ return FT_BOOL( node->face_id == face_id ); |
+ } |
+ |
+ |
+ /*************************************************************************/ |
+ /*************************************************************************/ |
+ /***** *****/ |
+ /***** GLYPH IMAGE CACHE *****/ |
+ /***** *****/ |
+ /*************************************************************************/ |
+ /*************************************************************************/ |
+ |
+ |
+ FT_CALLBACK_TABLE_DEF |
+ const FTC_CacheClassRec ftc_cmap_cache_class = |
+ { |
+ ftc_cmap_node_new, |
+ ftc_cmap_node_weight, |
+ ftc_cmap_node_compare, |
+ ftc_cmap_node_remove_faceid, |
+ ftc_cmap_node_free, |
+ |
+ sizeof ( FTC_CacheRec ), |
+ ftc_cache_init, |
+ ftc_cache_done, |
+ }; |
+ |
+ |
+ /* documentation is in ftcache.h */ |
+ |
+ FT_EXPORT_DEF( FT_Error ) |
+ FTC_CMapCache_New( FTC_Manager manager, |
+ FTC_CMapCache *acache ) |
+ { |
+ return FTC_Manager_RegisterCache( manager, |
+ &ftc_cmap_cache_class, |
+ FTC_CACHE_P( acache ) ); |
+ } |
+ |
+ |
+ /* documentation is in ftcache.h */ |
+ |
+ FT_EXPORT_DEF( FT_UInt ) |
+ FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, |
+ FTC_FaceID face_id, |
+ FT_Int cmap_index, |
+ FT_UInt32 char_code ) |
+ { |
+ FTC_Cache cache = FTC_CACHE( cmap_cache ); |
+ FTC_CMapQueryRec query; |
+ FTC_Node node; |
+ FT_Error error; |
+ FT_UInt gindex = 0; |
+ FT_PtrDist hash; |
+ FT_Int no_cmap_change = 0; |
+ |
+ |
+ if ( cmap_index < 0 ) |
+ { |
+ /* Treat a negative cmap index as a special value, meaning that you */ |
+ /* don't want to change the FT_Face's character map through this */ |
+ /* call. This can be useful if the face requester callback already */ |
+ /* sets the face's charmap to the appropriate value. */ |
+ |
+ no_cmap_change = 1; |
+ cmap_index = 0; |
+ } |
+ |
+ if ( !cache ) |
+ { |
+ FT_TRACE0(( "FTC_CMapCache_Lookup: bad arguments, returning 0\n" )); |
+ return 0; |
+ } |
+ |
+ query.face_id = face_id; |
+ query.cmap_index = (FT_UInt)cmap_index; |
+ query.char_code = char_code; |
+ |
+ hash = FTC_CMAP_HASH( face_id, cmap_index, char_code ); |
+ |
+#if 1 |
+ FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query, |
+ node, error ); |
+#else |
+ error = FTC_Cache_Lookup( cache, hash, &query, &node ); |
+#endif |
+ if ( error ) |
+ goto Exit; |
+ |
+ FT_ASSERT( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first ) < |
+ FTC_CMAP_INDICES_MAX ); |
+ |
+ /* something rotten can happen with rogue clients */ |
+ if ( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first >= |
+ FTC_CMAP_INDICES_MAX ) ) |
+ return 0; /* XXX: should return appropriate error */ |
+ |
+ gindex = FTC_CMAP_NODE( node )->indices[char_code - |
+ FTC_CMAP_NODE( node )->first]; |
+ if ( gindex == FTC_CMAP_UNKNOWN ) |
+ { |
+ FT_Face face; |
+ |
+ |
+ gindex = 0; |
+ |
+ error = FTC_Manager_LookupFace( cache->manager, |
+ FTC_CMAP_NODE( node )->face_id, |
+ &face ); |
+ if ( error ) |
+ goto Exit; |
+ |
+#ifdef FT_MAX_CHARMAP_CACHEABLE |
+ /* something rotten can happen with rogue clients */ |
+ if ( cmap_index > FT_MAX_CHARMAP_CACHEABLE ) |
+ return 0; /* XXX: should return appropriate error */ |
+#endif |
+ |
+ if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps ) |
+ { |
+ FT_CharMap old, cmap = NULL; |
+ |
+ |
+ old = face->charmap; |
+ cmap = face->charmaps[cmap_index]; |
+ |
+ if ( old != cmap && !no_cmap_change ) |
+ FT_Set_Charmap( face, cmap ); |
+ |
+ gindex = FT_Get_Char_Index( face, char_code ); |
+ |
+ if ( old != cmap && !no_cmap_change ) |
+ FT_Set_Charmap( face, old ); |
+ } |
+ |
+ FTC_CMAP_NODE( node )->indices[char_code - |
+ FTC_CMAP_NODE( node )->first] |
+ = (FT_UShort)gindex; |
+ } |
+ |
+ Exit: |
+ return gindex; |
+ } |
+ |
+ |
+/* END */ |