added new charmap cache. see include/freetype/cache/ftccmap.h

This commit is contained in:
David Turner 2001-12-07 14:43:45 +00:00
parent 6b2e4d4e13
commit 145f94cb26
10 changed files with 658 additions and 36 deletions

View File

@ -1,3 +1,9 @@
2001-12-07 David Turner <david@freetype.org>
* include/freetype/cache/ftccmap.h, src/cache/ftccmap.c: added new
charmap cache
2001-12-06 Leonard Rosenthol <leonardr@lazerware.com> 2001-12-06 Leonard Rosenthol <leonardr@lazerware.com>
* src/base/ftmac.c: Added support for reading .dfont files on * src/base/ftmac.c: Added support for reading .dfont files on
@ -7,22 +13,36 @@
* include/freetype/ftmac.h: Exported FT_GetFile_From_Mac_Name() * include/freetype/ftmac.h: Exported FT_GetFile_From_Mac_Name()
2001-12-06 Werner Lemberg <wl@gnu.org> 2001-12-06 Werner Lemberg <wl@gnu.org>
* INSTALL: Small update. * INSTALL: Small update.
2001-12-05 David Turner <david@freetype.org>
* src/base/ftglyph.c (FT_Glyph_To_Bitmap): Re-ordered code for
debugging purposes.
* src/smooth/ftsmooth.c (ft_smooth_render): Fixed a nasty hidden bug
where outline shifting wasn't correctly undone after bitmap
rasterization. This created problems with certain glyphs (like '"'
of certain fonts) and the cache system.
2001-12-05 David Turner <david@freetype.org> 2001-12-05 David Turner <david@freetype.org>
* src/base/ftglyph.c (FT_Glyph_To_Bitmap): re-ordered code for debugging
purposes..
* src/smooth/ftsmooth.c (ft_smooth_render): fixed a nasty hidden bug where
outline shifting wasn't correctly undone after bitmap rasterization. this
created problems with certain glyphs (like '"' of certain fonts..) and
the cache system..
2001-12-05 David Turner <david@freetype.org>
First of all, a big thanks to Werner and Antoine for their latest work !!
* src/pshinter/pshalgo2.c (psh2_hint_table_init),
src/pshinter/pshalgo1.c (psh1_hint_table_init): removed compiler
warnings
* include/freetype/cache/*, src/cache/*: yet another massive rewrite of
the caching sub-system, in order to both increase performance and allow
simpler cache sub-classing. As an example, the code for the image and
sbit caches is now much simpler
* src/pshinter/pshalgo2.c (psh2_hint_table_init), * src/pshinter/pshalgo2.c (psh2_hint_table_init),
src/pshinter/pshalgo1.c (psh1_hint_table_init): Removed compiler src/pshinter/pshalgo1.c (psh1_hint_table_init): Removed compiler
warnings warnings

195
include/freetype/cache/ftccmap.h vendored Normal file
View File

@ -0,0 +1,195 @@
/***************************************************************************/
/* */
/* ftccmap.h */
/* */
/* FreeType charmap cache */
/* */
/* Copyright 2000-2001 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. */
/* */
/***************************************************************************/
#ifndef __FT_CACHE_CHARMAP_H__
#define __FT_CACHE_CHARMAP_H__
#include <ft2build.h>
#include FT_CACHE_H
FT_BEGIN_HEADER
/************************************************************************
*
* @type: FTC_CmapCache
*
* @description:
* opaque handle used to manager a charmap cache. This cache is used
* to hold character codes -> glyph indices mappings
*/
typedef struct FTC_CMapCacheRec_* FTC_CMapCache;
/************************************************************************
*
* @type: FTC_CMapDesc
*
* @description:
* handle to a @FTC_CMapDescRec structure used to describe a given charmap
* in a charmap cache.
*
* each @FTC_CMapDesc describes which charmap, of which @FTC_Face we
* want to use in @FTC_CMapCache_Lookup
*/
typedef struct FTC_CMapDescRec_* FTC_CMapDesc;
/************************************************************************
*
* @enum: FTC_CMapType
*
* @description:
* the list of valid @FTC_CMap types, they indicate how we want to
* address a charmap within a @FTC_FaceID
*
* @values:
* FTC_CMAP_BY_INDEX ::
* used to indicate that we want to address a charmap by its index in
* the corresponding @FT_Face
*
* FTC_CMAP_BY_ENCODING ::
* used to indicate that we want to use a @FT_Face charmap that
* corresponds to a given encoding
*
* FTC_CMAP_BY_ID ::
* used to indicate that we want to use a @FT_Face charmap that
* corresponds to a given (platform,encoding) id. see @FTC_CMapIdRec
*/
typedef enum
{
FTC_CMAP_BY_INDEX = 0,
FTC_CMAP_BY_ENCODING = 1,
FTC_CMAP_BY_ID = 2
} FTC_CMapType;
/************************************************************************
*
* @struct: FTC_CMapIdRec
*
* @description:
* a short structure used to identify a charmap by a (platform,encoding)
* pair of values
*
* @fields:
* platform :: platform ID
* encoding :: encoding ID
*/
typedef struct FTC_CMapIdRec_
{
FT_UInt platform;
FT_UInt encoding;
} FTC_CMapIdRec;
/************************************************************************
*
* @struct: FTC_CMapDescRec
*
* @description:
* a structure used to describe a given charmap to the @FTC_CMapCache
*
* @fields:
* face_id :: @FTC_FaceID of the face this charmap belongs to
* type :: type of charmap, see @FTC_CMapType
*
* u.index :: for @FTC_CMAP_BY_INDEX types, this is the charmap index
* (within a @FT_Face) we want to use.
*
* u.encoding :: for @FTC_CMAP_BY_ENCODING types, this is the charmap
* encoding we want to use. see @FT_Encoding
*
* u.id :: for @FTC_CMAP_BY_ID types, this is the (platform,encoding)
* pair we want to use. see @FTC_CMapIdRec and
* @FT_CharMapRec
*/
typedef struct FTC_CMapDescRec_
{
FTC_FaceID face_id;
FTC_CMapType type;
union
{
FT_UInt index;
FT_Encoding encoding;
FTC_CMapIdRec id;
} u;
} FTC_CMapDescRec;
/************************************************************************
*
* @function: FTC_CMapCache_New
*
* @description:
* create a new charmap cache
*
* @input:
* manager :: handle to cache manager
*
* @output:
* acache :: new cache handle. NULL in case of error
*
* @return:
* FreeType error code. 0 means success
*
* @note:
* like all other caches, this one will be destroyed with the
* cache manager
*/
FT_EXPORT( FT_Error )
FTC_CMapCache_New( FTC_Manager manager,
FTC_CMapCache *acache );
/************************************************************************
*
* @function: FTC_CMapCache_Lookup
*
* @description:
* translate a character code into a glyph index, using the charmap
* cache.
*
* @input:
* cache :: charmap cache handle
* cmap_desc :: charmap descriptor handle
* char_code :: character code (in the corresponding charmap)
*
* @return:
* glyph index. 0 means "no glyph" !!
*
* @note:
* this function doesn't return @FTC_Node handles, since there is
* no real use for them with typical uses of charmaps
*/
FT_EXPORT( FT_UInt )
FTC_CMapCache_Lookup( FTC_CMapCache cache,
FTC_CMapDesc cmap_desc,
FT_UInt32 char_code );
/* */
FT_END_HEADER
#endif /* __FT_CACHE_CHARMAP_H__ */

View File

@ -417,6 +417,18 @@
#define FT_CACHE_SMALL_BITMAPS_H <freetype/cache/ftcsbits.h> #define FT_CACHE_SMALL_BITMAPS_H <freetype/cache/ftcsbits.h>
/*************************************************************************/
/* */
/* @macro: */
/* FT_CACHE_CHARMAP_H */
/* */
/* @description: */
/* A macro used in #include statements to name the file containing */
/* the `charmap'API of the FreeType 2 cache sub-system. */
/* */
#define FT_CACHE_CHARMAP_H <freetype/cache/ftccmap.h>
/*************************************************************************/ /*************************************************************************/
/* */ /* */
/* @macro: */ /* @macro: */

2
src/cache/Jamfile vendored
View File

@ -16,7 +16,7 @@ HDRMACRO [ FT2_SubDir include ftcache.h ] ;
if $(FT2_MULTI) if $(FT2_MULTI)
{ {
_sources = ftlru ftcmanag ftccache ftcglyph ftcsbits ftcimage ; _sources = ftlru ftcmanag ftccache ftcglyph ftcsbits ftcimage ftccmap ;
} }
else else
{ {

View File

@ -559,8 +559,8 @@
if ( ALLOC( node, clazz->node_size ) ) if ( ALLOC( node, clazz->node_size ) )
goto Exit; goto Exit;
/* node initializer must set 'hash' field */
node->fam_index = (FT_UShort) family->fam_index; node->fam_index = (FT_UShort) family->fam_index;
node->hash = query->hash;
node->ref_count = 0; node->ref_count = 0;
error = clazz->node_init( node, query, cache ); error = clazz->node_init( node, query, cache );

391
src/cache/ftccmap.c vendored Normal file
View File

@ -0,0 +1,391 @@
/***************************************************************************/
/* */
/* ftccmap.c */
/* */
/* FreeType CharMap cache */
/* */
/* Copyright 2000-2001 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 used 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 */
/* correspondingglyph indices.. */
/* */
/* we could do more complex things, but I don't think it's */
/* 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 hasn'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'll 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 )
{
FTC_CMapFamily cfam = FTC_CMAP_FAMILY( FTC_QUERY(cquery)->family );
FT_UInt32 first;
FT_UInt n;
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 )
{
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 ( 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;
FT_Error error;
FT_Face face;
/* setup charmap descriptor */
cfam->desc = *desc;
/* let's see if 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 index = count;
FT_CharMap* cur = face->charmaps;
switch ( desc->type )
{
case FTC_CMAP_BY_INDEX:
{
index = desc->u.index;
hash = index*33;
break;
}
case FTC_CMAP_BY_ENCODING:
{
for ( index = 0; index < count; index++, cur++ )
if ( cur[0]->encoding == desc->u.encoding )
break;
hash = index*67;
break;
}
case FTC_CMAP_BY_ID:
{
for ( index = 0; index < count; index++, 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 ( index >= count )
goto Bad_Descriptor;
/* compute hash value, both in family and query */
cfam->index = index;
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(( "FreeType.cache.cmap.lookup: invalid charmap descriptor\n" ));
return FT_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 ) );
}
/* 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;
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_cache_lookup( FTC_CACHE(cache),
FTC_QUERY(&cquery),
(FTC_Node*) &node );
if ( !error )
{
FT_UInt offset = (FT_UInt)( char_code - node->first );
gindex = node->indices[offset];
if ( gindex == FTC_CMAP_UNKNOWN )
{
FT_Face face;
FT_CharMap old, cmap, limit;
/* 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] = gindex;
/* restore old charmap */
FT_Set_Charmap( face, old );
}
}
}
return gindex;
}
/* END */

View File

@ -39,8 +39,6 @@
FT_UInt start = FTC_GLYPH_FAMILY_START(gfam,gindex); FT_UInt start = FTC_GLYPH_FAMILY_START(gfam,gindex);
gnode->node.fam_index = (FT_UShort) gfam->family.fam_index;
gnode->node.hash = FTC_GLYPH_FAMILY_HASH(gfam,gindex);
gnode->item_start = (FT_UShort) start; gnode->item_start = (FT_UShort) start;
len = gfam->item_total - start; len = gfam->item_total - start;
@ -68,12 +66,10 @@
ftc_glyph_node_compare( FTC_GlyphNode gnode, ftc_glyph_node_compare( FTC_GlyphNode gnode,
FTC_GlyphQuery gquery ) FTC_GlyphQuery gquery )
{ {
FT_UInt fam_index = (FT_UInt) FTC_NODE(gnode)->fam_index;
FT_UInt start = (FT_UInt) gnode->item_start; FT_UInt start = (FT_UInt) gnode->item_start;
FT_UInt count = (FT_UInt) gnode->item_count; FT_UInt count = (FT_UInt) gnode->item_count;
return FT_BOOL( (FT_UInt)(gquery->gindex - start) < count && return FT_BOOL( (FT_UInt)(gquery->gindex - start) < count );
gquery->query.family->fam_index == fam_index );
} }

