* src/base/ftdbgmem.c, docs/DEBUG.TXT: added new environment variables
to control memory debugging with FreeType. See the description of "FT2_DEBUG_MEMORY", "FT2_ALLOC_TOTAL_MAX" and "FT2_ALLOC_COUNT_MAX" in DEBUG.TXT * src/cache/ftccache.c, src/cache/ftccmap.c, src/cache/ftcsbits.c, ftlru.c: fixed the cache sub-system to correctly deal with out-of-memory conditions. * src/pfr/pfrobjs.c, src/pfr/pfrsbits.c: fixing compiler warnings and a small memory leak * src/psaux/psobjs.c (t1_reallocate_table): fixed a bug (memory leak) that only happened when trying to resize an array would end in an OOM. * src/smooth/ftgrays.c: removed compiler warnings / volatile bug * src/truetype/ttobjs.c: removed segmentation fault that happened in tight memory environments.
This commit is contained in:
parent
a3c378024b
commit
b280537b6d
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
||||
2003-03-13 David Turner <david@freetype.org>
|
||||
|
||||
* src/base/ftdbgmem.c, docs/DEBUG.TXT: added new environment variables
|
||||
to control memory debugging with FreeType. See the description of
|
||||
"FT2_DEBUG_MEMORY", "FT2_ALLOC_TOTAL_MAX" and "FT2_ALLOC_COUNT_MAX"
|
||||
in DEBUG.TXT
|
||||
|
||||
* src/cache/ftccache.c, src/cache/ftccmap.c, src/cache/ftcsbits.c,
|
||||
ftlru.c: fixed the cache sub-system to correctly deal with out-of-memory
|
||||
conditions.
|
||||
|
||||
* src/pfr/pfrobjs.c, src/pfr/pfrsbits.c: fixing compiler warnings and a
|
||||
small memory leak
|
||||
|
||||
* src/psaux/psobjs.c (t1_reallocate_table): fixed a bug (memory leak) that
|
||||
only happened when trying to resize an array would end in an OOM.
|
||||
|
||||
* src/smooth/ftgrays.c: removed compiler warnings / volatile bug
|
||||
|
||||
* src/truetype/ttobjs.c: removed segmentation fault that happened in
|
||||
tight memory environments.
|
||||
|
||||
2003-02-28 Pixel <pixel@mandrakesoft.com>
|
||||
|
||||
* src/gzip/ftgzip.c (ft_gzip_file_done): fixed memory leak, the ZLib
|
||||
|
@ -159,4 +159,25 @@ behaviour of FreeType at runtime:
|
||||
ignored in other builds.
|
||||
|
||||
|
||||
FT2_ALLOC_TOTAL_MAX
|
||||
|
||||
this variable is ignored if FT2_DEBUG_MEMORY is not defined. It allows
|
||||
you to specify a maximum heap size for all memory allocations performed
|
||||
by FreeType. This is very useful to test the robustness of the font
|
||||
engine and programs that use it in tight memory conditions.
|
||||
|
||||
If it is undefined, or if its value is not strictly positive, then no
|
||||
allocation bounds are checked at runtime.
|
||||
|
||||
|
||||
FT2_ALLOC_COUNT_MAX
|
||||
|
||||
this variable is ignored if FT2_DEBUG_MEMORY is not defined. It allows
|
||||
you to sepcify a maximum number of memory allocations performed by
|
||||
FreeType before returning the error FT_Err_Out_Of_Memory. This is
|
||||
useful for debugging and testing the engine's robustness.
|
||||
|
||||
If it is undefined, or if its value is not strictly positive, then no
|
||||
allocation bounsd are checked at runtime.
|
||||
|
||||
End of file
|
||||
|
@ -62,6 +62,13 @@
|
||||
FT_ULong alloc_total;
|
||||
FT_ULong alloc_current;
|
||||
FT_ULong alloc_max;
|
||||
FT_ULong alloc_count;
|
||||
|
||||
FT_Bool bound_total;
|
||||
FT_ULong alloc_total_max;
|
||||
|
||||
FT_Bool bound_count;
|
||||
FT_ULong alloc_count_max;
|
||||
|
||||
const char* file_name;
|
||||
FT_Long line_no;
|
||||
@ -476,10 +483,22 @@
|
||||
if ( size <= 0 )
|
||||
ft_mem_debug_panic( "negative block size allocation (%ld)", size );
|
||||
|
||||
/* return NULL if the maximum number of allocations was reached */
|
||||
if ( table->bound_count &&
|
||||
table->alloc_count >= table->alloc_count_max )
|
||||
return NULL;
|
||||
|
||||
/* return NULL if this allocation would overflow the maximum heap size */
|
||||
if ( table->bound_total &&
|
||||
table->alloc_current + (FT_ULong)size > table->alloc_total_max )
|
||||
return NULL;
|
||||
|
||||
block = (FT_Byte *)ft_mem_table_alloc( table, size );
|
||||
if ( block )
|
||||
ft_mem_table_set( table, block, (FT_ULong)size );
|
||||
|
||||
table->alloc_count++;
|
||||
|
||||
table->file_name = NULL;
|
||||
table->line_no = 0;
|
||||
|
||||
@ -570,15 +589,42 @@
|
||||
FT_Int result = 0;
|
||||
|
||||
|
||||
if ( getenv( "FT_DEBUG_MEMORY" ) )
|
||||
if ( getenv( "FT2_DEBUG_MEMORY" ) )
|
||||
{
|
||||
table = ft_mem_table_new( memory );
|
||||
if ( table )
|
||||
{
|
||||
const char* p;
|
||||
|
||||
memory->user = table;
|
||||
memory->alloc = ft_mem_debug_alloc;
|
||||
memory->realloc = ft_mem_debug_realloc;
|
||||
memory->free = ft_mem_debug_free;
|
||||
|
||||
p = getenv( "FT2_ALLOC_TOTAL_MAX" );
|
||||
if ( p != NULL )
|
||||
{
|
||||
FT_Long total_max = atol(p);
|
||||
|
||||
if ( total_max > 0 )
|
||||
{
|
||||
table->bound_total = 1;
|
||||
table->alloc_total_max = (FT_ULong) total_max;
|
||||
}
|
||||
}
|
||||
|
||||
p = getenv( "FT2_ALLOC_COUNT_MAX" );
|
||||
if ( p != NULL )
|
||||
{
|
||||
FT_Long total_count = atol(p);
|
||||
|
||||
if ( total_count > 0 )
|
||||
{
|
||||
table->bound_count = 1;
|
||||
table->alloc_count_max = (FT_ULong) total_count;
|
||||
}
|
||||
}
|
||||
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
359
src/cache/ftccache.c
vendored
359
src/cache/ftccache.c
vendored
@ -357,10 +357,12 @@
|
||||
|
||||
FT_FREE( node );
|
||||
|
||||
#if 0
|
||||
/* check, just in case of general corruption :-) */
|
||||
if ( manager->num_nodes == 0 )
|
||||
FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n",
|
||||
manager->num_nodes ));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -546,8 +548,10 @@
|
||||
FTC_Query query,
|
||||
FTC_Node *anode )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_LruNode lru;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FTC_Manager manager;
|
||||
FT_LruNode lru;
|
||||
FT_UInt free_count = 0;
|
||||
|
||||
|
||||
if ( !cache || !query || !anode )
|
||||
@ -558,153 +562,238 @@
|
||||
query->hash = 0;
|
||||
query->family = NULL;
|
||||
|
||||
/* XXX: we break encapsulation for the sake of speed! */
|
||||
{
|
||||
/* first of all, find the relevant family */
|
||||
FT_LruList list = cache->families;
|
||||
FT_LruNode fam, *pfam;
|
||||
FT_LruNode_CompareFunc compare = list->clazz->node_compare;
|
||||
manager = cache->manager;
|
||||
|
||||
pfam = &list->nodes;
|
||||
for (;;)
|
||||
/* here's a small note explaining what's hapenning in the code below.
|
||||
*
|
||||
* we need to deal intelligently with out-of-memory (OOM) conditions
|
||||
* when trying to create a new family or cache node during the lookup.
|
||||
*
|
||||
* when an OOM is detected, we'll try to free one or more "old" nodes
|
||||
* from the cache, then try again. it may be necessary to do that several
|
||||
* times, so a loop is needed.
|
||||
*
|
||||
* the local variable "free_count" holds the number of "old" nodes to
|
||||
* discard on each attempt. it starts at 1 and doubles on each iteration.
|
||||
* the loop stops when:
|
||||
*
|
||||
* - a non-OOM error is detected
|
||||
* - a succesful lookup is performed
|
||||
* - there are no more unused nodes in the cache
|
||||
*
|
||||
* for the record, remember that all used nodes appear _before_
|
||||
* unused ones in the manager's MRU node list.
|
||||
*/
|
||||
|
||||
for (;;)
|
||||
{
|
||||
{
|
||||
fam = *pfam;
|
||||
if ( fam == NULL )
|
||||
/* first of all, find the relevant family */
|
||||
FT_LruList list = cache->families;
|
||||
FT_LruNode fam, *pfam;
|
||||
FT_LruNode_CompareFunc compare = list->clazz->node_compare;
|
||||
|
||||
pfam = &list->nodes;
|
||||
for (;;)
|
||||
{
|
||||
error = FT_LruList_Lookup( list, query, &lru );
|
||||
fam = *pfam;
|
||||
if ( fam == NULL )
|
||||
{
|
||||
error = FT_LruList_Lookup( list, query, &lru );
|
||||
if ( error )
|
||||
goto Fail;
|
||||
|
||||
goto Skip;
|
||||
}
|
||||
|
||||
if ( compare( fam, query, list->data ) )
|
||||
break;
|
||||
|
||||
pfam = &fam->next;
|
||||
}
|
||||
|
||||
FT_ASSERT( fam != NULL );
|
||||
|
||||
/* move to top of list when needed */
|
||||
if ( fam != list->nodes )
|
||||
{
|
||||
*pfam = fam->next;
|
||||
fam->next = list->nodes;
|
||||
list->nodes = fam;
|
||||
}
|
||||
|
||||
lru = fam;
|
||||
|
||||
Skip:
|
||||
;
|
||||
}
|
||||
|
||||
{
|
||||
FTC_Manager manager = cache->manager;
|
||||
FTC_Family family = (FTC_Family) lru;
|
||||
FT_UFast hash = query->hash;
|
||||
FTC_Node* bucket;
|
||||
FT_UInt idx;
|
||||
|
||||
|
||||
idx = hash & cache->mask;
|
||||
if ( idx < cache->p )
|
||||
idx = hash & ( cache->mask * 2 + 1 );
|
||||
|
||||
bucket = cache->buckets + idx;
|
||||
|
||||
|
||||
if ( query->family != family ||
|
||||
family->fam_index >= manager->families.size )
|
||||
{
|
||||
FT_ERROR((
|
||||
"ftc_cache_lookup: invalid query (bad 'family' field)\n" ));
|
||||
error = FTC_Err_Invalid_Argument;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( *bucket )
|
||||
{
|
||||
FTC_Node* pnode = bucket;
|
||||
FTC_Node_CompareFunc compare = cache->clazz->node_compare;
|
||||
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
FTC_Node node;
|
||||
|
||||
|
||||
node = *pnode;
|
||||
if ( node == NULL )
|
||||
break;
|
||||
|
||||
if ( node->hash == hash &&
|
||||
(FT_UInt)node->fam_index == family->fam_index &&
|
||||
compare( node, query, cache ) )
|
||||
{
|
||||
/* move to head of bucket list */
|
||||
if ( pnode != bucket )
|
||||
{
|
||||
*pnode = node->link;
|
||||
node->link = *bucket;
|
||||
*bucket = node;
|
||||
}
|
||||
|
||||
/* move to head of MRU list */
|
||||
if ( node != manager->nodes_list )
|
||||
ftc_node_mru_up( node, manager );
|
||||
|
||||
*anode = node;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pnode = &node->link;
|
||||
}
|
||||
}
|
||||
|
||||
/* didn't find a node, create a new one */
|
||||
{
|
||||
FTC_Cache_Class clazz = cache->clazz;
|
||||
FT_Memory memory = cache->memory;
|
||||
FTC_Node node;
|
||||
|
||||
|
||||
if ( FT_ALLOC( node, clazz->node_size ) )
|
||||
goto Fail;
|
||||
|
||||
node->fam_index = (FT_UShort) family->fam_index;
|
||||
node->hash = query->hash;
|
||||
node->ref_count = 0;
|
||||
|
||||
error = clazz->node_init( node, query, cache );
|
||||
if ( error )
|
||||
{
|
||||
FT_FREE( node );
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
error = ftc_node_hash_link( node, cache );
|
||||
if ( error )
|
||||
{
|
||||
clazz->node_done( node, cache );
|
||||
FT_FREE( node );
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
ftc_node_mru_link( node, cache->manager );
|
||||
|
||||
cache->manager->cur_weight += clazz->node_weight( node, cache );
|
||||
|
||||
/* now try to compress the node pool when necessary */
|
||||
if ( manager->cur_weight >= manager->max_weight )
|
||||
{
|
||||
node->ref_count++;
|
||||
FTC_Manager_Compress( manager );
|
||||
node->ref_count--;
|
||||
}
|
||||
|
||||
*anode = node;
|
||||
}
|
||||
|
||||
/* all is well, exit now
|
||||
*/
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Fail:
|
||||
if ( error != FT_Err_Out_Of_Memory )
|
||||
goto Exit;
|
||||
|
||||
/* there is not enough memory, try to release some unused nodes
|
||||
* from the cache to make room for a new one.
|
||||
*/
|
||||
{
|
||||
FT_UInt new_count;
|
||||
|
||||
new_count = 1 + free_count*2;
|
||||
|
||||
/* check overflow and bounds */
|
||||
if ( new_count < free_count || free_count > manager->num_nodes )
|
||||
goto Exit;
|
||||
|
||||
free_count = new_count;
|
||||
|
||||
/* try to remove "new_count" nodes from the list */
|
||||
{
|
||||
FTC_Node first = manager->nodes_list;
|
||||
FTC_Node node;
|
||||
|
||||
if ( first == NULL ) /* empty list ! */
|
||||
goto Exit;
|
||||
|
||||
goto Skip;
|
||||
}
|
||||
|
||||
if ( compare( fam, query, list->data ) )
|
||||
break;
|
||||
|
||||
pfam = &fam->next;
|
||||
}
|
||||
|
||||
FT_ASSERT( fam != NULL );
|
||||
|
||||
/* move to top of list when needed */
|
||||
if ( fam != list->nodes )
|
||||
{
|
||||
*pfam = fam->next;
|
||||
fam->next = list->nodes;
|
||||
list->nodes = fam;
|
||||
}
|
||||
|
||||
lru = fam;
|
||||
|
||||
Skip:
|
||||
;
|
||||
}
|
||||
|
||||
{
|
||||
FTC_Family family = (FTC_Family) lru;
|
||||
FT_UFast hash = query->hash;
|
||||
FTC_Node* bucket;
|
||||
FT_UInt idx;
|
||||
|
||||
|
||||
idx = hash & cache->mask;
|
||||
if ( idx < cache->p )
|
||||
idx = hash & ( cache->mask * 2 + 1 );
|
||||
|
||||
bucket = cache->buckets + idx;
|
||||
|
||||
|
||||
if ( query->family != family ||
|
||||
family->fam_index >= cache->manager->families.size )
|
||||
{
|
||||
FT_ERROR((
|
||||
"ftc_cache_lookup: invalid query (bad 'family' field)\n" ));
|
||||
return FTC_Err_Invalid_Argument;
|
||||
}
|
||||
|
||||
if ( *bucket )
|
||||
{
|
||||
FTC_Node* pnode = bucket;
|
||||
FTC_Node_CompareFunc compare = cache->clazz->node_compare;
|
||||
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
FTC_Node node;
|
||||
|
||||
|
||||
node = *pnode;
|
||||
if ( node == NULL )
|
||||
break;
|
||||
|
||||
if ( node->hash == hash &&
|
||||
(FT_UInt)node->fam_index == family->fam_index &&
|
||||
compare( node, query, cache ) )
|
||||
/* go to last node - it's a circular list */
|
||||
node = first->mru_prev;
|
||||
for ( ; node && new_count > 0; new_count-- )
|
||||
{
|
||||
/* move to head of bucket list */
|
||||
if ( pnode != bucket )
|
||||
FTC_Node prev = node->mru_prev;
|
||||
|
||||
/* used nodes always appear before unused one in the MRU
|
||||
* list. if we find one here, we'd better stop right now
|
||||
* our iteration
|
||||
*/
|
||||
if ( node->ref_count > 0 )
|
||||
{
|
||||
*pnode = node->link;
|
||||
node->link = *bucket;
|
||||
*bucket = node;
|
||||
/* if there are no unused nodes in the list, we'd better exit */
|
||||
if ( new_count == free_count )
|
||||
goto Exit;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* move to head of MRU list */
|
||||
if ( node != cache->manager->nodes_list )
|
||||
ftc_node_mru_up( node, cache->manager );
|
||||
ftc_node_destroy( node, manager );
|
||||
|
||||
*anode = node;
|
||||
goto Exit;
|
||||
if ( node == first )
|
||||
break;
|
||||
|
||||
node = prev;
|
||||
}
|
||||
|
||||
pnode = &node->link;
|
||||
}
|
||||
}
|
||||
|
||||
/* didn't find a node, create a new one */
|
||||
{
|
||||
FTC_Cache_Class clazz = cache->clazz;
|
||||
FTC_Manager manager = cache->manager;
|
||||
FT_Memory memory = cache->memory;
|
||||
FTC_Node node;
|
||||
|
||||
|
||||
if ( FT_ALLOC( node, clazz->node_size ) )
|
||||
goto Exit;
|
||||
|
||||
node->fam_index = (FT_UShort) family->fam_index;
|
||||
node->hash = query->hash;
|
||||
node->ref_count = 0;
|
||||
|
||||
error = clazz->node_init( node, query, cache );
|
||||
if ( error )
|
||||
{
|
||||
FT_FREE( node );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
error = ftc_node_hash_link( node, cache );
|
||||
if ( error )
|
||||
{
|
||||
clazz->node_done( node, cache );
|
||||
FT_FREE( node );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
ftc_node_mru_link( node, cache->manager );
|
||||
|
||||
cache->manager->cur_weight += clazz->node_weight( node, cache );
|
||||
|
||||
/* now try to compress the node pool when necessary */
|
||||
if ( manager->cur_weight >= manager->max_weight )
|
||||
{
|
||||
node->ref_count++;
|
||||
FTC_Manager_Compress( manager );
|
||||
node->ref_count--;
|
||||
}
|
||||
|
||||
*anode = node;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
3
src/cache/ftccmap.c
vendored
3
src/cache/ftccmap.c
vendored
@ -27,6 +27,9 @@
|
||||
|
||||
#include "ftcerror.h"
|
||||
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT trace_cache
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* Each FTC_CMapNode contains a simple array to map a range of character */
|
||||
|
2
src/cache/ftcsbits.c
vendored
2
src/cache/ftcsbits.c
vendored
@ -216,7 +216,7 @@
|
||||
/* we mark unloaded glyphs with `sbit.buffer == 0' */
|
||||
/* and 'width == 255', 'height == 0' */
|
||||
/* */
|
||||
if ( error )
|
||||
if ( error && error != FT_Err_Out_Of_Memory )
|
||||
{
|
||||
sbit->width = 255;
|
||||
error = 0;
|
||||
|
156
src/cache/ftlru.c
vendored
156
src/cache/ftlru.c
vendored
@ -21,6 +21,7 @@
|
||||
#include FT_CACHE_INTERNAL_LRU_H
|
||||
#include FT_LIST_H
|
||||
#include FT_INTERNAL_OBJECTS_H
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
|
||||
#include "ftcerror.h"
|
||||
|
||||
@ -187,80 +188,135 @@
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* we haven't found the relevant element. We will now try */
|
||||
/* to create a new one. */
|
||||
/* */
|
||||
|
||||
/* first, check if our list if full, when appropriate */
|
||||
if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
|
||||
/* since we haven't found the relevant element in our LRU list,
|
||||
* we're going to "create" a new one.
|
||||
*
|
||||
* the following code is a bit special, because it tries to handle
|
||||
* out-of-memory conditions (OOM) in an intelligent way.
|
||||
*
|
||||
* more precisely, if not enough memory is available to create a
|
||||
* new node or "flush" an old one, we need to remove the oldest
|
||||
* elements from our list, and try again. since several tries may
|
||||
* be necessary, a loop is needed
|
||||
*
|
||||
* this loop will only exit when:
|
||||
*
|
||||
* - a new node was succesfully created, or an old node flushed
|
||||
* - an error other than FT_Err_Out_Of_Memory is detected
|
||||
* - the list of nodes is empty, and it isn't possible to create
|
||||
* new nodes
|
||||
*
|
||||
* on each unsucesful attempt, one node will be removed from the list
|
||||
*
|
||||
*/
|
||||
|
||||
{
|
||||
/* this list list is full; we will now flush */
|
||||
/* the oldest node, if there's one! */
|
||||
FT_LruNode last = *plast;
|
||||
FT_Int drop_last = ( list->max_nodes > 0 &&
|
||||
list->num_nodes >= list->max_nodes );
|
||||
|
||||
|
||||
if ( last )
|
||||
for (;;)
|
||||
{
|
||||
if ( clazz->node_flush )
|
||||
node = NULL;
|
||||
|
||||
/* when "drop_last" is true, we should free the last node in
|
||||
* the list to make room for a new one. note that we re-use
|
||||
* its memory block to save allocation calls.
|
||||
*/
|
||||
if ( drop_last )
|
||||
{
|
||||
error = clazz->node_flush( last, key, list->data );
|
||||
/* find the last node in the list
|
||||
*/
|
||||
pnode = &list->nodes;
|
||||
node = *pnode;
|
||||
|
||||
if ( node == NULL )
|
||||
{
|
||||
FT_ASSERT( list->nodes == 0 );
|
||||
error = FT_Err_Out_Of_Memory;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
FT_ASSERT( list->nodes > 0 );
|
||||
|
||||
while ( node->next )
|
||||
{
|
||||
pnode = &node->next;
|
||||
node = *pnode;
|
||||
}
|
||||
|
||||
/* remove it from the list, and try to "flush" it. doing this will
|
||||
* save a significant number of dynamic allocations compared to
|
||||
* a classic destroy/create cycle
|
||||
*/
|
||||
*pnode = NULL;
|
||||
list->num_nodes -= 1;
|
||||
|
||||
if ( clazz->node_flush )
|
||||
{
|
||||
error = clazz->node_flush( node, key, list->data );
|
||||
if ( !error )
|
||||
goto Success;
|
||||
|
||||
/* note that if an error occured during the flush, we need to
|
||||
* finalize it since it is potentially in incomplete state.
|
||||
*/
|
||||
}
|
||||
|
||||
/* we finalize, but do not destroy the last node, we
|
||||
* simply re-use its memory block !
|
||||
*/
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( node, list->data );
|
||||
|
||||
FT_MEM_ZERO( node, clazz->node_size );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( last, list->data );
|
||||
|
||||
last->key = key;
|
||||
error = clazz->node_init( last, key, list->data );
|
||||
/* try to allocate a new node when "drop_last" is not TRUE
|
||||
* this usually happens on the first pass, when the LRU list
|
||||
* is not already full.
|
||||
*/
|
||||
if ( FT_ALLOC( node, clazz->node_size ) )
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
FT_ASSERT( node != NULL );
|
||||
|
||||
if ( !error )
|
||||
node->key = key;
|
||||
error = clazz->node_init( node, key, list->data );
|
||||
if ( error )
|
||||
{
|
||||
/* move it to the top of the list */
|
||||
*plast = NULL;
|
||||
last->next = list->nodes;
|
||||
list->nodes = last;
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( node, list->data );
|
||||
|
||||
result = last;
|
||||
goto Exit;
|
||||
FT_FREE( node );
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
/* in case of error during the flush or done/init cycle, */
|
||||
/* we need to discard the node */
|
||||
if ( clazz->node_done )
|
||||
clazz->node_done( last, list->data );
|
||||
Success:
|
||||
result = node;
|
||||
|
||||
*plast = NULL;
|
||||
list->num_nodes--;
|
||||
|
||||
FT_FREE( last );
|
||||
node->next = list->nodes;
|
||||
list->nodes = node;
|
||||
list->num_nodes++;
|
||||
goto Exit;
|
||||
|
||||
Fail:
|
||||
if ( error != FT_Err_Out_Of_Memory )
|
||||
goto Exit;
|
||||
|
||||
drop_last = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* otherwise, simply allocate a new node */
|
||||
if ( FT_ALLOC( node, clazz->node_size ) )
|
||||
goto Exit;
|
||||
|
||||
node->key = key;
|
||||
error = clazz->node_init( node, key, list->data );
|
||||
if ( error )
|
||||
{
|
||||
FT_FREE( node );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
result = node;
|
||||
node->next = list->nodes;
|
||||
list->nodes = node;
|
||||
list->num_nodes++;
|
||||
|
||||
Exit:
|
||||
*anode = result;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FT_EXPORT_DEF( void )
|
||||
FT_LruList_Remove( FT_LruList list,
|
||||
FT_LruNode node )
|
||||
|
@ -41,6 +41,8 @@
|
||||
FT_LOCAL_DEF( void )
|
||||
pfr_face_done( PFR_Face face )
|
||||
{
|
||||
FT_Memory memory = face->root.driver->root.memory;
|
||||
|
||||
/* we don't want dangling pointers */
|
||||
face->root.family_name = NULL;
|
||||
face->root.style_name = NULL;
|
||||
@ -49,6 +51,7 @@
|
||||
pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
|
||||
|
||||
/* no need to finalize the logical font or the header */
|
||||
FT_FREE( face->root.available_sizes );
|
||||
}
|
||||
|
||||
|
||||
@ -179,8 +182,8 @@
|
||||
strike = phy_font->strikes;
|
||||
for ( n = 0; n < count; n++, size++, strike++ )
|
||||
{
|
||||
size->height = strike->y_ppm;
|
||||
size->width = strike->x_ppm;
|
||||
size->height = (FT_UShort) strike->y_ppm;
|
||||
size->width = (FT_UShort) strike->x_ppm;
|
||||
}
|
||||
root->num_fixed_sizes = count;
|
||||
}
|
||||
|
@ -111,7 +111,10 @@
|
||||
|
||||
/* allocate new base block */
|
||||
if ( FT_ALLOC( table->block, new_size ) )
|
||||
{
|
||||
table->block = old_base;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* copy elements and shift offsets */
|
||||
if (old_base )
|
||||
|
@ -1827,9 +1827,9 @@
|
||||
gray_convert_glyph( RAS_ARG )
|
||||
{
|
||||
TBand bands[40];
|
||||
volatile TBand* band;
|
||||
volatile int n, num_bands;
|
||||
volatile TPos min, max, max_y;
|
||||
TBand* volatile band;
|
||||
int volatile n, num_bands;
|
||||
TPos volatile min, max, max_y;
|
||||
FT_BBox* clip;
|
||||
|
||||
|
||||
|
@ -70,14 +70,17 @@
|
||||
{
|
||||
FT_Memory memory = zone->memory;
|
||||
|
||||
if ( memory )
|
||||
{
|
||||
FT_FREE( zone->contours );
|
||||
FT_FREE( zone->tags );
|
||||
FT_FREE( zone->cur );
|
||||
FT_FREE( zone->org );
|
||||
|
||||
FT_FREE( zone->contours );
|
||||
FT_FREE( zone->tags );
|
||||
FT_FREE( zone->cur );
|
||||
FT_FREE( zone->org );
|
||||
|
||||
zone->max_points = zone->n_points = 0;
|
||||
zone->max_contours = zone->n_contours = 0;
|
||||
zone->max_points = zone->n_points = 0;
|
||||
zone->max_contours = zone->n_contours = 0;
|
||||
zone->memory = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user