updated the cache sub-system. Major internal rewrite
please be aware that major bug persist..
This commit is contained in:
parent
58e932157b
commit
ebdce8344a
|
@ -22,12 +22,14 @@
|
|||
|
||||
#include "ftlru.c"
|
||||
#include "ftcmanag.c"
|
||||
#include "ftcglyph.c"
|
||||
#include "ftcimage.c"
|
||||
|
||||
#else
|
||||
|
||||
#include <cache/ftlru.c>
|
||||
#include <cache/ftcmanag.c>
|
||||
#include <cache/ftcglyph.c>
|
||||
#include <cache/ftcimage.c>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
/***************************************************************************/
|
||||
/* */
|
||||
/* ftcglyph.c */
|
||||
/* */
|
||||
/* FreeType Glyph Image (FT_Glyph) cache.. */
|
||||
/* */
|
||||
/* Copyright 2000 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. */
|
||||
/* */
|
||||
/* */
|
||||
/* Note: the implementation of glyph queues is rather generic in this */
|
||||
/* code. This will allow other glyph node/cache types to be */
|
||||
/* easily included in the future.. For now, we only cache */
|
||||
/* glyph images.. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
#include <freetype/cache/ftcglyph.h>
|
||||
#include <freetype/fterrors.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
#include <freetype/internal/ftlist.h>
|
||||
#include <freetype/fterrors.h>
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH NODES *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
/* in the future, we might provide a better scheme for managing */
|
||||
/* glyph node element. For the moment, we simply use FT_Alloc/FT_Free */
|
||||
|
||||
/* creates a new glyph node, setting its cache index and ref count */
|
||||
FT_EXPORT_FUNC(void) FTC_GlyphNode_Init( FTC_GlyphNode node,
|
||||
FTC_Glyph_Queue queue,
|
||||
FT_UInt gindex )
|
||||
{
|
||||
FTC_Glyph_Cache cache = queue->cache;
|
||||
FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( &node->root );
|
||||
|
||||
data->cache_index = (FT_UShort) cache->root.cache_index;
|
||||
data->ref_count = (FT_Short) 0;
|
||||
node->queue_index = (FT_UShort) queue->queue_index;
|
||||
node->glyph_index = (FT_UShort) gindex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Important: this function is called from the cache manager to */
|
||||
/* destroy a given cache node during "cache compression". The */
|
||||
/* second argument is always "cache.user_data". You thus be */
|
||||
/* certain that the function FTC_Image_Cache_New does indeed */
|
||||
/* set its "user_data" field correctly, otherwise bad things */
|
||||
/* will happen !! */
|
||||
|
||||
FT_EXPORT_FUNC(void) FTC_GlyphNode_Destroy( FTC_GlyphNode node,
|
||||
FTC_Glyph_Cache cache )
|
||||
{
|
||||
FT_LruNode queue_lru = cache->queues_lru->nodes+node->queue_index;
|
||||
FTC_Glyph_Queue queue = (FTC_Glyph_Queue)queue_lru->root.data;
|
||||
FT_UInt hash = node->glyph_index % queue->hash_size;
|
||||
FT_List bucket = queue->buckets + hash;
|
||||
|
||||
/* remove node from its queue's bucket list */
|
||||
FT_List_Remove( bucket, FTC_GLYPHNODE_TO_LISTNODE(node) );
|
||||
|
||||
/* destroy the node */
|
||||
queue->clazz->destroy_node( node, queue );
|
||||
}
|
||||
|
||||
|
||||
/* Important: this function is called from the cache manager to */
|
||||
/* size a given cache node during "cache compression". The */
|
||||
/* second argument is always "cache.user_data". You thus be */
|
||||
/* certain that the function FTC_Image_Cache_New does indeed */
|
||||
/* set its "user_data" field correctly, otherwise bad things */
|
||||
/* will happen !! */
|
||||
|
||||
FT_EXPORT_FUNC(FT_ULong) FTC_GlyphNode_Size( FTC_GlyphNode node,
|
||||
FTC_Glyph_Cache cache )
|
||||
{
|
||||
FT_LruNode queue_lru = cache->queues_lru->nodes+node->queue_index;
|
||||
FTC_Glyph_Queue queue = (FTC_Glyph_Queue)queue_lru->root.data;
|
||||
|
||||
return queue->clazz->size_node( node, queue );
|
||||
}
|
||||
|
||||
|
||||
FT_CPLUSPLUS(const FTC_CacheNode_Class) ftc_glyph_cache_node_class =
|
||||
{
|
||||
(FTC_CacheNode_SizeFunc) FTC_GlyphNode_Size,
|
||||
(FTC_CacheNode_DestroyFunc) FTC_GlyphNode_Destroy
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH QUEUES *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
FT_EXPORT_FUNC(FT_Error) FTC_Glyph_Queue_New(
|
||||
FTC_Glyph_Cache cache,
|
||||
FT_Pointer type,
|
||||
FTC_Glyph_Queue* aqueue )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Memory memory = cache->root.memory;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FTC_Glyph_Queue queue = 0;
|
||||
|
||||
FTC_Glyph_Cache_Class* gcache_class;
|
||||
FTC_Glyph_Queue_Class* clazz;
|
||||
|
||||
gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz;
|
||||
clazz = gcache_class->queue_class;
|
||||
|
||||
*aqueue = 0;
|
||||
|
||||
if ( ALLOC( queue, clazz->queue_byte_size ) )
|
||||
goto Exit;
|
||||
|
||||
queue->cache = cache;
|
||||
queue->manager = manager;
|
||||
queue->memory = memory;
|
||||
queue->hash_size = FTC_QUEUE_HASH_SIZE_DEFAULT;
|
||||
queue->clazz = clazz;
|
||||
|
||||
/* allocate buckets table */
|
||||
if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) )
|
||||
if (error)
|
||||
goto Exit;
|
||||
|
||||
/* initialize queue by type - if needed */
|
||||
if (clazz->init)
|
||||
{
|
||||
error = clazz->init( queue, type );
|
||||
if (error)
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
*aqueue = queue;
|
||||
|
||||
Exit:
|
||||
if ( error && queue )
|
||||
{
|
||||
FREE( queue->buckets );
|
||||
FREE( queue );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FT_EXPORT_FUNC(void) FTC_Glyph_Queue_Done( FTC_Glyph_Queue queue )
|
||||
{
|
||||
FTC_Glyph_Cache cache = queue->cache;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FT_List glyphs_lru = &manager->global_lru;
|
||||
FT_List bucket = queue->buckets;
|
||||
FT_List bucket_limit = bucket + queue->hash_size;
|
||||
FT_Memory memory = cache->root.memory;
|
||||
|
||||
FTC_Glyph_Queue_Class* clazz = queue->clazz;
|
||||
|
||||
/* for each bucket, free the list of Glyph nodes */
|
||||
for ( ; bucket < bucket_limit; bucket++ )
|
||||
{
|
||||
FT_ListNode node = bucket->head;
|
||||
FT_ListNode next = 0;
|
||||
FT_ListNode lrunode;
|
||||
FTC_GlyphNode inode;
|
||||
|
||||
|
||||
for ( ; node; node = next )
|
||||
{
|
||||
next = node->next;
|
||||
inode = FTC_LISTNODE_TO_GLYPHNODE(node);
|
||||
lrunode = FTC_GLYPHNODE_TO_LRUNODE( inode );
|
||||
|
||||
manager->num_bytes -= clazz->size_node( inode, queue );
|
||||
|
||||
FT_List_Remove( glyphs_lru, lrunode );
|
||||
|
||||
clazz->destroy_node( inode, queue );
|
||||
}
|
||||
|
||||
bucket->head = bucket->tail = 0;
|
||||
}
|
||||
|
||||
if (clazz->done)
|
||||
clazz->done(queue);
|
||||
|
||||
FREE( queue->buckets );
|
||||
FREE( queue );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_FUNC(FT_Error) FTC_Glyph_Queue_Lookup_Node(
|
||||
FTC_Glyph_Queue queue,
|
||||
FT_UInt glyph_index,
|
||||
FTC_GlyphNode* anode )
|
||||
{
|
||||
FTC_Glyph_Cache cache = queue->cache;
|
||||
FTC_Manager manager = cache->root.manager;
|
||||
FT_UInt hash_index = glyph_index % queue->hash_size;
|
||||
FT_List bucket = queue->buckets + hash_index;
|
||||
FT_ListNode node;
|
||||
FT_Error error;
|
||||
FTC_GlyphNode inode;
|
||||
|
||||
FTC_Glyph_Queue_Class* clazz = queue->clazz;
|
||||
|
||||
*anode = 0;
|
||||
for ( node = bucket->head; node; node = node->next )
|
||||
{
|
||||
FT_UInt gindex;
|
||||
|
||||
inode = FTC_LISTNODE_TO_GLYPHNODE(node);
|
||||
gindex = inode->glyph_index;
|
||||
|
||||
if ( gindex == glyph_index )
|
||||
{
|
||||
/* we found it! -- move glyph to start of the lists */
|
||||
FT_List_Up( bucket, node );
|
||||
FT_List_Up( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( inode ) );
|
||||
*anode = inode;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* we didn't found the glyph image, we will now create a new one */
|
||||
error = clazz->new_node( queue, glyph_index, &inode );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* insert the node at the start of our bucket list */
|
||||
FT_List_Insert( bucket, FTC_GLYPHNODE_TO_LISTNODE(inode) );
|
||||
|
||||
/* insert the node at the start the global LRU glyph list */
|
||||
FT_List_Insert( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE(inode) );
|
||||
|
||||
manager->num_bytes += clazz->size_node( inode, queue );
|
||||
|
||||
if (manager->num_bytes > manager->max_bytes)
|
||||
FTC_Manager_Compress( manager );
|
||||
|
||||
*anode = inode;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH QUEUES LRU CALLBACKS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
#define FTC_QUEUE_LRU_GET_CACHE( lru ) \
|
||||
( (FTC_Glyph_Cache)(lru)->user_data )
|
||||
|
||||
#define FTC_QUEUE_LRU_GET_MANAGER( lru ) \
|
||||
FTC_QUEUE_LRU_GET_CACHE( lru )->manager
|
||||
|
||||
#define FTC_LRUNODE_QUEUE( node ) \
|
||||
( (FTC_Glyph_Queue)(node)->root.data )
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Error ftc_glyph_queue_lru_init( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
{
|
||||
FTC_Glyph_Cache cache = FTC_QUEUE_LRU_GET_CACHE( lru );
|
||||
FT_Error error;
|
||||
FTC_Glyph_Queue queue;
|
||||
|
||||
error = FTC_Glyph_Queue_New( cache,
|
||||
(FT_Pointer)node->key,
|
||||
&queue );
|
||||
if ( !error )
|
||||
{
|
||||
/* good, now set the queue index within the queue object */
|
||||
queue->queue_index = node - lru->nodes;
|
||||
node->root.data = queue;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
void ftc_glyph_queue_lru_done( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
{
|
||||
FTC_Glyph_Queue queue = FTC_LRUNODE_QUEUE( node );
|
||||
|
||||
FT_UNUSED( lru );
|
||||
|
||||
|
||||
FTC_Glyph_Queue_Done( queue );
|
||||
}
|
||||
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Bool ftc_glyph_queue_lru_compare( FT_LruNode node,
|
||||
FT_LruKey key )
|
||||
{
|
||||
FTC_Glyph_Queue queue = FTC_LRUNODE_QUEUE( node );
|
||||
return queue->clazz->compare( queue, (FT_Pointer)key );
|
||||
}
|
||||
|
||||
|
||||
|
||||
FT_CPLUSPLUS( const FT_Lru_Class ) ftc_glyph_queue_lru_class =
|
||||
{
|
||||
sizeof( FT_LruRec ),
|
||||
ftc_glyph_queue_lru_init,
|
||||
ftc_glyph_queue_lru_done,
|
||||
0, /* no flush */
|
||||
ftc_glyph_queue_lru_compare
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH IMAGE CACHE OBJECTS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
FT_EXPORT_FUNC(FT_Error) FTC_Glyph_Cache_Init( FTC_Glyph_Cache cache )
|
||||
{
|
||||
FT_Memory memory = cache->root.memory;
|
||||
FT_Error error;
|
||||
|
||||
/* set up root node_class to be used by manager */
|
||||
cache->root.node_clazz = (FTC_CacheNode_Class*)&ftc_glyph_cache_node_class;
|
||||
|
||||
/* The following is extremely important for ftc_destroy_glyph_image */
|
||||
/* to work properly, as the second parameter that is sent to it */
|
||||
/* through the cache manager is "user_data" and must be set to */
|
||||
/* "cache" here.. */
|
||||
/* */
|
||||
cache->root.cache_user = cache;
|
||||
|
||||
error = FT_Lru_New( &ftc_glyph_queue_lru_class,
|
||||
FTC_MAX_GLYPH_QUEUES,
|
||||
cache,
|
||||
memory,
|
||||
1, /* pre_alloc == TRUE */
|
||||
&cache->queues_lru );
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_FUNC(void) FTC_Glyph_Cache_Done( FTC_Glyph_Cache cache )
|
||||
{
|
||||
/* discard Glyph queues */
|
||||
FT_Lru_Done( cache->queues_lru );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* END */
|
|
@ -1,146 +1,58 @@
|
|||
/***************************************************************************/
|
||||
/* */
|
||||
/* ftcimage.c */
|
||||
/* */
|
||||
/* FreeType Image Cache (body). */
|
||||
/* */
|
||||
/* Copyright 2000 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. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
#ifdef FT_FLAT_COMPILE
|
||||
# include "ftcimage.h"
|
||||
#else
|
||||
# include <cache/ftcimage.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <cache/ftcimage.h>
|
||||
#include <freetype/fterrors.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
#include <freetype/internal/ftlist.h>
|
||||
#include <freetype/fterrors.h>
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/***** *****/
|
||||
/***** IMAGE NODE MANAGEMENT *****/
|
||||
/***** *****/
|
||||
/***** For now, we simply ALLOC/FREE the FTC_ImageNode. However, it *****/
|
||||
/***** certainly is a good idea to use a chunk manager in the future *****/
|
||||
/***** in order to reduce memory waste resp. fragmentation. *****/
|
||||
/***** *****/
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH IMAGE NODES *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
static
|
||||
FT_Error FTC_ImageNode_New( FTC_Image_Cache cache,
|
||||
FTC_ImageNode* anode )
|
||||
/* this is a simple glyph image destructor, which is called exclusively */
|
||||
/* from the CacheQueue object */
|
||||
LOCAL_FUNC_X
|
||||
void ftc_glyph_image_node_destroy( FTC_GlyphNode node,
|
||||
FTC_Glyph_Queue queue )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Memory memory = cache->memory;
|
||||
FTC_ImageNode node;
|
||||
FT_Memory memory = queue->memory;
|
||||
|
||||
|
||||
*anode = 0;
|
||||
if ( !ALLOC( node, sizeof ( *node ) ) )
|
||||
*anode = node;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void FTC_ImageNode_Done( FTC_Image_Cache cache,
|
||||
FTC_ImageNode node )
|
||||
{
|
||||
/* for now, we simply discard the node; we may later add a chunk */
|
||||
/* manager to the image cache. */
|
||||
FT_Memory memory = cache->memory;
|
||||
|
||||
|
||||
FT_Done_Glyph( FTC_GLYPHNODE_GET_GLYPH( node ) );
|
||||
FREE( node );
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH IMAGE QUEUES *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
void ftc_done_glyph_image( FTC_Image_Queue queue,
|
||||
FTC_ImageNode node )
|
||||
{
|
||||
FT_UNUSED( queue );
|
||||
|
||||
FT_Done_Glyph( FTC_IMAGENODE_GET_GLYPH( node ) );
|
||||
}
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_ULong ftc_size_bitmap_image( FTC_Image_Queue queue,
|
||||
FTC_ImageNode node )
|
||||
{
|
||||
FT_Long pitch;
|
||||
FT_BitmapGlyph glyph;
|
||||
|
||||
FT_UNUSED( queue );
|
||||
|
||||
|
||||
glyph = (FT_BitmapGlyph)FTC_IMAGENODE_GET_GLYPH(node);
|
||||
pitch = glyph->bitmap.pitch;
|
||||
if ( pitch < 0 )
|
||||
pitch = -pitch;
|
||||
|
||||
return (FT_ULong)(pitch * glyph->bitmap.rows + sizeof ( *glyph ) );
|
||||
}
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_ULong ftc_size_outline_image( FTC_Image_Queue queue,
|
||||
FTC_ImageNode node )
|
||||
{
|
||||
FT_OutlineGlyph glyph;
|
||||
FT_Outline* outline;
|
||||
|
||||
FT_UNUSED( queue );
|
||||
|
||||
|
||||
glyph = (FT_OutlineGlyph)FTC_IMAGENODE_GET_GLYPH( node );
|
||||
outline = &glyph->outline;
|
||||
|
||||
return (FT_ULong)(
|
||||
outline->n_points * ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) +
|
||||
outline->n_contours * sizeof ( FT_Short ) +
|
||||
sizeof( *glyph ) );
|
||||
}
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Error ftc_init_glyph_image( FTC_Image_Queue queue,
|
||||
FTC_ImageNode node )
|
||||
FT_Error ftc_glyph_image_node_new( FTC_Glyph_Queue queue,
|
||||
FT_UInt glyph_index,
|
||||
FTC_GlyphNode *anode )
|
||||
{
|
||||
FT_Face face;
|
||||
FT_Size size;
|
||||
FT_Error error;
|
||||
FT_Memory memory = queue->memory;
|
||||
FTC_Image_Queue imageq = (FTC_Image_Queue)queue;
|
||||
FT_Error error;
|
||||
FTC_GlyphNode node = 0;
|
||||
FT_Face face;
|
||||
FT_Size size;
|
||||
|
||||
/* allocate node */
|
||||
if ( ALLOC( node, sizeof(*node) ) )
|
||||
goto Exit;
|
||||
|
||||
/* init its inner fields */
|
||||
FTC_GlyphNode_Init( node, queue, glyph_index );
|
||||
|
||||
/* we will now load the glyph image */
|
||||
error = FTC_Manager_Lookup_Size( queue->manager,
|
||||
&queue->descriptor.size,
|
||||
&imageq->description.font,
|
||||
&face, &size );
|
||||
if ( !error )
|
||||
{
|
||||
FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
|
||||
FT_UInt glyph_index = node->glyph_index;
|
||||
FT_UInt load_flags = FT_LOAD_DEFAULT;
|
||||
FT_UInt image_type = queue->descriptor.image_type;
|
||||
FT_UInt image_type = imageq->description.image_type;
|
||||
|
||||
if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
|
||||
{
|
||||
|
@ -179,373 +91,134 @@
|
|||
|
||||
error = FT_Get_Glyph( face->glyph, &glyph );
|
||||
if ( !error )
|
||||
FTC_IMAGENODE_SET_GLYPH( node, glyph );
|
||||
FTC_GLYPHNODE_SET_GLYPH( node, glyph );
|
||||
}
|
||||
else
|
||||
error = FT_Err_Invalid_Argument;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_CPLUSPLUS( const FTC_Image_Class ) ftc_bitmap_image_class =
|
||||
{
|
||||
ftc_init_glyph_image,
|
||||
ftc_done_glyph_image,
|
||||
ftc_size_bitmap_image
|
||||
};
|
||||
|
||||
FT_CPLUSPLUS( const FTC_Image_Class ) ftc_outline_image_class =
|
||||
{
|
||||
ftc_init_glyph_image,
|
||||
ftc_done_glyph_image,
|
||||
ftc_size_outline_image
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
FT_Error FTC_Image_Queue_New( FTC_Image_Cache cache,
|
||||
FTC_Image_Desc* desc,
|
||||
FTC_Image_Queue* aqueue )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Memory memory = cache->memory;
|
||||
FTC_Manager manager = cache->manager;
|
||||
FTC_Image_Queue queue = 0;
|
||||
|
||||
const FTC_Image_Class* clazz;
|
||||
|
||||
|
||||
*aqueue = 0;
|
||||
if ( ALLOC( queue, sizeof ( *queue ) ) )
|
||||
goto Exit;
|
||||
|
||||
queue->cache = cache;
|
||||
queue->manager = manager;
|
||||
queue->memory = memory;
|
||||
queue->descriptor = *desc;
|
||||
queue->hash_size = 64;
|
||||
|
||||
if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) )
|
||||
goto Exit;
|
||||
|
||||
switch ( FTC_IMAGE_FORMAT( desc->image_type ) )
|
||||
{
|
||||
case ftc_image_format_bitmap:
|
||||
clazz = &ftc_bitmap_image_class;
|
||||
break;
|
||||
|
||||
case ftc_image_format_outline:
|
||||
clazz = &ftc_outline_image_class;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* invalid image type! */
|
||||
error = FT_Err_Invalid_Argument;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
queue->clazz = (FTC_Image_Class*)clazz;
|
||||
*aqueue = queue;
|
||||
|
||||
Exit:
|
||||
if ( error )
|
||||
FREE( queue );
|
||||
if (error && node)
|
||||
FREE(node);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void FTC_Image_Queue_Done( FTC_Image_Queue queue )
|
||||
{
|
||||
FTC_Image_Cache cache = queue->cache;
|
||||
FT_List glyphs_lru = &cache->glyphs_lru;
|
||||
FT_List bucket = queue->buckets;
|
||||
FT_List bucket_limit = bucket + queue->hash_size;
|
||||
FT_Memory memory = cache->memory;
|
||||
|
||||
|
||||
/* for each bucket, free the list of image nodes */
|
||||
for ( ; bucket < bucket_limit; bucket++ )
|
||||
{
|
||||
FT_ListNode node = bucket->head;
|
||||
FT_ListNode next = 0;
|
||||
FT_ListNode lrunode;
|
||||
FTC_ImageNode inode;
|
||||
|
||||
|
||||
for ( ; node; node = next )
|
||||
{
|
||||
next = node->next;
|
||||
inode = (FTC_ImageNode)node;
|
||||
lrunode = FTC_IMAGENODE_TO_LISTNODE( inode );
|
||||
|
||||
cache->num_bytes -= queue->clazz->size_image( queue, inode ) +
|
||||
sizeof( FTC_ImageNodeRec );
|
||||
|
||||
queue->clazz->done_image( queue, inode );
|
||||
FT_List_Remove( glyphs_lru, lrunode );
|
||||
|
||||
FTC_ImageNode_Done( cache, inode );
|
||||
}
|
||||
|
||||
bucket->head = bucket->tail = 0;
|
||||
}
|
||||
|
||||
FREE( queue->buckets );
|
||||
FREE( queue );
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
FT_Error FTC_Image_Queue_Lookup_Node( FTC_Image_Queue queue,
|
||||
FT_UInt glyph_index,
|
||||
FTC_ImageNode* anode )
|
||||
{
|
||||
FTC_Image_Cache cache = queue->cache;
|
||||
FT_UInt hash_index = glyph_index % queue->hash_size;
|
||||
FT_List bucket = queue->buckets + hash_index;
|
||||
FT_ListNode node;
|
||||
FT_Error error;
|
||||
FTC_ImageNode inode;
|
||||
|
||||
|
||||
*anode = 0;
|
||||
for ( node = bucket->head; node; node = node->next )
|
||||
{
|
||||
FT_UInt gindex;
|
||||
|
||||
inode = (FTC_ImageNode)node;
|
||||
gindex = FTC_IMAGENODE_GET_GINDEX( inode );
|
||||
|
||||
if ( gindex == glyph_index )
|
||||
{
|
||||
/* we found it! -- move glyph to start of the list */
|
||||
FT_List_Up( bucket, node );
|
||||
FT_List_Up( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) );
|
||||
*anode = inode;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* we didn't found the glyph image, we will now create a new one */
|
||||
error = FTC_ImageNode_New( queue->cache, &inode );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* set the glyph and queue indices in the image node */
|
||||
FTC_IMAGENODE_SET_INDICES( inode, glyph_index, queue->index );
|
||||
|
||||
error = queue->clazz->init_image( queue, inode );
|
||||
if ( error )
|
||||
{
|
||||
FTC_ImageNode_Done( queue->cache, inode );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* insert the node at the start of our bucket list */
|
||||
FT_List_Insert( bucket, (FT_ListNode)inode );
|
||||
|
||||
/* insert the node at the start the global LRU glyph list */
|
||||
FT_List_Insert( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) );
|
||||
|
||||
cache->num_bytes += queue->clazz->size_image( queue, inode ) +
|
||||
sizeof( FTC_ImageNodeRec );
|
||||
|
||||
*anode = inode;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** IMAGE CACHE CALLBACKS *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
#define FTC_QUEUE_LRU_GET_CACHE( lru ) \
|
||||
( (FTC_Image_Cache)(lru)->user_data )
|
||||
#define FTC_QUEUE_LRU_GET_MANAGER( lru ) \
|
||||
FTC_QUEUE_LRU_GET_CACHE( lru )->manager
|
||||
#define FTC_LRUNODE_QUEUE( node ) \
|
||||
( (FTC_Image_Queue)(node)->root.data )
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Error ftc_image_cache_init_queue( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
{
|
||||
FTC_Image_Cache cache = FTC_QUEUE_LRU_GET_CACHE( lru );
|
||||
FTC_Image_Desc* desc = (FTC_Image_Desc*)node->key;
|
||||
FT_Error error;
|
||||
FTC_Image_Queue queue;
|
||||
|
||||
|
||||
error = FTC_Image_Queue_New( cache, desc, &queue );
|
||||
if ( !error )
|
||||
{
|
||||
/* good, now set the queue index within the queue object */
|
||||
queue->index = node - lru->nodes;
|
||||
node->root.data = queue;
|
||||
}
|
||||
|
||||
*anode = node;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* this function is important, because it is both part of */
|
||||
/* a FTC_Glyph_Queue_Class and a FTC_CacheNode_Class */
|
||||
/* */
|
||||
LOCAL_FUNC_X
|
||||
void ftc_image_cache_done_queue( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
FT_ULong ftc_glyph_image_node_size( FTC_GlyphNode node )
|
||||
{
|
||||
FTC_Image_Queue queue = FTC_LRUNODE_QUEUE( node );
|
||||
FT_ULong size = 0;
|
||||
FT_Glyph glyph = FTC_GLYPHNODE_GET_GLYPH(node);
|
||||
|
||||
FT_UNUSED( lru );
|
||||
|
||||
|
||||
FTC_Image_Queue_Done( queue );
|
||||
}
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Bool ftc_image_cache_compare_queue( FT_LruNode node,
|
||||
FT_LruKey key )
|
||||
{
|
||||
FTC_Image_Queue queue = FTC_LRUNODE_QUEUE( node );
|
||||
FTC_Image_Desc* desc2 = (FTC_Image_Desc*)key;
|
||||
FTC_Image_Desc* desc1 = &queue->descriptor;
|
||||
|
||||
|
||||
return ( desc1->size.face_id == desc2->size.face_id &&
|
||||
desc1->size.pix_width == desc2->size.pix_width &&
|
||||
desc1->size.pix_height == desc2->size.pix_height &&
|
||||
desc1->image_type == desc2->image_type );
|
||||
}
|
||||
|
||||
|
||||
FT_CPLUSPLUS( const FT_Lru_Class ) ftc_image_queue_lru_class =
|
||||
{
|
||||
sizeof( FT_LruRec ),
|
||||
ftc_image_cache_init_queue,
|
||||
ftc_image_cache_done_queue,
|
||||
0, /* no flush */
|
||||
ftc_image_cache_compare_queue
|
||||
};
|
||||
|
||||
|
||||
/* compress image cache if necessary, i.e., discard all old glyph images */
|
||||
/* until `cache.num_bytes' is less than `cache.max_bytes'. Note that */
|
||||
/* this function will avoid to remove `new_node'. */
|
||||
static
|
||||
void FTC_Image_Cache_Compress( FTC_Image_Cache cache,
|
||||
FTC_ImageNode new_node )
|
||||
{
|
||||
while ( cache->num_bytes > cache->max_bytes )
|
||||
switch (glyph->format)
|
||||
{
|
||||
FT_ListNode cur;
|
||||
FTC_Image_Queue queue;
|
||||
FT_UInt glyph_index;
|
||||
FT_UInt hash_index;
|
||||
FT_UInt queue_index;
|
||||
FT_ULong size;
|
||||
FTC_ImageNode inode;
|
||||
|
||||
|
||||
/* exit our loop if there isn't any glyph image left, or if */
|
||||
/* we reached the newly created node (which happens always at the */
|
||||
/* start of the list) */
|
||||
|
||||
cur = cache->glyphs_lru.tail;
|
||||
inode = FTC_LISTNODE_TO_IMAGENODE( cur );
|
||||
if ( !cur || inode == new_node )
|
||||
case ft_glyph_format_bitmap:
|
||||
{
|
||||
FT_BitmapGlyph bitg;
|
||||
|
||||
bitg = (FT_BitmapGlyph)glyph;
|
||||
size = bitg->bitmap.rows * labs(bitg->bitmap.pitch) +
|
||||
sizeof(*bitg);
|
||||
}
|
||||
break;
|
||||
|
||||
glyph_index = FTC_IMAGENODE_GET_GINDEX( inode );
|
||||
queue_index = FTC_IMAGENODE_GET_QINDEX( inode );
|
||||
queue = (FTC_Image_Queue)cache->queues_lru->
|
||||
nodes[queue_index].root.data;
|
||||
hash_index = glyph_index % queue->hash_size;
|
||||
size = queue->clazz->size_image( queue, inode ) +
|
||||
sizeof(FTC_ImageNodeRec);
|
||||
|
||||
FT_List_Remove( &cache->glyphs_lru, cur );
|
||||
FT_List_Remove( queue->buckets + hash_index, (FT_ListNode)inode );
|
||||
queue->clazz->done_image( queue, inode );
|
||||
FTC_ImageNode_Done( cache, inode );
|
||||
|
||||
cache->num_bytes -= size;
|
||||
case ft_glyph_format_outline:
|
||||
{
|
||||
FT_OutlineGlyph outg;
|
||||
|
||||
outg = (FT_OutlineGlyph)glyph;
|
||||
size = outg->outline.n_points *
|
||||
( sizeof( FT_Vector ) + sizeof( FT_Byte ) ) +
|
||||
outg->outline.n_contours *
|
||||
sizeof( FT_Short ) +
|
||||
sizeof(*outg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
size += sizeof(*node);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager,
|
||||
FT_ULong max_bytes,
|
||||
FTC_Image_Cache* acache )
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH IMAGE QUEUES *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Error ftc_image_queue_init( FTC_Image_Queue queue,
|
||||
FTC_Image_Desc* type )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Memory memory;
|
||||
FTC_Image_Cache cache;
|
||||
|
||||
|
||||
if ( !manager )
|
||||
return FT_Err_Invalid_Cache_Handle;
|
||||
|
||||
if ( !acache || !manager->library )
|
||||
return FT_Err_Invalid_Argument;
|
||||
|
||||
*acache = 0;
|
||||
memory = manager->library->memory;
|
||||
|
||||
if ( ALLOC( cache, sizeof ( *cache ) ) )
|
||||
goto Exit;
|
||||
|
||||
cache->manager = manager;
|
||||
cache->memory = manager->library->memory;
|
||||
cache->max_bytes = max_bytes;
|
||||
|
||||
error = FT_Lru_New( &ftc_image_queue_lru_class,
|
||||
FTC_MAX_IMAGE_QUEUES,
|
||||
cache,
|
||||
memory,
|
||||
1, /* pre_alloc == TRUE */
|
||||
&cache->queues_lru );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
*acache = cache;
|
||||
|
||||
Exit:
|
||||
if ( error )
|
||||
FREE( cache );
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache )
|
||||
{
|
||||
FT_Memory memory;
|
||||
|
||||
|
||||
if ( !cache )
|
||||
return;
|
||||
|
||||
memory = cache->memory;
|
||||
|
||||
/* discard image queues */
|
||||
FT_Lru_Done( cache->queues_lru );
|
||||
|
||||
/* discard cache */
|
||||
FREE( cache );
|
||||
queue->description = *type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Bool ftc_image_queue_compare( FTC_Image_Queue queue,
|
||||
FTC_Image_Desc* type )
|
||||
{
|
||||
return !memcmp( &queue->description, type, sizeof(*type) );
|
||||
}
|
||||
|
||||
|
||||
FT_CPLUSPLUS(const FTC_Glyph_Queue_Class) ftc_glyph_image_queue_class =
|
||||
{
|
||||
sizeof( FTC_Image_QueueRec ),
|
||||
|
||||
(FTC_Glyph_Queue_InitFunc) ftc_image_queue_init,
|
||||
(FTC_Glyph_Queue_DoneFunc) 0,
|
||||
(FTC_Glyph_Queue_CompareFunc) ftc_image_queue_compare,
|
||||
|
||||
(FTC_Glyph_Queue_NewNodeFunc) ftc_glyph_image_node_new,
|
||||
(FTC_Glyph_Queue_SizeNodeFunc) ftc_glyph_image_node_size,
|
||||
(FTC_Glyph_Queue_DestroyNodeFunc) ftc_glyph_image_node_destroy
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** GLYPH IMAGE CACHE *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
|
||||
FT_CPLUSPLUS(const FTC_Glyph_Cache_Class) ftc_glyph_image_cache_class =
|
||||
{
|
||||
{
|
||||
sizeof( FTC_Glyph_CacheRec ),
|
||||
(FTC_Cache_InitFunc) FTC_Glyph_Cache_Init,
|
||||
(FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done
|
||||
},
|
||||
(FTC_Glyph_Queue_Class*) &ftc_glyph_image_queue_class
|
||||
};
|
||||
|
||||
|
||||
FT_EXPORT_FUNC( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager,
|
||||
FTC_Image_Cache* acache )
|
||||
{
|
||||
return FTC_Manager_Register_Cache(
|
||||
manager,
|
||||
(FTC_Cache_Class*)&ftc_glyph_image_cache_class,
|
||||
(FTC_Cache*)acache );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_Lookup(
|
||||
FTC_Image_Cache cache,
|
||||
FTC_Image_Desc* desc,
|
||||
|
@ -553,43 +226,47 @@
|
|||
FT_Glyph* aglyph )
|
||||
{
|
||||
FT_Error error;
|
||||
FTC_Image_Queue queue;
|
||||
FTC_ImageNode inode;
|
||||
FTC_Glyph_Queue queue;
|
||||
FTC_GlyphNode inode;
|
||||
FTC_Manager manager;
|
||||
|
||||
FTC_Image_Queue img_queue;
|
||||
|
||||
/* check for valid `desc' delayed to FT_Lru_Lookup() */
|
||||
|
||||
if ( !cache || !aglyph )
|
||||
return FT_Err_Invalid_Argument;
|
||||
|
||||
*aglyph = 0;
|
||||
queue = cache->last_queue;
|
||||
if ( !queue ||
|
||||
queue->descriptor.size.face_id != desc->size.face_id ||
|
||||
queue->descriptor.size.pix_width != desc->size.pix_width ||
|
||||
queue->descriptor.size.pix_height != desc->size.pix_height ||
|
||||
queue->descriptor.image_type != desc->image_type )
|
||||
*aglyph = 0;
|
||||
queue = cache->root.last_queue;
|
||||
img_queue = (FTC_Image_Queue)queue;
|
||||
if ( !queue || memcmp( &img_queue->description, desc, sizeof(*desc) ) )
|
||||
{
|
||||
error = FT_Lru_Lookup( cache->queues_lru,
|
||||
error = FT_Lru_Lookup( cache->root.queues_lru,
|
||||
(FT_LruKey)desc,
|
||||
(FT_Pointer*)&queue );
|
||||
cache->last_queue = queue;
|
||||
cache->root.last_queue = queue;
|
||||
if ( error )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
error = FTC_Image_Queue_Lookup_Node( queue, gindex, &inode );
|
||||
error = FTC_Glyph_Queue_Lookup_Node( queue, gindex, &inode );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
if (cache->num_bytes > cache->max_bytes)
|
||||
FTC_Image_Cache_Compress( cache, inode );
|
||||
/* now compress the manager's cache pool if needed */
|
||||
manager = cache->root.root.manager;
|
||||
if (manager->num_bytes > manager->max_bytes)
|
||||
{
|
||||
FTC_GlyphNode_Ref(inode);
|
||||
FTC_Manager_Compress( manager );
|
||||
FTC_GlyphNode_Unref(inode);
|
||||
}
|
||||
|
||||
*aglyph = FTC_IMAGENODE_GET_GLYPH( inode );
|
||||
*aglyph = FTC_GLYPHNODE_GET_GLYPH( inode );
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -1,137 +1,21 @@
|
|||
/***************************************************************************/
|
||||
/* */
|
||||
/* ftcimage.h */
|
||||
/* */
|
||||
/* FreeType Image Cache (specification). */
|
||||
/* */
|
||||
/* Copyright 2000 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 FTCIMAGE_H
|
||||
#define FTCIMAGE_H
|
||||
|
||||
#include <cache/ftcmanag.h>
|
||||
#include <freetype/ftglyph.h>
|
||||
#include <stddef.h>
|
||||
#include <freetype/cache/ftcglyph.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FTC_MAX_IMAGE_QUEUES 16
|
||||
|
||||
typedef struct FTC_Image_QueueRec_* FTC_Image_Queue;
|
||||
typedef struct FTC_ImageNodeRec_* FTC_ImageNode;
|
||||
/* the glyph image queue type */
|
||||
typedef struct FTC_Image_QueueRec_
|
||||
{
|
||||
FTC_Glyph_QueueRec root;
|
||||
FTC_Image_Desc description;
|
||||
|
||||
} FTC_Image_QueueRec, *FTC_Image_Queue;
|
||||
|
||||
/* macros used to pack a glyph index and a queue index in a single ptr */
|
||||
#define FTC_PTR_TO_GINDEX( p ) ( (FT_UInt)( (FT_ULong)(p) >> 16 ) )
|
||||
#define FTC_PTR_TO_QINDEX( p ) ( (FT_UInt)( (FT_ULong)(p) & 0xFFFF ) )
|
||||
#define FTC_INDICES_TO_PTR( g, q ) \
|
||||
( (FT_Pointer)( ( (FT_ULong)(g) << 16 ) | \
|
||||
( (FT_ULong)(q) & 0xFFFF) ) )
|
||||
|
||||
typedef struct FTC_ImageNodeRec_
|
||||
typedef struct FTC_Image_CacheRec_
|
||||
{
|
||||
/* root1.data contains an FT_Glyph handle */
|
||||
FT_ListNodeRec root1;
|
||||
|
||||
/* root2.data contains a glyph index + queue index */
|
||||
FT_ListNodeRec root2;
|
||||
|
||||
} FTC_ImageNodeRec;
|
||||
|
||||
|
||||
/* macros to read/set the glyph & queue index in a FTC_ImageNode */
|
||||
#define FTC_IMAGENODE_GET_GINDEX( n ) FTC_PTR_TO_GINDEX( (n)->root2.data )
|
||||
#define FTC_IMAGENODE_GET_QINDEX( n ) FTC_PTR_TO_QINDEX( (n)->root2.data )
|
||||
#define FTC_IMAGENODE_GET_GLYPH( n ) ( (FT_Glyph)(n)->root1.data )
|
||||
#define FTC_IMAGENODE_SET_GLYPH( n, g ) \
|
||||
do \
|
||||
{ \
|
||||
(n)->root1.data = g; \
|
||||
} while ( 0 )
|
||||
|
||||
#define FTC_IMAGENODE_SET_INDICES( n, g, q ) \
|
||||
do \
|
||||
{ \
|
||||
(n)->root2.data = FTC_INDICES_TO_PTR( g, q ); \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
/* this macro is used to extract a handle to the global LRU list node */
|
||||
/* corresponding to a given image node */
|
||||
#define FTC_IMAGENODE_TO_LISTNODE( n ) \
|
||||
( (FT_ListNode)&(n)->root2 )
|
||||
|
||||
/* this macro is used to extract a handle to a given image node from */
|
||||
/* the corresponding LRU glyph list node. That's a bit hackish.. */
|
||||
#define FTC_LISTNODE_TO_IMAGENODE( p ) \
|
||||
( (FTC_ImageNode)( (char*)(p) - \
|
||||
offsetof( FTC_ImageNodeRec,root2 ) ) )
|
||||
|
||||
|
||||
typedef struct FTC_Image_CacheRec_
|
||||
{
|
||||
FTC_Manager manager;
|
||||
FT_Memory memory;
|
||||
FTC_Glyph_CacheRec root;
|
||||
|
||||
FT_ULong max_bytes; /* maximum size of cache in bytes */
|
||||
FT_ULong num_bytes; /* current size of cache in bytes */
|
||||
|
||||
FT_Lru queues_lru; /* static queues lru list */
|
||||
FT_ListRec glyphs_lru; /* global lru list of glyph images */
|
||||
|
||||
FTC_Image_Queue last_queue; /* small cache */
|
||||
|
||||
} FTC_Image_CacheRec;
|
||||
|
||||
|
||||
/* a table of functions used to generate/manager glyph images */
|
||||
typedef struct FTC_Image_Class_
|
||||
{
|
||||
FT_Error (*init_image)( FTC_Image_Queue queue,
|
||||
FTC_ImageNode node );
|
||||
|
||||
void (*done_image)( FTC_Image_Queue queue,
|
||||
FTC_ImageNode node );
|
||||
|
||||
FT_ULong (*size_image)( FTC_Image_Queue queue,
|
||||
FTC_ImageNode node );
|
||||
|
||||
} FTC_Image_Class;
|
||||
|
||||
|
||||
typedef struct FTC_Image_QueueRec_
|
||||
{
|
||||
FTC_Image_Cache cache;
|
||||
FTC_Manager manager;
|
||||
FT_Memory memory;
|
||||
FTC_Image_Class* clazz;
|
||||
FTC_Image_Desc descriptor;
|
||||
FT_UInt hash_size;
|
||||
FT_List buckets;
|
||||
FT_UInt index; /* index in parent cache */
|
||||
|
||||
} FTC_Image_QueueRec;
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* FTCIMAGE_H */
|
||||
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -16,9 +16,13 @@
|
|||
/***************************************************************************/
|
||||
|
||||
|
||||
#include <cache/ftcmanag.h>
|
||||
#include <freetype/cache/ftcmanag.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
#include <freetype/internal/ftdebug.h>
|
||||
#include <freetype/ftlist.h>
|
||||
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT trace_cache
|
||||
|
||||
#define FTC_LRU_GET_MANAGER( lru ) (FTC_Manager)lru->user_data
|
||||
|
||||
|
@ -38,6 +42,7 @@
|
|||
{
|
||||
FTC_Manager manager = FTC_LRU_GET_MANAGER( lru );
|
||||
FT_Error error;
|
||||
FT_Face face;
|
||||
|
||||
|
||||
error = manager->request_face( (FTC_FaceID)node->key,
|
||||
|
@ -47,9 +52,7 @@
|
|||
if ( !error )
|
||||
{
|
||||
/* destroy initial size object; it will be re-created later */
|
||||
FT_Face face = (FT_Face)node->root.data;
|
||||
|
||||
|
||||
face = (FT_Face)node->root.data;
|
||||
FT_Done_Size( face->size );
|
||||
}
|
||||
|
||||
|
@ -89,23 +92,23 @@
|
|||
}
|
||||
|
||||
|
||||
typedef struct FTC_SizeRequest_
|
||||
typedef struct FTC_FontRequest_
|
||||
{
|
||||
FT_Face face;
|
||||
FT_UShort width;
|
||||
FT_UShort height;
|
||||
|
||||
} FTC_SizeRequest;
|
||||
} FTC_FontRequest;
|
||||
|
||||
|
||||
LOCAL_FUNC_X
|
||||
FT_Error ftc_manager_init_size( FT_Lru lru,
|
||||
FT_LruNode node )
|
||||
{
|
||||
FTC_SizeRequest* size_req = (FTC_SizeRequest*)node->key;
|
||||
FTC_FontRequest* font_req = (FTC_FontRequest*)node->key;
|
||||
FT_Size size;
|
||||
FT_Error error;
|
||||
FT_Face face = size_req->face;
|
||||
FT_Face face = font_req->face;
|
||||
|
||||
FT_UNUSED( lru );
|
||||
|
||||
|
@ -116,8 +119,8 @@
|
|||
{
|
||||
face->size = size;
|
||||
error = FT_Set_Pixel_Sizes( face,
|
||||
size_req->width,
|
||||
size_req->height );
|
||||
font_req->width,
|
||||
font_req->height );
|
||||
if ( error )
|
||||
FT_Done_Size( size );
|
||||
else
|
||||
|
@ -142,7 +145,7 @@
|
|||
FT_LruNode node,
|
||||
FT_LruKey key )
|
||||
{
|
||||
FTC_SizeRequest* req = (FTC_SizeRequest*)key;
|
||||
FTC_FontRequest* req = (FTC_FontRequest*)key;
|
||||
FT_Size size = (FT_Size)node->root.data;
|
||||
FT_Error error;
|
||||
|
||||
|
@ -168,7 +171,7 @@
|
|||
FT_Bool ftc_manager_compare_size( FT_LruNode node,
|
||||
FT_LruKey key )
|
||||
{
|
||||
FTC_SizeRequest* req = (FTC_SizeRequest*)key;
|
||||
FTC_FontRequest* req = (FTC_FontRequest*)key;
|
||||
FT_Size size = (FT_Size)node->root.data;
|
||||
|
||||
FT_UNUSED( node );
|
||||
|
@ -203,6 +206,7 @@
|
|||
FT_EXPORT_FUNC( FT_Error ) FTC_Manager_New( FT_Library library,
|
||||
FT_UInt max_faces,
|
||||
FT_UInt max_sizes,
|
||||
FT_ULong max_bytes,
|
||||
FTC_Face_Requester requester,
|
||||
FT_Pointer req_data,
|
||||
FTC_Manager* amanager )
|
||||
|
@ -221,10 +225,13 @@
|
|||
goto Exit;
|
||||
|
||||
if ( max_faces == 0 )
|
||||
max_faces = FTC_MAX_FACES;
|
||||
max_faces = FTC_MAX_FACES_DEFAULT;
|
||||
|
||||
if ( max_sizes == 0 )
|
||||
max_sizes = FTC_MAX_SIZES;
|
||||
max_sizes = FTC_MAX_SIZES_DEFAULT;
|
||||
|
||||
if ( max_bytes == 0 )
|
||||
max_bytes = FTC_MAX_BYTES_DEFAULT;
|
||||
|
||||
error = FT_Lru_New( &ftc_face_lru_class,
|
||||
max_faces,
|
||||
|
@ -245,6 +252,7 @@
|
|||
goto Exit;
|
||||
|
||||
manager->library = library;
|
||||
manager->max_bytes = max_bytes;
|
||||
manager->request_face = requester;
|
||||
manager->request_data = req_data;
|
||||
*amanager = manager;
|
||||
|
@ -264,6 +272,7 @@
|
|||
FT_EXPORT_DEF( void ) FTC_Manager_Done( FTC_Manager manager )
|
||||
{
|
||||
FT_Memory memory;
|
||||
FT_UInt index;
|
||||
|
||||
|
||||
if ( !manager || !manager->library )
|
||||
|
@ -271,19 +280,35 @@
|
|||
|
||||
memory = manager->library->memory;
|
||||
|
||||
/* now discard all caches */
|
||||
for (index = 0; index < FTC_MAX_CACHES; index++ )
|
||||
{
|
||||
FTC_Cache cache = manager->caches[index];
|
||||
|
||||
|
||||
if (cache)
|
||||
{
|
||||
cache->clazz->done_cache( cache );
|
||||
FREE(cache);
|
||||
manager->caches[index] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* discard faces and sizes */
|
||||
FT_Lru_Done( manager->sizes_lru );
|
||||
FT_Lru_Done( manager->faces_lru );
|
||||
|
||||
FREE( manager );
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void ) FTC_Manager_Reset( FTC_Manager manager )
|
||||
{
|
||||
if ( !manager )
|
||||
return;
|
||||
|
||||
FT_Lru_Reset( manager->sizes_lru );
|
||||
FT_Lru_Reset( manager->faces_lru );
|
||||
if (manager )
|
||||
{
|
||||
FT_Lru_Reset( manager->sizes_lru );
|
||||
FT_Lru_Reset( manager->faces_lru );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -298,14 +323,14 @@
|
|||
(FT_LruKey)face_id,
|
||||
(FT_Pointer*)aface );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Size( FTC_Manager manager,
|
||||
FTC_SizeID size_id,
|
||||
FTC_Font font,
|
||||
FT_Face* aface,
|
||||
FT_Size* asize )
|
||||
{
|
||||
FTC_SizeRequest req;
|
||||
FTC_FontRequest req;
|
||||
FT_Error error;
|
||||
FT_Face face;
|
||||
|
||||
|
@ -318,15 +343,15 @@
|
|||
if ( asize )
|
||||
*asize = 0;
|
||||
|
||||
error = FTC_Manager_Lookup_Face( manager, size_id->face_id, &face );
|
||||
error = FTC_Manager_Lookup_Face( manager, font->face_id, &face );
|
||||
if ( !error )
|
||||
{
|
||||
FT_Size size;
|
||||
|
||||
|
||||
req.face = face;
|
||||
req.width = size_id->pix_width;
|
||||
req.height = size_id->pix_height;
|
||||
req.width = font->pix_width;
|
||||
req.height = font->pix_height;
|
||||
|
||||
error = FT_Lru_Lookup( manager->sizes_lru,
|
||||
(FT_LruKey)&req,
|
||||
|
@ -348,4 +373,98 @@
|
|||
}
|
||||
|
||||
|
||||
/* "compress" the manager's data, i.e. get rids of old cache nodes */
|
||||
/* that are not referenced anymore in order to limit the total */
|
||||
/* memory used by the cache.. */
|
||||
FT_EXPORT_FUNC(void) FTC_Manager_Compress( FTC_Manager manager )
|
||||
{
|
||||
FT_ListNode node;
|
||||
|
||||
node = manager->global_lru.tail;
|
||||
while (manager->num_bytes > manager->max_bytes && node)
|
||||
{
|
||||
FTC_CacheNode cache_node = FTC_LIST_TO_CACHENODE(node);
|
||||
FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P(cache_node);
|
||||
FTC_Cache cache;
|
||||
FT_ListNode prev = node->prev;
|
||||
|
||||
if (data->ref_count <= 0)
|
||||
{
|
||||
/* ok, we're going to remove this node */
|
||||
FT_List_Remove( &manager->global_lru, node );
|
||||
|
||||
/* finalize cache node */
|
||||
cache = manager->caches[data->cache_index];
|
||||
if (cache)
|
||||
{
|
||||
FTC_CacheNode_Class* clazz = cache->node_clazz;
|
||||
|
||||
manager->num_bytes -= clazz->size_node( cache_node,
|
||||
cache->cache_user );
|
||||
|
||||
clazz->destroy_node( cache_node, cache->cache_user );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this should never happen !! */
|
||||
FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted !!\n" ));
|
||||
}
|
||||
}
|
||||
node = prev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FT_EXPORT_DEF( FT_Error ) FTC_Manager_Register_Cache(
|
||||
FTC_Manager manager,
|
||||
FTC_Cache_Class* clazz,
|
||||
FTC_Cache *acache )
|
||||
{
|
||||
FT_Error error = FT_Err_Invalid_Argument;
|
||||
|
||||
|
||||
if ( manager && clazz && acache )
|
||||
{
|
||||
FT_Memory memory = manager->library->memory;
|
||||
FTC_Cache cache;
|
||||
FT_UInt index = 0;
|
||||
|
||||
/* by default, return 0 */
|
||||
*acache = 0;
|
||||
|
||||
/* check for an empty cache slot in the manager's table */
|
||||
for ( index = 0; index < FTC_MAX_CACHES; index++ )
|
||||
{
|
||||
if ( manager->caches[index] == 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
/* return an error if there are too many registered caches */
|
||||
if (index >= FTC_MAX_CACHES)
|
||||
{
|
||||
error = FT_Err_Too_Many_Caches;
|
||||
FT_ERROR(( "FTC_Manager_Register_Cache:" ));
|
||||
FT_ERROR(( " too many registered caches..\n" ));
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( !ALLOC( cache, clazz->cache_byte_size ) )
|
||||
{
|
||||
cache->manager = manager;
|
||||
cache->memory = memory;
|
||||
cache->clazz = clazz;
|
||||
|
||||
if (clazz->init_cache)
|
||||
error = clazz->init_cache( cache );
|
||||
|
||||
if (error)
|
||||
FREE(cache);
|
||||
else
|
||||
manager->caches[index] = *acache = cache;
|
||||
}
|
||||
}
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
/***************************************************************************/
|
||||
|
||||
|
||||
#include <cache/ftlru.h>
|
||||
#include <freetype/cache/ftlru.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
#include <freetype/internal/ftlist.h>
|
||||
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
|
||||
# Cache driver directory
|
||||
#
|
||||
Cache_DIR := $(SRC_)cache
|
||||
Cache_DIR_ := $(Cache_DIR)$(SEP)
|
||||
CACHE_DIR := $(SRC_)cache
|
||||
CACHE_DIR_ := $(CACHE_DIR)$(SEP)
|
||||
|
||||
CACHE_H_DIR := $(PUBLIC_)cache
|
||||
CACHE_H_DIR_ := $(CACHE_H_DIR)$(SEP)
|
||||
|
||||
# compilation flags for the driver
|
||||
#
|
||||
|
@ -26,13 +28,17 @@ Cache_COMPILE := $(FT_COMPILE)
|
|||
|
||||
# Cache driver sources (i.e., C files)
|
||||
#
|
||||
Cache_DRV_SRC := $(Cache_DIR_)ftlru.c \
|
||||
$(Cache_DIR_)ftcmanag.c \
|
||||
$(Cache_DIR_)ftcimage.c
|
||||
Cache_DRV_SRC := $(CACHE_DIR_)ftlru.c \
|
||||
$(CACHE_DIR_)ftcmanag.c \
|
||||
$(CACHE_DIR_)ftcglyph.c \
|
||||
$(CACHE_DIR_)ftcimage.c
|
||||
|
||||
# Cache driver headers
|
||||
#
|
||||
Cache_DRV_H := $(Cache_DRV_SRC:%c=%h)
|
||||
Cache_DRV_H := $(CACHE_H_DIR_)ftlru.h \
|
||||
$(CACHE_H_DIR_)ftcmanag.h \
|
||||
$(CACHE_H_DIR_)ftcglyph.h \
|
||||
$(CACHE_DIR_)ftcimage.h
|
||||
|
||||
|
||||
# Cache driver object(s)
|
||||
|
@ -40,12 +46,12 @@ Cache_DRV_H := $(Cache_DRV_SRC:%c=%h)
|
|||
# Cache_DRV_OBJ_M is used during `multi' builds.
|
||||
# Cache_DRV_OBJ_S is used during `single' builds.
|
||||
#
|
||||
Cache_DRV_OBJ_M := $(Cache_DRV_SRC:$(Cache_DIR_)%.c=$(OBJ_)%.$O)
|
||||
Cache_DRV_OBJ_M := $(Cache_DRV_SRC:$(CACHE_DIR_)%.c=$(OBJ_)%.$O)
|
||||
Cache_DRV_OBJ_S := $(OBJ_)ftcache.$O
|
||||
|
||||
# Cache driver source file for single build
|
||||
#
|
||||
Cache_DRV_SRC_S := $(Cache_DIR_)ftcache.c
|
||||
Cache_DRV_SRC_S := $(CACHE_DIR_)ftcache.c
|
||||
|
||||
|
||||
# Cache driver - single object
|
||||
|
@ -57,7 +63,7 @@ $(Cache_DRV_OBJ_S): $(Cache_DRV_SRC_S) $(Cache_DRV_SRC) \
|
|||
|
||||
# Cache driver - multiple objects
|
||||
#
|
||||
$(OBJ_)%.$O: $(Cache_DIR_)%.c $(FREETYPE_H) $(Cache_DRV_H)
|
||||
$(OBJ_)%.$O: $(CACHE_DIR_)%.c $(FREETYPE_H) $(Cache_DRV_H)
|
||||
$(Cache_COMPILE) $T$@ $<
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue