Commit 3752ad97 authored by David Turner's avatar David Turner
Browse files

updated the cache sub-system. Major internal rewrite

please be aware that major bug persist..
parent 2905ff93
......@@ -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
......
/***************************************************************************/
/* */
/* 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 */
This diff is collapsed.
/***************************************************************************/
/* */
/* 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>
#ifdef __cplusplus
extern "C" {
#endif
#define FTC_MAX_IMAGE_QUEUES 16
#include <freetype/cache/ftcglyph.h>
typedef struct FTC_Image_QueueRec_* FTC_Image_Queue;
typedef struct FTC_ImageNodeRec_* FTC_ImageNode;
/* 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_
/* the glyph image queue type */
typedef struct FTC_Image_QueueRec_
{
/* 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 ) ) )
FTC_Glyph_QueueRec root;
FTC_Image_Desc description;
} FTC_Image_QueueRec, *FTC_Image_Queue;
typedef struct FTC_Image_CacheRec_
typedef struct FTC_Image_CacheRec_
{
FTC_Manager manager;
FT_Memory memory;
FT_ULong max_bytes; /* maximum size of cache in bytes */
FT_ULong num_bytes; /* current size of cache in bytes */
FTC_Glyph_CacheRec root;
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;