2000-08-23 19:32:42 +02:00
|
|
|
/***************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* ftcimage.c */
|
|
|
|
/* */
|
2000-08-24 18:29:15 +02:00
|
|
|
/* FreeType Image Cache (body). */
|
2000-08-23 19:32:42 +02:00
|
|
|
/* */
|
|
|
|
/* 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. */
|
|
|
|
/* */
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
|
2000-08-23 13:22:30 +02:00
|
|
|
#include <cache/ftcimage.h>
|
2000-08-23 23:11:13 +02:00
|
|
|
#include <freetype/fterrors.h>
|
|
|
|
#include <freetype/internal/ftobjs.h>
|
|
|
|
#include <freetype/internal/ftlist.h>
|
2000-08-29 18:04:28 +02:00
|
|
|
#include <freetype/fterrors.h>
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
/**************************************************************************/
|
|
|
|
/**************************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** 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. *****/
|
|
|
|
/***** *****/
|
|
|
|
/**************************************************************************/
|
|
|
|
/**************************************************************************/
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_Error FTC_ImageNode_New( FTC_Image_Cache cache,
|
|
|
|
FTC_ImageNode* anode )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
|
|
|
FT_Error error;
|
|
|
|
FT_Memory memory = cache->memory;
|
|
|
|
FTC_ImageNode node;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
*anode = 0;
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( !ALLOC( node, sizeof ( *node ) ) )
|
2000-08-23 23:11:13 +02:00
|
|
|
*anode = node;
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
void FTC_ImageNode_Done( FTC_Image_Cache cache,
|
|
|
|
FTC_ImageNode node )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
/* for now, we simply discard the node; we may later add a chunk */
|
|
|
|
/* manager to the image cache. */
|
2000-08-23 23:11:13 +02:00
|
|
|
FT_Memory memory = cache->memory;
|
2000-08-24 18:29:15 +02:00
|
|
|
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
FREE( node );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** GLYPH IMAGE QUEUES *****/
|
|
|
|
/***** *****/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-23 13:22:30 +02:00
|
|
|
|
|
|
|
static
|
2000-08-23 19:32:42 +02:00
|
|
|
void ftc_done_glyph_image( FTC_Image_Queue queue,
|
|
|
|
FTC_ImageNode node )
|
2000-08-23 13:22:30 +02:00
|
|
|
{
|
2000-08-23 19:32:42 +02:00
|
|
|
FT_UNUSED( queue );
|
|
|
|
|
|
|
|
FT_Done_Glyph( FTC_IMAGENODE_GET_GLYPH( node ) );
|
2000-08-23 13:22:30 +02:00
|
|
|
}
|
|
|
|
|
2000-08-23 19:32:42 +02:00
|
|
|
|
2000-08-23 13:22:30 +02:00
|
|
|
static
|
2000-08-23 19:32:42 +02:00
|
|
|
FT_ULong ftc_size_bitmap_image( FTC_Image_Queue queue,
|
|
|
|
FTC_ImageNode node )
|
2000-08-23 13:22:30 +02:00
|
|
|
{
|
|
|
|
FT_Long pitch;
|
|
|
|
FT_BitmapGlyph glyph;
|
|
|
|
|
2000-08-23 19:32:42 +02:00
|
|
|
FT_UNUSED( queue );
|
|
|
|
|
|
|
|
|
2000-08-23 13:22:30 +02:00
|
|
|
glyph = (FT_BitmapGlyph)FTC_IMAGENODE_GET_GLYPH(node);
|
|
|
|
pitch = glyph->bitmap.pitch;
|
2000-08-23 19:32:42 +02:00
|
|
|
if ( pitch < 0 )
|
2000-08-23 13:22:30 +02:00
|
|
|
pitch = -pitch;
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
return (FT_ULong)(pitch * glyph->bitmap.rows + sizeof ( *glyph ) );
|
2000-08-23 13:22:30 +02:00
|
|
|
}
|
|
|
|
|
2000-08-23 19:32:42 +02:00
|
|
|
|
2000-08-23 13:22:30 +02:00
|
|
|
static
|
2000-08-23 19:32:42 +02:00
|
|
|
FT_ULong ftc_size_outline_image( FTC_Image_Queue queue,
|
|
|
|
FTC_ImageNode node )
|
2000-08-23 13:22:30 +02:00
|
|
|
{
|
|
|
|
FT_OutlineGlyph glyph;
|
|
|
|
FT_Outline* outline;
|
|
|
|
|
2000-08-23 19:32:42 +02:00
|
|
|
FT_UNUSED( queue );
|
|
|
|
|
|
|
|
|
|
|
|
glyph = (FT_OutlineGlyph)FTC_IMAGENODE_GET_GLYPH( node );
|
2000-08-23 13:22:30 +02:00
|
|
|
outline = &glyph->outline;
|
|
|
|
|
|
|
|
return (FT_ULong)(
|
2000-08-23 19:32:42 +02:00
|
|
|
outline->n_points * ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) +
|
|
|
|
outline->n_contours * sizeof ( FT_Short ) +
|
|
|
|
sizeof( *glyph ) );
|
2000-08-23 13:22:30 +02:00
|
|
|
}
|
|
|
|
|
2000-08-23 19:32:42 +02:00
|
|
|
|
2000-08-23 13:22:30 +02:00
|
|
|
static
|
2000-08-29 18:04:28 +02:00
|
|
|
FT_Error ftc_init_glyph_image( FTC_Image_Queue queue,
|
|
|
|
FTC_ImageNode node )
|
2000-08-23 13:22:30 +02:00
|
|
|
{
|
2000-08-23 19:32:42 +02:00
|
|
|
FT_Face face;
|
|
|
|
FT_Size size;
|
|
|
|
FT_Error error;
|
2000-08-23 13:22:30 +02:00
|
|
|
|
|
|
|
error = FTC_Manager_Lookup_Size( queue->manager,
|
2000-08-23 23:11:13 +02:00
|
|
|
&queue->descriptor.size,
|
2000-08-23 13:22:30 +02:00
|
|
|
&face, &size );
|
2000-08-23 19:32:42 +02:00
|
|
|
if ( !error )
|
2000-08-23 13:22:30 +02:00
|
|
|
{
|
2000-08-23 23:11:13 +02:00
|
|
|
FT_UInt glyph_index = FTC_IMAGENODE_GET_GINDEX( node );
|
2000-08-29 18:04:28 +02:00
|
|
|
FT_UInt load_flags = FT_LOAD_DEFAULT;
|
|
|
|
FT_UInt image_type = queue->descriptor.image_type;
|
2000-08-23 13:22:30 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
if ( FTC_IMAGE_FORMAT(image_type) == ftc_image_format_bitmap )
|
|
|
|
{
|
|
|
|
load_flags |= FT_LOAD_RENDER;
|
|
|
|
if ( image_type & ftc_image_flag_monochrome )
|
|
|
|
load_flags |= FT_LOAD_MONOCHROME;
|
2000-08-23 13:22:30 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
/* disable embedded bitmaps loading if necessary */
|
|
|
|
if (load_flags & ftc_image_flag_no_sbits)
|
|
|
|
load_flags |= FT_LOAD_NO_BITMAP;
|
2000-08-23 13:22:30 +02:00
|
|
|
}
|
2000-08-29 18:04:28 +02:00
|
|
|
else if ( FTC_IMAGE_FORMAT(image_type) == ftc_image_format_outline )
|
2000-08-23 13:22:30 +02:00
|
|
|
{
|
2000-08-29 18:04:28 +02:00
|
|
|
/* disable embedded bitmaps loading */
|
|
|
|
load_flags |= FT_LOAD_NO_BITMAP;
|
|
|
|
|
|
|
|
if (image_type & ftc_image_flag_unscaled)
|
|
|
|
load_flags |= FT_LOAD_NO_SCALE;
|
|
|
|
}
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
if (image_type & ftc_image_flag_unhinted)
|
|
|
|
load_flags |= FT_LOAD_NO_HINTING;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
if (image_type & ftc_image_flag_autohinted)
|
|
|
|
load_flags |= FT_LOAD_FORCE_AUTOHINT;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
error = FT_Load_Glyph( face, glyph_index, load_flags );
|
2000-08-23 23:11:13 +02:00
|
|
|
if ( !error )
|
|
|
|
{
|
2000-08-29 18:04:28 +02:00
|
|
|
if ( face->glyph->format == ft_glyph_format_bitmap ||
|
|
|
|
face->glyph->format == ft_glyph_format_outline )
|
|
|
|
{
|
2000-08-23 23:11:13 +02:00
|
|
|
/* ok, copy it */
|
|
|
|
FT_Glyph glyph;
|
|
|
|
|
|
|
|
|
|
|
|
error = FT_Get_Glyph( face->glyph, &glyph );
|
|
|
|
if ( !error )
|
|
|
|
FTC_IMAGENODE_SET_GLYPH( node, glyph );
|
|
|
|
}
|
2000-08-29 18:04:28 +02:00
|
|
|
else
|
|
|
|
error = FT_Err_Invalid_Argument;
|
2000-08-23 23:11:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-08-23 13:22:30 +02:00
|
|
|
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
static
|
2000-08-29 18:04:28 +02:00
|
|
|
const FTC_Image_Class ftc_bitmap_image_class =
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-29 18:04:28 +02:00
|
|
|
ftc_init_glyph_image,
|
2000-08-23 23:11:13 +02:00
|
|
|
ftc_done_glyph_image,
|
|
|
|
ftc_size_bitmap_image
|
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
const FTC_Image_Class ftc_outline_image_class =
|
|
|
|
{
|
2000-08-29 18:04:28 +02:00
|
|
|
ftc_init_glyph_image,
|
2000-08-23 23:11:13 +02:00
|
|
|
ftc_done_glyph_image,
|
|
|
|
ftc_size_outline_image
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_Error FTC_Image_Queue_New( FTC_Image_Cache cache,
|
|
|
|
FTC_Image_Desc* desc,
|
|
|
|
FTC_Image_Queue* aqueue )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
|
|
|
FT_Error error;
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_Memory memory = cache->memory;
|
2000-08-23 23:11:13 +02:00
|
|
|
FTC_Manager manager = cache->manager;
|
2000-08-24 18:29:15 +02:00
|
|
|
FTC_Image_Queue queue = 0;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
const FTC_Image_Class* clazz;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
*aqueue = 0;
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( ALLOC( queue, sizeof ( *queue ) ) )
|
2000-08-23 23:11:13 +02:00
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
queue->cache = cache;
|
|
|
|
queue->manager = manager;
|
|
|
|
queue->memory = memory;
|
|
|
|
queue->descriptor = *desc;
|
2000-08-29 18:04:28 +02:00
|
|
|
queue->hash_size = 64;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
if ( ALLOC_ARRAY( queue->buckets, queue->hash_size, FT_ListRec ) )
|
|
|
|
goto Exit;
|
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
switch (FTC_IMAGE_FORMAT(desc->image_type))
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-29 18:04:28 +02:00
|
|
|
case ftc_image_format_bitmap:
|
|
|
|
clazz = &ftc_bitmap_image_class;
|
|
|
|
break;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
case ftc_image_format_outline:
|
|
|
|
clazz = &ftc_outline_image_class;
|
|
|
|
break;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
default:
|
|
|
|
/* invalid image type! */
|
|
|
|
error = FT_Err_Invalid_Argument;
|
|
|
|
goto Exit;
|
2000-08-23 23:11:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
queue->clazz = (FTC_Image_Class*)clazz;
|
|
|
|
*aqueue = queue;
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
Exit:
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( error )
|
2000-08-23 23:11:13 +02:00
|
|
|
FREE( queue );
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
void FTC_Image_Queue_Done( FTC_Image_Queue queue )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
/* 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;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
for ( ; node; node = next )
|
|
|
|
{
|
|
|
|
next = node->next;
|
|
|
|
inode = (FTC_ImageNode)node;
|
2000-08-24 18:29:15 +02:00
|
|
|
lrunode = FTC_IMAGENODE_TO_LISTNODE( inode );
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
queue->clazz->done_image( queue, inode );
|
|
|
|
FT_List_Remove( glyphs_lru, lrunode );
|
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
cache->num_bytes -= queue->clazz->size_image(queue,inode) +
|
|
|
|
sizeof(FTC_ImageNodeRec);
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
FTC_ImageNode_Done( cache, inode );
|
|
|
|
}
|
|
|
|
|
|
|
|
bucket->head = bucket->tail = 0;
|
|
|
|
}
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
FREE( queue->buckets );
|
|
|
|
FREE( queue );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
FT_Error FTC_Image_Queue_Lookup_Node( FTC_Image_Queue queue,
|
|
|
|
FT_UInt glyph_index,
|
2000-08-24 18:29:15 +02:00
|
|
|
FTC_ImageNode* anode )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
|
|
|
FTC_Image_Cache cache = queue->cache;
|
|
|
|
FT_UInt hash_index = glyph_index % queue->hash_size;
|
|
|
|
FT_List bucket = queue->buckets + hash_index;
|
2000-08-29 18:04:28 +02:00
|
|
|
FT_ListNode node;
|
2000-08-23 23:11:13 +02:00
|
|
|
FT_Error error;
|
|
|
|
FTC_ImageNode inode;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
*anode = 0;
|
2000-08-29 18:04:28 +02:00
|
|
|
for ( node = bucket->head; node; node = node->next )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-29 18:04:28 +02:00
|
|
|
FT_UInt gindex;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
inode = (FTC_ImageNode)node;
|
|
|
|
gindex = FTC_IMAGENODE_GET_GINDEX(inode);
|
|
|
|
|
|
|
|
if ( gindex == glyph_index )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
/* we found it! -- move glyph to start of the list */
|
2000-08-23 23:11:13 +02:00
|
|
|
FT_List_Up( bucket, node );
|
2000-08-29 18:04:28 +02:00
|
|
|
FT_List_Up( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) );
|
2000-08-23 23:11:13 +02:00
|
|
|
*anode = inode;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2000-08-29 18:04:28 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
/* we didn't found the glyph image, we will now create a new one */
|
|
|
|
error = FTC_ImageNode_New( queue->cache, &inode );
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( error )
|
2000-08-23 23:11:13 +02:00
|
|
|
goto Exit;
|
2000-08-24 14:39:40 +02:00
|
|
|
|
|
|
|
/* set the glyph and queue indices in the image node */
|
|
|
|
FTC_IMAGENODE_SET_INDICES( inode, glyph_index, queue->index );
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
error = queue->clazz->init_image( queue, inode );
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( error )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
|
|
|
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 */
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_List_Insert( &cache->glyphs_lru, FTC_IMAGENODE_TO_LISTNODE( inode ) );
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
cache->num_bytes += queue->clazz->size_image(queue,inode) +
|
|
|
|
sizeof(FTC_ImageNodeRec);
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
*anode = inode;
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
/***** *****/
|
|
|
|
/***** IMAGE CACHE CALLBACKS *****/
|
|
|
|
/***** *****/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
|
|
|
#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 )
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_Error ftc_image_cache_init_queue( FT_Lru lru,
|
|
|
|
FT_LruNode node )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
FTC_Image_Cache cache = FTC_QUEUE_LRU_GET_CACHE( lru );
|
|
|
|
FTC_Image_Desc* desc = (FTC_Image_Desc*)node->key;
|
2000-08-23 23:11:13 +02:00
|
|
|
FT_Error error;
|
|
|
|
FTC_Image_Queue queue;
|
2000-08-24 18:29:15 +02:00
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
error = FTC_Image_Queue_New( cache, desc, &queue );
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( !error )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
|
|
|
/* good, now set the queue index within the queue object */
|
|
|
|
queue->index = node - lru->nodes;
|
|
|
|
node->root.data = queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
void ftc_image_cache_done_queue( FT_Lru lru,
|
|
|
|
FT_LruNode node )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
FTC_Image_Queue queue = FTC_LRUNODE_QUEUE( node );
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_UNUSED( lru );
|
|
|
|
|
|
|
|
|
|
|
|
FTC_Image_Queue_Done( queue );
|
2000-08-23 23:11:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_Bool ftc_image_cache_compare_queue( FT_LruNode node,
|
|
|
|
FT_LruKey key )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
FTC_Image_Queue queue = FTC_LRUNODE_QUEUE( node );
|
2000-08-23 23:11:13 +02:00
|
|
|
FTC_Image_Desc* desc2 = (FTC_Image_Desc*)key;
|
|
|
|
FTC_Image_Desc* desc1 = &queue->descriptor;
|
|
|
|
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
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 );
|
|
|
|
}
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
const FT_Lru_Class ftc_image_queue_lru_class =
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
|
|
|
sizeof( FT_LruRec ),
|
|
|
|
ftc_image_cache_init_queue,
|
|
|
|
ftc_image_cache_done_queue,
|
|
|
|
0, /* no flush */
|
|
|
|
ftc_image_cache_compare_queue
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
/* 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'. */
|
2000-08-23 23:11:13 +02:00
|
|
|
static
|
2000-08-24 18:29:15 +02:00
|
|
|
void FTC_Image_Cache_Compress( FTC_Image_Cache cache,
|
|
|
|
FTC_ImageNode new_node )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
while ( cache->num_bytes > cache->max_bytes )
|
2000-08-23 23:11:13 +02:00
|
|
|
{
|
2000-08-29 18:04:28 +02:00
|
|
|
FT_ListNode cur;
|
2000-08-23 23:11:13 +02:00
|
|
|
FTC_Image_Queue queue;
|
|
|
|
FT_UInt glyph_index;
|
|
|
|
FT_UInt hash_index;
|
|
|
|
FT_UInt queue_index;
|
|
|
|
FT_ULong size;
|
|
|
|
FTC_ImageNode inode;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
|
|
|
/* 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) */
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
cur = cache->glyphs_lru.tail;
|
2000-08-24 18:29:15 +02:00
|
|
|
inode = FTC_LISTNODE_TO_IMAGENODE( cur );
|
2000-08-23 23:11:13 +02:00
|
|
|
if ( !cur || inode == new_node )
|
|
|
|
break;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
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;
|
2000-08-23 23:11:13 +02:00
|
|
|
hash_index = glyph_index % queue->hash_size;
|
2000-08-29 18:04:28 +02:00
|
|
|
size = queue->clazz->size_image( queue, inode ) +
|
|
|
|
sizeof(FTC_ImageNodeRec);
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2000-08-29 18:04:28 +02:00
|
|
|
}
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
2000-08-27 00:16:44 +02:00
|
|
|
if ( !manager )
|
|
|
|
return FT_Err_Invalid_Cache_Handle;
|
|
|
|
|
|
|
|
if ( !acache || !manager->library )
|
2000-08-24 18:29:15 +02:00
|
|
|
return FT_Err_Invalid_Argument;
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
*acache = 0;
|
|
|
|
memory = manager->library->memory;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( ALLOC( cache, sizeof ( *cache ) ) )
|
2000-08-23 23:11:13 +02:00
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
cache->manager = manager;
|
2000-08-24 14:39:40 +02:00
|
|
|
cache->memory = manager->library->memory;
|
2000-08-23 23:11:13 +02:00
|
|
|
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 );
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( error )
|
2000-08-23 23:11:13 +02:00
|
|
|
goto Exit;
|
|
|
|
|
|
|
|
*acache = cache;
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
if ( error )
|
|
|
|
FREE( cache );
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FT_EXPORT_DEF( void ) FTC_Image_Cache_Done( FTC_Image_Cache cache )
|
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
FT_Memory memory;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
|
|
|
if ( !cache )
|
|
|
|
return;
|
|
|
|
|
|
|
|
memory = cache->memory;
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
|
|
|
|
/* check for valid `desc' delayed to FT_Lru_Lookup() */
|
|
|
|
|
|
|
|
if ( !cache || !aglyph )
|
|
|
|
return FT_Err_Invalid_Argument;
|
|
|
|
|
2000-08-23 23:11:13 +02:00
|
|
|
*aglyph = 0;
|
2000-08-24 14:39:40 +02:00
|
|
|
queue = cache->last_queue;
|
2000-08-29 18:04:28 +02:00
|
|
|
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 )
|
2000-08-24 14:39:40 +02:00
|
|
|
{
|
2000-08-24 18:29:15 +02:00
|
|
|
error = FT_Lru_Lookup( cache->queues_lru,
|
|
|
|
(FT_LruKey)desc,
|
|
|
|
(FT_Pointer*)&queue );
|
2000-08-24 14:39:40 +02:00
|
|
|
cache->last_queue = queue;
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( error )
|
2000-08-24 14:39:40 +02:00
|
|
|
goto Exit;
|
|
|
|
}
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
error = FTC_Image_Queue_Lookup_Node( queue, gindex, &inode );
|
2000-08-24 18:29:15 +02:00
|
|
|
if ( error )
|
2000-08-23 23:11:13 +02:00
|
|
|
goto Exit;
|
|
|
|
|
2000-08-29 18:04:28 +02:00
|
|
|
if (cache->num_bytes > cache->max_bytes)
|
|
|
|
FTC_Image_Cache_Compress( cache, inode );
|
|
|
|
|
2000-08-24 18:29:15 +02:00
|
|
|
*aglyph = FTC_IMAGENODE_GET_GLYPH( inode );
|
2000-08-23 23:11:13 +02:00
|
|
|
|
|
|
|
Exit:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-23 19:32:42 +02:00
|
|
|
/* END */
|