ref: 3b2c50eb3b7863131ea18350a3ae5d48fbc567b9
parent: 8728f294bcc5d424337e10b33d40077366c79c36
author: David Turner <[email protected]>
date: Wed Aug 23 17:11:13 EDT 2000
completing the FreeType Cache subsystem files
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
LATEST CHANGES
+ - added the cache sub-system. See <freetype/ftcache.h> as well as the
+ sources in "src/cache". Note that it compiles but is still untested
+ for now ..
+
- updated "docs/docmaker.py", a draft API reference is available at
http://www.freetype.org/ft2api.html
--- /dev/null
+++ b/include/freetype/ftcache.h
@@ -1,0 +1,451 @@
+/***************************************************************************/
+/* */
+/* ftcache.h */
+/* */
+/* FreeType Cache subsystem */
+/* */
+/* Copyright 1996-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 FTCACHE_H
+#define FTCACHE_H
+
+#include <freetype/ftglyph.h>
+
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** BASIC TYPE DEFINITIONS *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+
+ /**************************************************************************
+ *
+ * <Type>
+ * FTC_FaceID
+ *
+ * <Description>
+ * a generic pointer type that is used to identity face objects.
+ * the content of such objects is application-dependent
+ *
+ **************************************************************************/
+
+ typedef FT_Pointer FTC_FaceID;
+
+
+
+ /**************************************************************************
+ *
+ * <FuncType>
+ * FTC_Face_Requester
+ *
+ * <Description>
+ * a callback function provided by client applications. It is used
+ * to translate a given FTC_FaceID into a new valid FT_Face object
+ *
+ * <Input>
+ * face_id :: the face id to resolve
+ * library :: handle to a FreeType library object
+ * data :: application-provided request data
+ *
+ * <Output>
+ * aface :: a new FT_Face handle
+ *
+ * <Return>
+ * Error code. 0 means success
+ *
+ **************************************************************************/
+
+ typedef FT_Error (*FTC_Face_Requester)( FTC_FaceID face_id,
+ FT_Library library,
+ FT_Pointer request_data,
+ FT_Face* aface );
+
+
+ /**************************************************************************
+ *
+ * <Struct>
+ * FTC_SizeRec
+ *
+ * <Description>
+ * A simple structure used to describe a given "font size" to the
+ * cache manager
+ *
+ * <Fields>
+ * face_id :: id of face to use
+ * pix_width :: character width in integer pixels
+ * pix_height :: character height in integer pixels
+ *
+ **************************************************************************/
+
+ typedef struct FTC_SizeRec_
+ {
+ FTC_FaceID face_id;
+ FT_UShort pix_width;
+ FT_UShort pix_height;
+
+ } FTC_SizeRec;
+
+
+ /**************************************************************************
+ *
+ * <Type>
+ * FTC_SizeID
+ *
+ * <Description>
+ * A simple handle to a FTC_SizeRec structure
+ *
+ **************************************************************************/
+
+ typedef FTC_SizeRec* FTC_SizeID;
+
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** CACHE MANAGER OBJECT *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+
+
+ /**************************************************************************
+ *
+ * <Type>
+ * FTC_Manager
+ *
+ * <Description>
+ * This object is used to cache one or more FT_Face object, along with
+ * corresponding FT_Size objects.
+ *
+ **************************************************************************/
+
+ typedef struct FTC_ManagerRec_* FTC_Manager;
+
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Manager_New
+ *
+ * <Description>
+ * Create a new cache manager.
+ *
+ * <Input>
+ * library :: the parent FreeType library handle to use
+ *
+ * requester :: an application-provided callback used to translate
+ * face IDs into real FT_Face objects
+ *
+ * req_data :: a generic pointer that is passed to the requester
+ * each time it is called (see FTC_Face_Requester)
+ *
+ * <Output>
+ * amanager :: handle to new manager object. 0 in case of failure
+ *
+ * <Return>
+ * Error code. 0 means success
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( FT_Error ) FTC_Manager_New( FT_Library library,
+ FTC_Face_Requester requester,
+ FT_Pointer req_data,
+ FTC_Manager* amanager );
+
+
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Manager_Reset
+ *
+ * <Description>
+ * Empty a given cache manager. This simply gets rid of all the
+ * currently cached FT_Face & FT_Size objects within the manager
+ *
+ * <Input>
+ * manager :: handle to manager
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( void ) FTC_Manager_Reset( FTC_Manager manager );
+
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Manager_Done
+ *
+ * <Description>
+ * destroys a given manager after emptying it..
+ *
+ * <Input>
+ * manager :: handle to target cache manager object
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( void ) FTC_Manager_Done( FTC_Manager manager );
+
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Manager_Lookup_Face
+ *
+ * <Description>
+ * retrieves the FT_Face that corresponds to a given face ID through
+ * a cache manager.
+ *
+ * <Input>
+ * manager :: handle to cache manager
+ * face_id :: ID of face object
+ *
+ * <Output>
+ * aface :: handle to face object
+ *
+ * <Return>
+ * Error code. 0 means success
+ *
+ * <Note>
+ * The returned FT_Face object is always owned by the manager, you
+ * should never try to discard it yourself..
+ *
+ * The FT_Face object doesn't necessarily have a current size object
+ * (i.e. face->size can be 0). If you need a specific "font size",
+ * use FTC_Manager_Lookup_Size instead..
+ *
+ * Never change the face's transform (i.e. NEVER CALL FT_Set_Transform)
+ * on a returned face. If you need to transform glyphs, do it yourself
+ * after glyph loading..
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Face( FTC_Manager manager,
+ FTC_FaceID face_id,
+ FT_Face* aface );
+
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Manager_Lookup_Size
+ *
+ * <Description>
+ * retrieves the FT_Face & FT_Size that correspond to a given
+ * FTC_SizeID
+ *
+ * <Input>
+ * manager :: handle to cache manager.
+ * size_id :: ID of the "font size" to use
+ *
+ * <InOut>
+ * aface :: ptr to handle to face object. Set to 0 if you don't need it
+ * asize :: ptr to handle to size object. Set to 0 if you don't need it
+ *
+ * <Return>
+ * Error code. 0 means success
+ *
+ * <Note>
+ * The returned FT_Face object is always owned by the manager, you
+ * should never try to discard it yourself..
+ *
+ * Never change the face's transform (i.e. NEVER CALL FT_Set_Transform)
+ * on a returned face. If you need to transform glyphs, do it yourself
+ * after glyph loading..
+ *
+ * The returned FT_Size object is always owned by the manager, you
+ * should never try to discard it, NEVER CHANGE ITS SETTINGS THROUGH
+ * FT_Set_Pixel_Sizes OR FT_Set_Char_Size !!
+ *
+ * The returned size object is the face's current size, which means
+ * that you can call FT_Load_Glyph with the face if you need to..
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Size( FTC_Manager manager,
+ FTC_SizeID size_id,
+ FT_Face* aface,
+ FT_Size* asize );
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** IMAGE CACHE OBJECT *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+ /**************************************************************************
+ *
+ * <Enum>
+ * FTC_Image_Type
+ *
+ * <Description>
+ * An enumeration used to list the types of glyph images found in a
+ * glyph image cache.
+ *
+ * <Fields>
+ * ftc_image_mono :: monochrome bitmap glyphs
+ * ftc_image_grays :: anti-aliased bitmap glyphs
+ * ftc_image_outline :: scaled (and hinted) outline glyphs
+ * ftc_master_outline :: unscaled original outline glyphs
+ *
+ * <Note>
+ * other types may be defined in the future
+ *
+ **************************************************************************/
+
+ typedef enum FTC_Image_Type_
+ {
+ ftc_image_mono = 0, /* monochrome bitmap */
+ ftc_image_grays, /* anti-aliased bitmap */
+ ftc_image_outline, /* scaled outline */
+ ftc_image_master_outline /* original outline */
+
+ } FTC_Image_Type;
+
+
+ /**************************************************************************
+ *
+ * <Struct>
+ * FTC_Image_Desc
+ *
+ * <Description>
+ * A simple structure used to describe a given glyph image category
+ *
+ * <Fields>
+ * size :: a FTC_SizeRec used to describe the glyph's face & size
+ * image_type :: the glyph image's type
+ *
+ **************************************************************************/
+
+ typedef struct FTC_Image_Desc_
+ {
+ FTC_SizeRec size;
+ FT_UInt image_type;
+
+ } FTC_Image_Desc;
+
+
+
+ /**************************************************************************
+ *
+ * <Type>
+ * FTC_Image_Cache
+ *
+ * <Description>
+ * A handle to an glyph image cache object.. They are designed to
+ * hold many distinct glyph images, while not exceeding a certain
+ * memory threshold..
+ *
+ **************************************************************************/
+
+ typedef struct FTC_Image_CacheRec_* FTC_Image_Cache;
+
+
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Image_Cache_New
+ *
+ * <Description>
+ * Create a new glyph image cache.
+ *
+ * <Input>
+ * manager :: parent manager for the image cache
+ *
+ * max_bytes :: the maximum amount of memory that will be used to
+ * store glyph images
+ *
+ * <Output>
+ * acache :: handle to new glyph image cache object
+ *
+ * <Return>
+ * Error code. 0 means success
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager,
+ FT_ULong max_bytes,
+ FTC_Image_Cache* acache );
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Image_Cache_Done
+ *
+ * <Description>
+ * Destroys a given glyph image cache (and all glyphs within it).
+ *
+ * <Input>
+ * manager :: parent manager for the image cache
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache );
+
+
+ /**************************************************************************
+ *
+ * <Function>
+ * FTC_Image_Cache_Lookup
+ *
+ * <Description>
+ * Retrieve a given glyph image from a glyph image cache.
+ *
+ * <Input>
+ * cache :: handle to source glyph image cache
+ * desc :: pointer to a glyph image descriptor
+ * gindex :: index of glyph to retrieve
+ *
+ * <Output>
+ * aglyph :: the corresponding FT_Glyph object. 0 in case of failure
+ *
+ * <Return>
+ * Error code. 0 means success
+ *
+ * <Note>
+ * the returned glyph is owned and manager by the glyph image cache,
+ * never try to transform or discard it manually. You can however
+ * create a copy with FT_Glyph_Copy and modify the new one at will.
+ *
+ * Because the glyph image cache limits the total amount of memory
+ * taken by the glyphs it holds, the returned glyph might disappear
+ * on a later invocation of this function !! It's a cache after all ;-)
+ *
+ **************************************************************************/
+
+ FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_Lookup(
+ FTC_Image_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FT_Glyph* aglyph );
+
+
+#endif /* FTCACHE_H */
--- /dev/null
+++ b/src/cache/ftcache.c
@@ -1,0 +1,36 @@
+/***************************************************************************/
+/* */
+/* ftcache.c */
+/* */
+/* The FreeType Caching sub-system */
+/* */
+/* Copyright 1996-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. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#ifdef FT_FLAT_COMPILE
+
+#include "ftlru.c"
+#include "ftcmanag.c"
+#include "ftcimage.c"
+
+#else
+
+#include <cache/ftlru.c>
+#include <cache/ftcmanag.c>
+#include <cache/ftcimage.c>
+
+#endif
+
+
+/* END */
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -17,8 +17,61 @@
#include <cache/ftcimage.h>
+#include <freetype/fterrors.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftlist.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/fragmentation *****/
+ /***** *****/
+ /***********************************************************************/
+ /***********************************************************************/
+
+
static
+ FT_Error FTC_ImageNode_New( FTC_Image_Cache cache,
+ FTC_ImageNode *anode )
+ {
+ FT_Error error;
+ FT_Memory memory = cache->memory;
+ FTC_ImageNode node;
+
+ *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;
+ FREE( node );
+ }
+
+
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE QUEUES *****/
+ /***** *****/
+ /***********************************************************************/
+ /***********************************************************************/
+
+
+ static
void ftc_done_glyph_image( FTC_Image_Queue queue,
FTC_ImageNode node )
{
@@ -43,7 +96,7 @@
if ( pitch < 0 )
pitch = -pitch;
- return (FT_ULong)(pitch * glyph->bitmap->rows + sizeof ( *glyph ) );
+ return (FT_ULong)(pitch * glyph->bitmap.rows + sizeof ( *glyph ) );
}
@@ -51,7 +104,6 @@
FT_ULong ftc_size_outline_image( FTC_Image_Queue queue,
FTC_ImageNode node )
{
- FT_Long pitch;
FT_OutlineGlyph glyph;
FT_Outline* outline;
@@ -68,14 +120,6 @@
}
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** MONOCHROME BITMAP CALLBACKS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
static
FT_Error ftc_init_mono_image( FTC_Image_Queue queue,
FTC_ImageNode node )
@@ -84,13 +128,12 @@
FT_Size size;
FT_Error error;
-
error = FTC_Manager_Lookup_Size( queue->manager,
- &queue->size_rec,
+ &queue->descriptor.size,
&face, &size );
if ( !error )
{
- FT_UInt glyph_index = FTC_IMAGENODE_GINDEX( node );
+ FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
error = FT_Load_Glyph( face, glyph_index,
@@ -97,7 +140,7 @@
FT_LOAD_RENDER | FT_LOAD_MONOCHROME );
if ( !error )
{
- if ( face->glyph->format != ft_image_format_bitmap ||
+ if ( face->glyph->format != ft_glyph_format_bitmap ||
face->glyph->bitmap.pixel_mode != ft_pixel_mode_mono )
{
/* there is no monochrome glyph for this font! */
@@ -129,11 +172,11 @@
error = FTC_Manager_Lookup_Size( queue->manager,
- &queue->size_rec,
+ &queue->descriptor.size,
&face, &size );
if ( !error )
{
- FT_UInt glyph_index = FTC_IMAGENODE_GINDEX( node );
+ FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
error = FT_Load_Glyph( face, glyph_index,
@@ -140,10 +183,10 @@
FT_LOAD_RENDER );
if ( !error )
{
- if ( face->glyph->format != ft_image_format_bitmap ||
+ if ( face->glyph->format != ft_glyph_format_bitmap ||
face->glyph->bitmap.pixel_mode != ft_pixel_mode_grays )
{
- /* there is no monochrome glyph for this font! */
+ /* there is no anti-aliased glyph for this font! */
error = FT_Err_Invalid_Glyph_Index;
}
else
@@ -158,6 +201,472 @@
}
}
}
+ return error;
+ }
+
+
+ static
+ FT_Error ftc_init_outline_image( FTC_Image_Queue queue,
+ FTC_ImageNode node )
+ {
+ FT_Face face;
+ FT_Size size;
+ FT_Error error;
+
+
+ error = FTC_Manager_Lookup_Size( queue->manager,
+ &queue->descriptor.size,
+ &face, &size );
+ if ( !error )
+ {
+ FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
+
+
+ error = FT_Load_Glyph( face, glyph_index,
+ FT_LOAD_NO_BITMAP );
+ if ( !error )
+ {
+ if ( face->glyph->format != ft_glyph_format_outline )
+ {
+ /* there is no outline glyph for this font! */
+ error = FT_Err_Invalid_Glyph_Index;
+ }
+ else
+ {
+ /* ok, copy it */
+ FT_Glyph glyph;
+
+
+ error = FT_Get_Glyph( face->glyph, &glyph );
+ if ( !error )
+ FTC_IMAGENODE_SET_GLYPH( node, glyph );
+ }
+ }
+ }
+ return error;
+ }
+
+
+
+ static
+ FT_Error ftc_init_master_outline_image( FTC_Image_Queue queue,
+ FTC_ImageNode node )
+ {
+ FT_Face face;
+ FT_Size size;
+ FT_Error error;
+
+
+ error = FTC_Manager_Lookup_Size( queue->manager,
+ &queue->descriptor.size,
+ &face, &size );
+ if ( !error )
+ {
+ FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
+
+
+ error = FT_Load_Glyph( face, glyph_index,
+ FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
+ if ( !error )
+ {
+ if ( face->glyph->format != ft_glyph_format_outline )
+ {
+ /* there is no outline glyph for this font! */
+ error = FT_Err_Invalid_Glyph_Index;
+ }
+ else
+ {
+ /* ok, copy it */
+ FT_Glyph glyph;
+
+
+ error = FT_Get_Glyph( face->glyph, &glyph );
+ if ( !error )
+ FTC_IMAGENODE_SET_GLYPH( node, glyph );
+ }
+ }
+ }
+ return error;
+ }
+
+
+ static
+ const FTC_Image_Class ftc_mono_image_class =
+ {
+ ftc_init_mono_image,
+ ftc_done_glyph_image,
+ ftc_size_bitmap_image
+ };
+
+ static
+ const FTC_Image_Class ftc_gray_image_class =
+ {
+ ftc_init_gray_image,
+ ftc_done_glyph_image,
+ ftc_size_bitmap_image
+ };
+
+ static
+ const FTC_Image_Class ftc_outline_image_class =
+ {
+ ftc_init_outline_image,
+ ftc_done_glyph_image,
+ ftc_size_outline_image
+ };
+
+ static
+ const FTC_Image_Class ftc_master_outline_image_class =
+ {
+ ftc_init_master_outline_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 = 32;
+
+ if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) )
+ goto Exit;
+
+ switch (desc->image_type)
+ {
+ case ftc_image_mono:
+ clazz = &ftc_mono_image_class;
+ break;
+
+ case ftc_image_grays:
+ clazz = &ftc_gray_image_class;
+ break;
+
+ case ftc_image_outline:
+ clazz = &ftc_outline_image_class;
+ break;
+
+ case ftc_image_master_outline:
+ clazz = &ftc_master_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 );
+
+ 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);
+
+ 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, next;
+ FT_Error error;
+ FTC_ImageNode inode;
+
+ *anode = 0;
+ for ( node = bucket->head; node; node = next )
+ {
+ inode = (FTC_ImageNode)node;
+
+ if ( FTC_IMAGENODE_GET_GINDEX(inode) == glyph_index )
+ {
+ /* we found it !! - move glyph to start of the list */
+ FT_List_Up( bucket, node );
+ *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;
+
+ error = queue->clazz->init_image( queue, inode );
+ if (error)
+ {
+ FTC_ImageNode_Done( queue->cache, inode );
+ goto Exit;
+ }
+
+ /* set the glyph and queue indices in the image node */
+ FTC_IMAGENODE_SET_INDICES( inode, glyph_index, queue->index );
+
+ /* 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);
+
+ *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)
+
+ static
+ 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;
+ }
+
+ return error;
+ }
+
+
+ static
+ void ftc_image_cache_done_queue( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_Image_Queue queue = FTC_LRUNODE_QUEUE(node);
+
+ FT_UNUSED(lru);
+ FTC_Image_Queue_Done(queue);
+ }
+
+
+ static
+ 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 );
+ }
+
+
+
+ static
+ 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 it needs it.. i.e. discards all old glyph images */
+ /* until "cache.num_bytes" is under "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)
+ {
+ FT_ListNode cur = cache->glyphs_lru.tail;
+ 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 is always at the */
+ /* start of the list..) */
+
+ inode = FTC_LISTNODE_TO_IMAGENODE(cur);
+ if ( !cur || inode == new_node )
+ 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 );
+
+ 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;
+ }
+ }
+
+
+ FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager,
+ FT_ULong max_bytes,
+ FTC_Image_Cache* acache )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FTC_Image_Cache cache;
+
+
+ *acache = 0;
+ memory = manager->library->memory;
+
+ if ( ALLOC( cache, sizeof(*cache) ) )
+ goto Exit;
+
+ cache->manager = manager;
+ 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 = cache->memory;
+
+
+ /* discard image queues */
+ FT_Lru_Done( cache->queues_lru );
+
+ /* discard cache */
+ FREE( cache );
+ }
+
+
+
+ FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_Lookup(
+ FTC_Image_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FT_Glyph* aglyph )
+ {
+ FT_Error error;
+ FTC_Image_Queue queue;
+ FTC_ImageNode inode;
+
+ *aglyph = 0;
+ error = FT_Lru_Lookup( cache->queues_lru,
+ (FT_LruKey)desc,
+ (FT_Pointer*)&queue );
+ if (error)
+ goto Exit;
+
+ error = FTC_Image_Queue_Lookup_Node( queue, gindex, &inode );
+ if (error)
+ goto Exit;
+
+ FTC_Image_Cache_Compress( cache, inode );
+ *aglyph = FTC_IMAGENODE_GET_GLYPH(inode);
+
+ Exit:
return error;
}
--- a/src/cache/ftcimage.h
+++ b/src/cache/ftcimage.h
@@ -21,40 +21,18 @@
#include <cache/ftcmanag.h>
#include <freetype/ftglyph.h>
+#include <stddef.h>
-
#ifdef __cplusplus
extern "C" {
#endif
+#define FTC_MAX_IMAGE_QUEUES 16
typedef struct FTC_Image_QueueRec_* FTC_Image_Queue;
- typedef struct FTC_Image_CacheRec_* FTC_Image_Cache;
typedef struct FTC_ImageNodeRec_* FTC_ImageNode;
- /* types of glyph images */
- typedef enum FTC_Image_Type_
- {
- ftc_image_mono = 0, /* monochrome bitmap */
- ftc_image_grays, /* anti-aliased bitmap */
- ftc_image_outline, /* scaled outline */
- ftc_image_master_outline, /* original outline */
-
- } FTC_Image_Type;
-
-
- /* a descriptor used to describe all glyphs in a given queue */
- typedef struct FTC_Image_Desc_
- {
- FTC_FaceID face_id;
- FT_UInt pix_width;
- FT_UInt pix_height;
- FT_UInt image_type;
-
- } FTC_Image_Desc;
-
-
/* 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 ) )
@@ -76,7 +54,9 @@
/* 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_SET_INDICES( g, q ) \
+#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 ); \
@@ -83,6 +63,17 @@
} 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;
@@ -91,9 +82,10 @@
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_Lru queues_lru; /* static queues lru list */
+ FT_ListRec glyphs_lru; /* global lru list of glyph images */
- } FTC_Image_Cache;
+ } FTC_Image_CacheRec;
/* a table of functions used to generate/manager glyph images */
@@ -100,13 +92,13 @@
typedef struct FTC_Image_Class_
{
FT_Error (*init_image)( FTC_Image_Queue queue,
- FTC_Image_Node node );
+ FTC_ImageNode node );
void (*done_image)( FTC_Image_Queue queue,
- FTC_Image_Node node );
+ FTC_ImageNode node );
FT_ULong (*size_image)( FTC_Image_Queue queue,
- FTC_Image_Node node );
+ FTC_ImageNode node );
} FTC_Image_Class;
@@ -120,21 +112,10 @@
FTC_Image_Desc descriptor;
FT_UInt hash_size;
FT_List buckets;
+ FT_UInt index; /* index in parent cache */
- } FTC_Image_SubCacheRec;
+ } FTC_Image_QueueRec;
-
- FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_New( FTC_Manager manager,
- FT_ULong max_bytes,
- FTC_Image_Cache* acache );
-
- FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache );
-
- FT_EXPORT_DEF( FT_Error ) FTC_Image_Cache_Lookup(
- FTC_Image_Cache cache,
- FTC_Image_Desc* desc,
- FT_UInt gindex,
- FT_Glyph* aglyph );
#ifdef __cplusplus
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -20,7 +20,7 @@
#include <freetype/internal/ftobjs.h>
-#define FTC_LRU_GET_MANAGER( lru ) ((FTC_Manager_Lru)lru)->manager
+#define FTC_LRU_GET_MANAGER( lru ) (FTC_Manager)lru->user_data
/**************************************************************************/
@@ -40,6 +40,7 @@
error = manager->request_face( (FTC_FaceID)node->key,
+ manager->library,
manager->request_data,
(FT_Face*)&node->root.data );
if ( !error )
@@ -179,7 +180,7 @@
static
const FT_Lru_Class ftc_face_lru_class =
{
- sizeof ( FTC_Manager_LruRec ),
+ sizeof ( FT_LruRec ),
ftc_manager_init_face,
ftc_manager_done_face,
0,
@@ -190,7 +191,7 @@
static
const FT_Lru_Class ftc_size_lru_class =
{
- sizeof ( FTC_Manager_LruRec ),
+ sizeof ( FT_LruRec ),
ftc_manager_init_size,
ftc_manager_done_size,
ftc_manager_flush_size,
@@ -213,6 +214,7 @@
error = FT_Lru_New( &ftc_face_lru_class,
FTC_MAX_FACES,
+ manager,
memory,
1, /* pre_alloc = TRUE */
(FT_Lru*)&manager->faces_lru );
@@ -221,6 +223,7 @@
error = FT_Lru_New( &ftc_size_lru_class,
FTC_MAX_SIZES,
+ manager,
memory,
1, /* pre_alloc = TRUE */
(FT_Lru*)&manager->sizes_lru );
@@ -227,9 +230,6 @@
if ( error )
goto Exit;
- ((FTC_Manager_Lru)manager->faces_lru)->manager = manager;
- ((FTC_Manager_Lru)manager->sizes_lru)->manager = manager;
-
manager->library = library;
manager->request_face = requester;
manager->request_data = req_data;
@@ -275,6 +275,7 @@
}
+
FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Size( FTC_Manager manager,
FTC_SizeID size_id,
FT_Face* aface,
@@ -285,12 +286,17 @@
FT_Face face;
- *aface = 0;
- *asize = 0;
+ if (aface)
+ *aface = 0;
+
+ if (asize)
+ *asize = 0;
error = FTC_Manager_Lookup_Face( manager, size_id->face_id, &face );
if ( !error )
{
+ FT_Size size;
+
req.face = face;
req.width = size_id->pix_width;
req.height = size_id->pix_height;
@@ -297,12 +303,17 @@
error = FT_Lru_Lookup( manager->sizes_lru,
(FT_LruKey)&req,
- (FT_Pointer*)asize );
+ (FT_Pointer*)&size );
if ( !error )
{
/* select the size as the current one for this face */
face->size = *asize;
- *aface = face;
+
+ if (asize)
+ *asize = size;
+
+ if (aface)
+ *aface = face;
}
}
--- a/src/cache/ftcmanag.h
+++ b/src/cache/ftcmanag.h
@@ -19,6 +19,7 @@
#ifndef FTCMANAG_H
#define FTCMANAG_H
+#include <freetype/ftcache.h>
#include <cache/ftlru.h>
@@ -31,32 +32,6 @@
#define FTC_MAX_SIZES 8
- typedef FT_Pointer FTC_FaceID;
-
- typedef struct FTC_SizeRec_
- {
- FTC_FaceID face_id;
- FT_UShort pix_width;
- FT_UShort pix_height;
-
- } FTC_SizeRec, *FTC_SizeID;
-
-
- typedef FT_Error (*FTC_Face_Requester)( FTC_FaceID face_id,
- FT_Pointer data,
- FT_Face* aface );
-
-
- typedef struct FTC_ManagerRec_* FTC_Manager;
-
- typedef struct FTC_Manager_LruRec_
- {
- FT_LruRec root;
- FTC_Manager manager;
-
- } FTC_Manager_LruRec, *FTC_Manager_Lru;
-
-
typedef struct FTC_ManagerRec_
{
FT_Library library;
@@ -68,24 +43,6 @@
} FTC_ManagerRec;
-
- FT_EXPORT_DEF( FT_Error ) FTC_Manager_New( FT_Library library,
- FTC_Face_Requester requester,
- FT_Pointer req_data,
- FTC_Manager* amanager );
-
- FT_EXPORT_DEF( void ) FTC_Manager_Done( FTC_Manager manager );
-
- FT_EXPORT_DEF( void ) FTC_Manager_Reset( FTC_Manager manager );
-
- FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Face( FTC_Manager manager,
- FTC_FaceID face_id,
- FT_Face* aface );
-
- FT_EXPORT_DEF( FT_Error ) FTC_Manager_Lookup_Size( FTC_Manager manager,
- FTC_SizeID size_id,
- FT_Face* aface,
- FT_Size* asize );
#ifdef __cplusplus
--- a/src/cache/ftlru.c
+++ b/src/cache/ftlru.c
@@ -38,6 +38,7 @@
FT_EXPORT_FUNC( FT_Error ) FT_Lru_New( const FT_Lru_Class* clazz,
FT_UInt max_elements,
+ FT_Pointer user_data,
FT_Memory memory,
FT_Bool pre_alloc,
FT_Lru* alru )
@@ -66,6 +67,7 @@
lru->clazz = (FT_Lru_Class*)clazz;
lru->max_elements = max_elements;
lru->memory = memory;
+ lru->user_data = user_data;
*alru = lru;
}
--- a/src/cache/ftlru.h
+++ b/src/cache/ftlru.h
@@ -40,6 +40,8 @@
typedef struct FT_LruRec_* FT_Lru;
+
+
typedef struct FT_Lru_Class_
{
FT_UInt lru_size; /* object size in bytes */
@@ -60,6 +62,7 @@
} FT_Lru_Class;
+
typedef FT_Bool (*FT_Lru_Selector)( FT_Lru lru,
FT_LruNode node,
FT_Pointer data );
@@ -72,6 +75,7 @@
FT_UInt num_elements;
FT_ListRec elements;
FT_Memory memory;
+ FT_Pointer user_data;
/* the following fields are only meaningful for static lru containers */
FT_ListRec free_nodes;
@@ -82,6 +86,7 @@
FT_EXPORT_DEF( FT_Error ) FT_Lru_New( const FT_Lru_Class* clazz,
FT_UInt max_elements,
+ FT_Pointer user_data,
FT_Memory memory,
FT_Bool pre_alloc,
FT_Lru* alru );
--- /dev/null
+++ b/src/cache/rules.mk
@@ -1,0 +1,70 @@
+#
+# FreeType 2 Cache configuration rules
+#
+
+
+# Copyright 1996-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.
+
+
+# Cache driver directory
+#
+Cache_DIR := $(SRC_)cache
+Cache_DIR_ := $(Cache_DIR)$(SEP)
+
+
+# compilation flags for the driver
+#
+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 driver headers
+#
+Cache_DRV_H := $(Cache_DRV_SRC:%c=%h)
+
+
+# Cache driver object(s)
+#
+# 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_S := $(OBJ_)ftcache.$O
+
+# Cache driver source file for single build
+#
+Cache_DRV_SRC_S := $(Cache_DIR_)ftcache.c
+
+
+# Cache driver - single object
+#
+$(Cache_DRV_OBJ_S): $(Cache_DRV_SRC_S) $(Cache_DRV_SRC) \
+ $(FREETYPE_H) $(Cache_DRV_H)
+ $(Cache_COMPILE) $T$@ $(Cache_DRV_SRC_S)
+
+
+# Cache driver - multiple objects
+#
+$(OBJ_)%.$O: $(Cache_DIR_)%.c $(FREETYPE_H) $(Cache_DRV_H)
+ $(Cache_COMPILE) $T$@ $<
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(Cache_DRV_OBJ_S)
+DRV_OBJS_M += $(Cache_DRV_OBJ_M)
+
+
+# EOF