/***************************************************************************//* *//* ftccmap.c *//* *//* FreeType CharMap cache (body) *//* *//* Copyright 2000-2001, 2002 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 FT_CACHE_CHARMAP_H#include FT_CACHE_MANAGER_H#include FT_INTERNAL_MEMORY_H#include FT_INTERNAL_DEBUG_H #include "ftcerror.h" /*************************************************************************/ /* */ /* 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 typedef struct FTC_CMapNodeRec_ { FTC_NodeRec node; 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 ) ) /* compute node hash value from cmap family and "requested" glyph index */#define FTC_CMAP_HASH( cfam, cquery ) \ ( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) ) /* 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)-1 ) /* the charmap query */ typedef struct FTC_CMapQueryRec_ { FTC_QueryRec query; FTC_CMapDesc desc; FT_UInt32 char_code; } FTC_CMapQueryRec, *FTC_CMapQuery; #define FTC_CMAP_QUERY( x ) ( (FTC_CMapQuery)( x ) ) /* the charmap family */ typedef struct FTC_CMapFamilyRec_ { FTC_FamilyRec family; FT_UInt32 hash; FTC_CMapDescRec desc; FT_UInt index; } FTC_CMapFamilyRec, *FTC_CMapFamily; #define FTC_CMAP_FAMILY( x ) ( (FTC_CMapFamily)( x ) )#define FTC_CMAP_FAMILY_MEMORY( x ) FTC_FAMILY( x )->memory /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** CHARMAP NODES *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ /* no need for specific finalizer; we use "ftc_node_done" directly */ /* initialize a new cmap node */ FT_CALLBACK_DEF( FT_Error ) ftc_cmap_node_init( FTC_CMapNode cnode, FTC_CMapQuery cquery, FTC_Cache cache ) { FT_UInt32 first; FT_UInt n; FT_UNUSED( cache ); first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) * FTC_CMAP_INDICES_MAX; cnode->first = first; for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ ) cnode->indices[n] = FTC_CMAP_UNKNOWN; return 0; } /* compute the weight of a given cmap node */ FT_CALLBACK_DEF( FT_ULong ) ftc_cmap_node_weight( FTC_CMapNode cnode ) { FT_UNUSED( cnode ); return sizeof ( *cnode ); } /* compare a cmap node to a given query */ FT_CALLBACK_DEF( FT_Bool ) ftc_cmap_node_compare( FTC_CMapNode cnode, FTC_CMapQuery cquery ) { FT_UInt32 offset = (FT_UInt32)( cquery->char_code - cnode->first ); return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** CHARMAP FAMILY *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ FT_CALLBACK_DEF( FT_Error ) ftc_cmap_family_init( FTC_CMapFamily cfam, FTC_CMapQuery cquery, FTC_Cache cache ) { FTC_Manager manager = cache->manager; FTC_CMapDesc desc = cquery->desc; FT_UInt32 hash = 0; FT_Error error; FT_Face face; /* setup charmap descriptor */ cfam->desc = *desc; /* let's see whether the rest is correct too */ error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face ); if ( !error ) { FT_UInt count = face->num_charmaps; FT_UInt idx = count; FT_CharMap* cur = face->charmaps; switch ( desc->type ) { case FTC_CMAP_BY_INDEX: idx = desc->u.index; hash = idx * 33; break; case FTC_CMAP_BY_ENCODING: for ( idx = 0; idx < count; idx++, cur++ ) if ( cur[0]->encoding == desc->u.encoding ) break; hash = idx * 67; break; case FTC_CMAP_BY_ID: for ( idx = 0; idx < count; idx++, cur++ ) { if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform && (FT_UInt)cur[0]->encoding_id == desc->u.id.encoding ) { hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7; break; } } break; default: ; } if ( idx >= count ) goto Bad_Descriptor; /* compute hash value, both in family and query */ cfam->index = idx; cfam->hash = hash ^ FTC_FACE_ID_HASH( desc->face_id ); FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery ); error = ftc_family_init( FTC_FAMILY( cfam ), FTC_QUERY( cquery ), cache ); } return error; Bad_Descriptor: FT_ERROR(( "ftp_cmap_family_init: invalid charmap descriptor\n" )); return FTC_Err_Invalid_Argument; } FT_CALLBACK_DEF( FT_Bool ) ftc_cmap_family_compare( FTC_CMapFamily cfam, FTC_CMapQuery cquery ) { FT_Int result = 0; /* first, compare face id and type */ if ( cfam->desc.face_id != cquery->desc->face_id || cfam->desc.type != cquery->desc->type ) goto Exit; switch ( cfam->desc.type ) { case FTC_CMAP_BY_INDEX: result = ( cfam->desc.u.index == cquery->desc->u.index ); break; case FTC_CMAP_BY_ENCODING: result = ( cfam->desc.u.encoding == cquery->desc->u.encoding ); break; case FTC_CMAP_BY_ID: result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform && cfam->desc.u.id.encoding == cquery->desc->u.id.encoding ); break; default: ; } if ( result ) { /* when found, update the 'family' and 'hash' field of the query */ FTC_QUERY( cquery )->family = FTC_FAMILY( cfam ); FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery ); } Exit: return FT_BOOL( result ); } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GLYPH IMAGE CACHE *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ FT_CALLBACK_TABLE_DEF const FTC_Cache_ClassRec ftc_cmap_cache_class = { sizeof ( FTC_CacheRec ), (FTC_Cache_InitFunc) ftc_cache_init, (FTC_Cache_ClearFunc)ftc_cache_clear, (FTC_Cache_DoneFunc) ftc_cache_done, sizeof ( FTC_CMapFamilyRec ), (FTC_Family_InitFunc) ftc_cmap_family_init, (FTC_Family_CompareFunc)ftc_cmap_family_compare, (FTC_Family_DoneFunc) ftc_family_done, sizeof ( FTC_CMapNodeRec ), (FTC_Node_InitFunc) ftc_cmap_node_init, (FTC_Node_WeightFunc) ftc_cmap_node_weight, (FTC_Node_CompareFunc)ftc_cmap_node_compare, (FTC_Node_DoneFunc) ftc_node_done }; /* documentation is in ftccmap.h */ FT_EXPORT_DEF( FT_Error ) FTC_CMapCache_New( FTC_Manager manager, FTC_CMapCache *acache ) { return FTC_Manager_Register_Cache( manager, (FTC_Cache_Class)&ftc_cmap_cache_class, FTC_CACHE_P( acache ) ); } #ifdef FTC_CACHE_USE_INLINE #define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \ ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) ) #define GEN_CACHE_NODE_COMPARE( n, q, c ) \ ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) ) #define GEN_CACHE_LOOKUP ftc_cmap_cache_lookup #include "ftccache.i" #else /* !FTC_CACHE_USE_INLINE */ #define ftc_cmap_cache_lookup ftc_cache_lookup #endif /* !FTC_CACHE_USE_INLINE */ /* documentation is in ftccmap.h */ FT_EXPORT_DEF( FT_UInt ) FTC_CMapCache_Lookup( FTC_CMapCache cache, FTC_CMapDesc desc, FT_UInt32 char_code ) { FTC_CMapQueryRec cquery; FTC_CMapNode node; FT_Error error; FT_UInt gindex = 0; if ( !cache || !desc ) { FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" )); return 0; } cquery.desc = desc; cquery.char_code = char_code; error = ftc_cmap_cache_lookup( FTC_CACHE( cache ), FTC_QUERY( &cquery ), (FTC_Node*)&node ); if ( !error ) { FT_UInt offset = (FT_UInt)( char_code - node->first ); FT_ASSERT( offset < FTC_CMAP_INDICES_MAX ); gindex = node->indices[offset]; if ( gindex == FTC_CMAP_UNKNOWN ) { FT_Face face; /* we need to use FT_Get_Char_Index */ gindex = 0; error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager, desc->face_id, &face ); if ( !error ) { FT_CharMap old, cmap = NULL; FT_UInt cmap_index; /* save old charmap, select new one */ old = face->charmap; cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index; cmap = face->charmaps[cmap_index]; FT_Set_Charmap( face, cmap ); /* perform lookup */ gindex = FT_Get_Char_Index( face, char_code ); node->indices[offset] = (FT_UInt16)gindex; /* restore old charmap */ FT_Set_Charmap( face, old ); } } } return gindex; } /* END */
/***************************************************************************/
/* */
/* ftccmap.c */
/* */
/* FreeType CharMap cache (body) */
/* */
/* Copyright 2000-2001, 2002 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 FT_CACHE_CHARMAP_H
#include FT_CACHE_MANAGER_H
#include FT_INTERNAL_MEMORY_H
#include FT_INTERNAL_DEBUG_H
#include "ftcerror.h"
/*************************************************************************/
/* */
/* 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
typedef struct FTC_CMapNodeRec_
{
FTC_NodeRec node;
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 ) )
/* compute node hash value from cmap family and "requested" glyph index */
#define FTC_CMAP_HASH( cfam, cquery ) \
( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) )
/* 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)-1 )
/* the charmap query */
typedef struct FTC_CMapQueryRec_
{
FTC_QueryRec query;
FTC_CMapDesc desc;
FT_UInt32 char_code;
} FTC_CMapQueryRec, *FTC_CMapQuery;
#define FTC_CMAP_QUERY( x ) ( (FTC_CMapQuery)( x ) )
/* the charmap family */
typedef struct FTC_CMapFamilyRec_
{
FTC_FamilyRec family;
FT_UInt32 hash;
FTC_CMapDescRec desc;
FT_UInt index;
} FTC_CMapFamilyRec, *FTC_CMapFamily;
#define FTC_CMAP_FAMILY( x ) ( (FTC_CMapFamily)( x ) )
#define FTC_CMAP_FAMILY_MEMORY( x ) FTC_FAMILY( x )->memory
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CHARMAP NODES *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* no need for specific finalizer; we use "ftc_node_done" directly */
/* initialize a new cmap node */
FT_CALLBACK_DEF( FT_Error )
ftc_cmap_node_init( FTC_CMapNode cnode,
FTC_CMapQuery cquery,
FTC_Cache cache )
{
FT_UInt32 first;
FT_UInt n;
FT_UNUSED( cache );
first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) *
FTC_CMAP_INDICES_MAX;
cnode->first = first;
for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
cnode->indices[n] = FTC_CMAP_UNKNOWN;
return 0;
}
/* compute the weight of a given cmap node */
FT_CALLBACK_DEF( FT_ULong )
ftc_cmap_node_weight( FTC_CMapNode cnode )
{
FT_UNUSED( cnode );
return sizeof ( *cnode );
}
/* compare a cmap node to a given query */
FT_CALLBACK_DEF( FT_Bool )
ftc_cmap_node_compare( FTC_CMapNode cnode,
FTC_CMapQuery cquery )
{
FT_UInt32 offset = (FT_UInt32)( cquery->char_code - cnode->first );
return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** CHARMAP FAMILY *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_CALLBACK_DEF( FT_Error )
ftc_cmap_family_init( FTC_CMapFamily cfam,
FTC_CMapQuery cquery,
FTC_Cache cache )
{
FTC_Manager manager = cache->manager;
FTC_CMapDesc desc = cquery->desc;
FT_UInt32 hash = 0;
FT_Error error;
FT_Face face;
/* setup charmap descriptor */
cfam->desc = *desc;
/* let's see whether the rest is correct too */
error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face );
if ( !error )
{
FT_UInt count = face->num_charmaps;
FT_UInt idx = count;
FT_CharMap* cur = face->charmaps;
switch ( desc->type )
{
case FTC_CMAP_BY_INDEX:
idx = desc->u.index;
hash = idx * 33;
break;
case FTC_CMAP_BY_ENCODING:
for ( idx = 0; idx < count; idx++, cur++ )
if ( cur[0]->encoding == desc->u.encoding )
break;
hash = idx * 67;
break;
case FTC_CMAP_BY_ID:
for ( idx = 0; idx < count; idx++, cur++ )
{
if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform &&
(FT_UInt)cur[0]->encoding_id == desc->u.id.encoding )
{
hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7;
break;
}
}
break;
default:
;
}
if ( idx >= count )
goto Bad_Descriptor;
/* compute hash value, both in family and query */
cfam->index = idx;
cfam->hash = hash ^ FTC_FACE_ID_HASH( desc->face_id );
FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
error = ftc_family_init( FTC_FAMILY( cfam ),
FTC_QUERY( cquery ), cache );
}
return error;
Bad_Descriptor:
FT_ERROR(( "ftp_cmap_family_init: invalid charmap descriptor\n" ));
return FTC_Err_Invalid_Argument;
}
FT_CALLBACK_DEF( FT_Bool )
ftc_cmap_family_compare( FTC_CMapFamily cfam,
FTC_CMapQuery cquery )
{
FT_Int result = 0;
/* first, compare face id and type */
if ( cfam->desc.face_id != cquery->desc->face_id ||
cfam->desc.type != cquery->desc->type )
goto Exit;
switch ( cfam->desc.type )
{
case FTC_CMAP_BY_INDEX:
result = ( cfam->desc.u.index == cquery->desc->u.index );
break;
case FTC_CMAP_BY_ENCODING:
result = ( cfam->desc.u.encoding == cquery->desc->u.encoding );
break;
case FTC_CMAP_BY_ID:
result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform &&
cfam->desc.u.id.encoding == cquery->desc->u.id.encoding );
break;
default:
;
}
if ( result )
{
/* when found, update the 'family' and 'hash' field of the query */
FTC_QUERY( cquery )->family = FTC_FAMILY( cfam );
FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
}
Exit:
return FT_BOOL( result );
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** GLYPH IMAGE CACHE *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_CALLBACK_TABLE_DEF
const FTC_Cache_ClassRec ftc_cmap_cache_class =
{
sizeof ( FTC_CacheRec ),
(FTC_Cache_InitFunc) ftc_cache_init,
(FTC_Cache_ClearFunc)ftc_cache_clear,
(FTC_Cache_DoneFunc) ftc_cache_done,
sizeof ( FTC_CMapFamilyRec ),
(FTC_Family_InitFunc) ftc_cmap_family_init,
(FTC_Family_CompareFunc)ftc_cmap_family_compare,
(FTC_Family_DoneFunc) ftc_family_done,
sizeof ( FTC_CMapNodeRec ),
(FTC_Node_InitFunc) ftc_cmap_node_init,
(FTC_Node_WeightFunc) ftc_cmap_node_weight,
(FTC_Node_CompareFunc)ftc_cmap_node_compare,
(FTC_Node_DoneFunc) ftc_node_done
};
/* documentation is in ftccmap.h */
FT_EXPORT_DEF( FT_Error )
FTC_CMapCache_New( FTC_Manager manager,
FTC_CMapCache *acache )
{
return FTC_Manager_Register_Cache(
manager,
(FTC_Cache_Class)&ftc_cmap_cache_class,
FTC_CACHE_P( acache ) );
}
#ifdef FTC_CACHE_USE_INLINE
#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) )
#define GEN_CACHE_NODE_COMPARE( n, q, c ) \
ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) )
#define GEN_CACHE_LOOKUP ftc_cmap_cache_lookup
#include "ftccache.i"
#else /* !FTC_CACHE_USE_INLINE */
#define ftc_cmap_cache_lookup ftc_cache_lookup
#endif /* !FTC_CACHE_USE_INLINE */
/* documentation is in ftccmap.h */
FT_EXPORT_DEF( FT_UInt )
FTC_CMapCache_Lookup( FTC_CMapCache cache,
FTC_CMapDesc desc,
FT_UInt32 char_code )
{
FTC_CMapQueryRec cquery;
FTC_CMapNode node;
FT_Error error;
FT_UInt gindex = 0;
if ( !cache || !desc )
{
FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
return 0;
}
cquery.desc = desc;
cquery.char_code = char_code;
error = ftc_cmap_cache_lookup( FTC_CACHE( cache ),
FTC_QUERY( &cquery ),
(FTC_Node*)&node );
if ( !error )
{
FT_UInt offset = (FT_UInt)( char_code - node->first );
FT_ASSERT( offset < FTC_CMAP_INDICES_MAX );
gindex = node->indices[offset];
if ( gindex == FTC_CMAP_UNKNOWN )
{
FT_Face face;
/* we need to use FT_Get_Char_Index */
gindex = 0;
error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager,
desc->face_id,
&face );
if ( !error )
{
FT_CharMap old, cmap = NULL;
FT_UInt cmap_index;
/* save old charmap, select new one */
old = face->charmap;
cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index;
cmap = face->charmaps[cmap_index];
FT_Set_Charmap( face, cmap );
/* perform lookup */
gindex = FT_Get_Char_Index( face, char_code );
node->indices[offset] = (FT_UInt16)gindex;
/* restore old charmap */
FT_Set_Charmap( face, old );
}
}
}
return gindex;
}
/* END */