[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [ft]Some problem about FTC_Cache_RemoveFaceID
From: |
suzuki toshiya |
Subject: |
Re: [ft]Some problem about FTC_Cache_RemoveFaceID |
Date: |
Sun, 20 Feb 2011 18:21:02 +0900 |
User-agent: |
Mozilla-Thunderbird 2.0.0.12 (X11/20080406) |
Hi,
Just I've confirmed that the part you found is a bug,
FTC_Cache_RemoveFaceID() cannot free all of the cache nodes
related with a face with given face ID.
It inflates the footprint of the application in runtime,
but the leaked memory is freed by FTC_Manager_Done(), so
it is difficult to be found by SEGV error. I will soon
update the source code.
I really appreciate your hunting of this subtle bug,
thank you very much!
Regards,
mpsuzuki
--
My experiment to confirm this bug is following:
1) Attached is a patch to extend ftbench to take multiple
font pathnames from its argument, and execute benchmarks
for each faces. The faces are cached, and freed when the
number of cached faces exceeds the limit. The size of
face cache can be specified by "-M" option, like this.
$ ftbench -M 3 -C a.ttf b.ttf c.ttf d.ttf e.ttf f.ttf g.ttf ...
*** Benchmark with font file a.ttf
...
*** Benchmark with font file b.ttf
...
*** Benchmark with font file c.ttf
...
*** Benchmark with font file d.ttf
more than max cacheable faces, remove existing cache for a.ttf
...
2) By limiting max face cache to 1, and check the cache
manager before & after FTC_Manager_RemoveFaceID().
Theoretically, all cached objects are related with the first
face, so FTC_Manager_RemoveFaceID() should free all nodes.
But a node is not freed.
Before
(gdb) p *manager
$15 = {library = 0x80e2020,
memory = 0x80e2008,
nodes_list = 0x80f7200,
max_weight = 1048576,
cur_weight = 42271,
num_nodes = 103,
caches = {0x80eb198, 0x80f5aa0, 0x80f6f20, 0x0 <repeats 13 times>},
num_caches = 3,
faces = {num_nodes = 1, max_nodes = 1, ... <=== yes, 1 face is cached
...
After
(gdb) p *manager
$16 = {library = 0x80e2020,
memory = 0x80e2008,
nodes_list = 0x80ef2e8,
max_weight = 1048576,
cur_weight = 238,
num_nodes = 1, <=== oops!
caches = {0x80eb198, 0x80f5aa0, 0x80f6f20, 0x0 <repeats 13 times>},
num_caches = 3,
faces = {num_nodes = 0, max_nodes = 1, ... <=== yes, no face is cached
anymore
...
3) Modifying FTC_Cache_RemoveFaceID's count from "cache->p + cache->mask"
to "cache->p + cache->mask + 1", the last node is freed as theoretical
expect.
After
(gdb) p *manager
$2 = {library = 0x80e2020,
memory = 0x80e2008,
nodes_list = 0x0,
max_weight = 1048576,
cur_weight = 0,
num_nodes = 0, <== ok!
caches = {0x80eb198, 0x80f5aa0, 0x80f6f20, 0x0 <repeats 13 times>},
num_caches = 3,
faces = {num_nodes = 0, max_nodes = 1, ...
...
于晨 wrote:
Thank you very much :)
--- 11年1月18日,周二, Werner LEMBERG <address@hidden> 写道:
发件人: Werner LEMBERG <address@hidden>
主题: Re: [ft]Some problem about FTC_Cache_RemoveFaceID
收件人: address@hidden
抄送: address@hidden, address@hidden
日期: 2011年1月18日,周二,上午12:34
I found some
strange thing when I used
FTC_Cache_RemoveFaceID() to clear the cmap
cache nodes, it
seemed that there
was a node can't be freed, as the code is:
I will check, but please wait a few weeks. I'm quite
sorry.
And please do a ping in about a month if nothing has
happened :-)
Werner
diff --git a/src/ftbench.c b/src/ftbench.c
index 94c05d3..773ed05 100644
--- a/src/ftbench.c
+++ b/src/ftbench.c
@@ -101,7 +101,10 @@ const char* bench_desc[] = {
int preload;
char* filename;
-unsigned int first_index;
+unsigned int gid_initial;
+unsigned int gid_final;
+unsigned int gid_delta;
+unsigned int fill_gid_rect;
FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL;
FT_Int32 load_flags = FT_LOAD_DEFAULT;
@@ -209,18 +212,19 @@ test_load( btimer_t* timer,
FT_Face face,
void* user_data )
{
- int i, done = 0;
+ int i, j, done = 0;
FT_UNUSED( user_data );
TIMER_START( timer );
- for ( i = first_index; i < face->num_glyphs; i++ )
- {
- if ( !FT_Load_Glyph( face, i, load_flags ) )
- done++;
- }
+ for ( j = 0; j < fill_gid_rect; j++ )
+ for ( i = gid_initial + j; i < gid_final; i += gid_delta )
+ {
+ if ( !FT_Load_Glyph( face, i, load_flags ) )
+ done++;
+ }
TIMER_STOP( timer );
@@ -243,9 +247,9 @@ test_load_advances( btimer_t* timer,
TIMER_START( timer );
FT_Get_Advances( face,
- first_index, face->num_glyphs - first_index,
+ gid_initial, gid_final - gid_initial + 1,
flags, advances );
- done += face->num_glyphs - first_index;
+ done += gid_final - gid_initial + 1;
TIMER_STOP( timer );
@@ -260,21 +264,22 @@ test_render( btimer_t* timer,
FT_Face face,
void* user_data )
{
- int i, done = 0;
+ int i, j, done = 0;
FT_UNUSED( user_data );
- for ( i = first_index; i < face->num_glyphs; i++ )
- {
- if ( FT_Load_Glyph( face, i, load_flags ) )
+ for ( j = 0; j < fill_gid_rect; j++ )
+ for ( i = gid_initial + j; i < gid_final; i += gid_delta )
+ {
+ if ( FT_Load_Glyph( face, i, load_flags ) )
continue;
- TIMER_START( timer );
- if ( !FT_Render_Glyph( face->glyph, render_mode ) )
- done++;
- TIMER_STOP( timer );
- }
+ TIMER_START( timer );
+ if ( !FT_Render_Glyph( face->glyph, render_mode ) )
+ done++;
+ TIMER_STOP( timer );
+ }
return done;
}
@@ -284,21 +289,22 @@ test_embolden( btimer_t* timer,
FT_Face face,
void* user_data )
{
- int i, done = 0;
+ int i, j, done = 0;
FT_UNUSED( user_data );
- for ( i = first_index; i < face->num_glyphs; i++ )
- {
- if ( FT_Load_Glyph( face, i, load_flags ) )
- continue;
+ for ( j = 0; j < fill_gid_rect; j++ )
+ for ( i = gid_initial + j; i < gid_final; i += gid_delta )
+ {
+ if ( FT_Load_Glyph( face, i, load_flags ) )
+ continue;
- TIMER_START( timer );
- /*FT_GlyphSlot_Embolden ( face->glyph );*/
- done++;
- TIMER_STOP( timer );
- }
+ TIMER_START( timer );
+ /*FT_GlyphSlot_Embolden ( face->glyph );*/
+ done++;
+ TIMER_STOP( timer );
+ }
return done;
}
@@ -310,24 +316,25 @@ test_get_glyph( btimer_t* timer,
void* user_data )
{
FT_Glyph glyph;
- int i, done = 0;
+ int i, j, done = 0;
FT_UNUSED( user_data );
- for ( i = first_index; i < face->num_glyphs; i++ )
- {
- if ( FT_Load_Glyph( face, i, load_flags ) )
- continue;
-
- TIMER_START( timer );
- if ( !FT_Get_Glyph( face->glyph, &glyph ) )
+ for ( j = 0; j < fill_gid_rect; j++ )
+ for ( i = gid_initial + j; i < gid_final; i += gid_delta )
{
- FT_Done_Glyph( glyph );
- done++;
+ if ( FT_Load_Glyph( face, i, load_flags ) )
+ continue;
+
+ TIMER_START( timer );
+ if ( !FT_Get_Glyph( face->glyph, &glyph ) )
+ {
+ FT_Done_Glyph( glyph );
+ done++;
+ }
+ TIMER_STOP( timer );
}
- TIMER_STOP( timer );
- }
return done;
}
@@ -340,26 +347,27 @@ test_get_cbox( btimer_t* timer,
{
FT_Glyph glyph;
FT_BBox bbox;
- int i, done = 0;
+ int i, j, done = 0;
FT_UNUSED( user_data );
- for ( i = first_index; i < face->num_glyphs; i++ )
- {
- if ( FT_Load_Glyph( face, i, load_flags ) )
- continue;
+ for ( j = 0; j < fill_gid_rect; j++ )
+ for ( i = gid_initial + j; i < gid_final; i += gid_delta )
+ {
+ if ( FT_Load_Glyph( face, i, load_flags ) )
+ continue;
- if ( FT_Get_Glyph( face->glyph, &glyph ) )
- continue;
+ if ( FT_Get_Glyph( face->glyph, &glyph ) )
+ continue;
- TIMER_START( timer );
- FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_PIXELS, &bbox );
- TIMER_STOP( timer );
+ TIMER_START( timer );
+ FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_PIXELS, &bbox );
+ TIMER_STOP( timer );
- FT_Done_Glyph( glyph );
- done++;
- }
+ FT_Done_Glyph( glyph );
+ done++;
+ }
return done;
}
@@ -425,7 +433,7 @@ test_image_cache( btimer_t* timer,
void* user_data )
{
FT_Glyph glyph;
- int i, done = 0;
+ int i, j, done = 0;
FT_UNUSED( user_data );
@@ -438,11 +446,12 @@ test_image_cache( btimer_t* timer,
TIMER_START( timer );
- for ( i = first_index; i < face->num_glyphs; i++ )
- {
- if ( !FTC_ImageCache_Lookup(image_cache, &font_type, i, &glyph, NULL) )
- done++;
- }
+ for ( j = 0; j < fill_gid_rect; j++ )
+ for ( i = gid_initial + j; i < gid_final; i += gid_delta )
+ {
+ if ( !FTC_ImageCache_Lookup(image_cache, &font_type, i, &glyph, NULL) )
+ done++;
+ }
TIMER_STOP( timer );
@@ -456,7 +465,7 @@ test_sbit_cache( btimer_t* timer,
void* user_data )
{
FTC_SBit glyph;
- int i, done = 0;
+ int i, j, done = 0;
FT_UNUSED( user_data );
@@ -469,11 +478,12 @@ test_sbit_cache( btimer_t* timer,
TIMER_START( timer );
- for ( i = first_index; i < face->num_glyphs; i++ )
- {
- if ( !FTC_SBitCache_Lookup(sbit_cache, &font_type, i, &glyph, NULL) )
- done++;
- }
+ for ( j = 0; j < fill_gid_rect; j++ )
+ for ( i = gid_initial + j; i < gid_final; i += gid_delta )
+ {
+ if ( !FTC_SBitCache_Lookup(sbit_cache, &font_type, i, &glyph, NULL) )
+ done++;
+ }
TIMER_STOP( timer );
@@ -553,7 +563,7 @@ get_charset( FT_Face face,
/* */
while ( gindex && i < face->num_glyphs )
{
- if ( gindex >= first_index )
+ if ( gindex >= gid_initial )
charset->code[i++] = charcode;
charcode = FT_Get_Next_Char(face, charcode, &gindex);
}
@@ -565,7 +575,7 @@ get_charset( FT_Face face,
/* no charmap, do an identity mapping */
- for ( i = 0, j = first_index; j < face->num_glyphs; i++, j++ )
+ for ( i = 0, j = gid_initial; j < gid_final; i++, j += gid_delta )
charset->code[i] = j;
}
@@ -642,8 +652,11 @@ void usage(void)
"options:\n"
" -C : compare with cached version if available\n"
" -c : max iteration count for each test (0 means time limited)\n"
+ " -d : glyph index delta in looping (default is 1)\n"
" -f : load flags (hexadecimal)\n"
- " -i : first index to start with (default is 0)\n"
+ " -i : initial glyph index to start with (default is 0)\n"
+ " -j : crawl all glyph between -i & -l\n"
+ " -l : final glyph index to end with (max gid)\n"
" -m : max cache size in KByte (default is %d)\n"
" -p : preload font file in memory\n"
" -r : render mode (default is FT_RENDER_MODE_NORMAL)\n"
@@ -679,12 +692,16 @@ main(int argc,
int compare_cached = 0;
int i;
+ gid_initial = 0;
+ gid_final = UINT_MAX;
+ gid_delta = 1;
+ fill_gid_rect = 1;
while ( 1 )
{
int opt;
- opt = getopt( argc, argv, "Cc:f:i:m:pr:s:t:b:" );
+ opt = getopt( argc, argv, "Cc:f:i:d:f:jl:m:pr:s:t:b:" );
if ( opt == -1 )
break;
@@ -701,7 +718,16 @@ main(int argc,
load_flags = strtol( optarg, NULL, 16 );
break;
case 'i':
- first_index = atoi( optarg );
+ gid_initial = atoi( optarg );
+ break;
+ case 'j':
+ fill_gid_rect = 2;
+ break;
+ case 'l':
+ gid_final = atoi( optarg );
+ break;
+ case 'd':
+ gid_delta = atoi( optarg );
break;
case 'm':
max_bytes = atoi( optarg );
@@ -733,6 +759,8 @@ main(int argc,
break;
}
}
+ if ( fill_gid_rect > 1 )
+ fill_gid_rect = gid_delta;
argc -= optind;
argv += optind;
@@ -752,6 +780,9 @@ main(int argc,
if ( get_face( &face ) )
goto Exit;
+ if ( face->num_glyphs < gid_final )
+ gid_final = face->num_glyphs;
+
if ( FT_IS_SCALABLE( face ) )
{
diff --git a/src/ftdump.c b/src/ftdump.c
index 3bb7fc0..6d0f270 100644
--- a/src/ftdump.c
+++ b/src/ftdump.c
@@ -74,6 +74,7 @@
# endif
#endif
fprintf( stderr, " -n print SFNT name tables\n" );
+ fprintf( stderr, " -8 print non-ASCII characters in octal escaped
format\n" );
fprintf( stderr, " -v be verbose\n" );
fprintf( stderr, "\n" );
@@ -364,6 +365,61 @@
}
+ typedef enum Esc_Type_
+ {
+ Esc_None, /* print raw characters */
+ Esc_Octal, /* octal escaped, \OOO */
+ Esc_Hexadecimal, /* hexadecimal escaped, \xXX */
+ } Esc_Type;
+
+ static Esc_Type esc_nonascii;
+
+ static void
+ put_escaped( FT_Byte* string,
+ FT_UInt string_len,
+ FT_UInt indent,
+ Esc_Type esc_type )
+ {
+ FT_Int ch = 0;
+ FT_UInt j;
+
+
+ for ( j = 0; j < indent; j++ )
+ putchar( ' ' );
+ putchar( '"' );
+
+ for ( j = 0; j < string_len; j++ )
+ {
+ if ( 0 && 0x1F < string[j] && string[j] < 0x7F )
+ {
+ if ( string[j] != 0x5B )
+ putchar( string[j] );
+ else
+ puts( "\\\\" );
+ }
+ else
+ {
+ switch( esc_type )
+ {
+ case Esc_None:
+ putchar( string[j] );
+ break;
+ case Esc_Octal:
+ putchar( '\\' );
+ printf( "%o", string[j] );
+ break;
+ case Esc_Hexadecimal:
+ printf( "\\x" );
+ printf( "%02X", string[j] );
+ break;
+ }
+ }
+ }
+
+ if ( ch != '\n' )
+ putchar( '"' );
+ }
+
void
Print_Sfnt_Names( FT_Face face )
{
@@ -391,7 +447,10 @@
case TT_APPLE_ID_UNICODE_1_1:
case TT_APPLE_ID_ISO_10646:
case TT_APPLE_ID_UNICODE_2_0:
- put_unicode_be16( name.string, name.string_len, 6 );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ put_unicode_be16( name.string, name.string_len, 6 );
break;
default:
@@ -411,11 +470,17 @@
/* FIXME: convert from MacRoman to ASCII/ISO8895-1/whatever */
/* (MacRoman is mostly like ISO8895-1 but there are */
/* differences) */
- put_ascii( name.string, name.string_len, 6 );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ put_ascii( name.string, name.string_len, 6 );
break;
default:
- printf( "{unsupported encoding %d}", name.encoding_id );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ printf( "{unsupported encoding %d}", name.encoding_id );
break;
}
@@ -426,15 +491,24 @@
{
case TT_ISO_ID_7BIT_ASCII:
case TT_ISO_ID_8859_1:
- put_ascii( name.string, name.string_len, 6 );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ put_ascii( name.string, name.string_len, 6 );
break;
case TT_ISO_ID_10646:
- put_unicode_be16( name.string, name.string_len, 6 );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ put_unicode_be16( name.string, name.string_len, 6 );
break;
default:
- printf( "{unsupported encoding %d}", name.encoding_id );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ printf( "{unsupported encoding %d}", name.encoding_id );
break;
}
break;
@@ -450,18 +524,27 @@
/* information from the MS font development team */
case TT_MS_ID_SYMBOL_CS:
case TT_MS_ID_UNICODE_CS:
- put_unicode_be16( name.string, name.string_len, 6 );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ put_unicode_be16( name.string, name.string_len, 6 );
break;
default:
- printf( "{unsupported encoding %d}", name.encoding_id );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ printf( "{unsupported encoding %d}", name.encoding_id );
break;
}
break;
default:
- printf( "{unsupported platform}" );
+ if ( esc_nonascii )
+ put_escaped( name.string, name.string_len, 6, esc_nonascii );
+ else
+ printf( "{unsupported platform}" );
break;
}
@@ -553,11 +636,12 @@
FT_Face face; /* the font face */
- execname = ftdemo_basename( argv[0] );
+ esc_nonascii = Esc_None;
+ execname = ftdemo_basename( argv[0] );
while ( 1 )
{
- option = getopt( argc, argv, "dl:nv" );
+ option = getopt( argc, argv, "8dl:nvX" );
if ( option == -1 )
break;
@@ -578,6 +662,14 @@
name_tables = 1;
break;
+ case '8':
+ esc_nonascii = Esc_Octal;
+ break;
+
+ case 'X':
+ esc_nonascii = Esc_Hexadecimal;
+ break;
+
case 'v':
verbose = 1;
break;
- Re: [ft]Some problem about FTC_Cache_RemoveFaceID,
suzuki toshiya <=