freetype
[Top][All Lists]
Advanced

[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;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]