View File

@ -261,7 +261,6 @@
FT_Bool result; FT_Bool result;
/* we must set iquery.glyph.gfam for faster glyph node comparisons */
result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &ifam->desc, &iquery->desc ) ); result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &ifam->desc, &iquery->desc ) );
if ( result ) if ( result )
FTC_GLYPH_FAMILY_FOUND(ifam,iquery); FTC_GLYPH_FAMILY_FOUND(ifam,iquery);

20
src/cache/ftcsbits.c vendored
View File

@ -122,13 +122,13 @@
static FT_Error static FT_Error
ftc_sbit_node_load( FTC_SBitNode snode, ftc_sbit_node_load( FTC_SBitNode snode,
FTC_Manager manager, FTC_Manager manager,
FTC_SBitFamily sfam,
FT_UInt gindex, FT_UInt gindex,
FT_ULong *asize ) FT_ULong *asize )
{ {
FT_Error error; FT_Error error;
FTC_GlyphNode gnode = FTC_GLYPH_NODE(snode); FTC_GlyphNode gnode = FTC_GLYPH_NODE(snode);
FTC_GlyphFamily gfam; FTC_GlyphFamily gfam = FTC_GLYPH_FAMILY(sfam);
FTC_SBitFamily sfam;
FT_Memory memory; FT_Memory memory;
FT_Face face; FT_Face face;
FT_Size size; FT_Size size;
@ -141,8 +141,6 @@
return FTC_Err_Invalid_Argument; return FTC_Err_Invalid_Argument;
} }
gfam = FTC_GLYPH_FAMILY( manager->families.entries[ gnode->node.fam_index ].family );
sfam = FTC_SBIT_FAMILY(gfam);
memory = manager->library->memory; memory = manager->library->memory;
sbit = snode->sbits + (gindex - gnode->item_start); sbit = snode->sbits + (gindex - gnode->item_start);
@ -275,7 +273,11 @@
gquery->gindex, gquery->gindex,
FTC_GLYPH_FAMILY(gquery->query.family) ); FTC_GLYPH_FAMILY(gquery->query.family) );
error = ftc_sbit_node_load( snode, cache->manager, gquery->gindex, NULL ); error = ftc_sbit_node_load( snode,
cache->manager,
FTC_SBIT_FAMILY( FTC_QUERY(gquery)->family ),
gquery->gindex,
NULL );
if ( error ) if ( error )
ftc_glyph_node_done( FTC_GLYPH_NODE(snode), cache ); ftc_glyph_node_done( FTC_GLYPH_NODE(snode), cache );
@ -336,7 +338,13 @@
{ {
FT_ULong size; FT_ULong size;
ftc_sbit_node_load( snode, cache->manager, gindex, &size ); /* yes, it's safe to ignore errors here */
ftc_sbit_node_load( snode,
cache->manager,
FTC_SBIT_FAMILY( FTC_QUERY(squery)->family ),
gindex,
&size );
cache->manager->cur_weight += size; cache->manager->cur_weight += size;
} }
} }

3
src/cache/rules.mk vendored
View File

@ -33,7 +33,8 @@ Cache_DRV_SRC := $(CACHE_DIR_)ftlru.c \
$(CACHE_DIR_)ftccache.c \ $(CACHE_DIR_)ftccache.c \
$(CACHE_DIR_)ftcglyph.c \ $(CACHE_DIR_)ftcglyph.c \
$(CACHE_DIR_)ftcsbits.c \ $(CACHE_DIR_)ftcsbits.c \
$(CACHE_DIR_)ftcimage.c $(CACHE_DIR_)ftcimage.c \
$(CACHE_DIR_)ftccmap.c
# Cache driver headers # Cache driver headers
# #