freetype
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ft] wip: looped reference detection (Re: Failure in loading U+033F in D


From: suzuki toshiya
Subject: [ft] wip: looped reference detection (Re: Failure in loading U+033F in DejaVu fonts)
Date: Tue, 10 May 2016 12:53:20 +0900
User-agent: Mozilla-Thunderbird 2.0.0.24 (X11/20100329)

Dear Werner,

The original detection was sufficient for the case:

the composition tree is something like
a-+-b-c-b
  +-d
  +-e

the composites list would be "a-b-c-b-d-e", and it can
detect the loop at the 2nd occurrence of b.

In DejaVu case, the structure is

a-+-b
  +-b

and the composites list would be "a-b-b", and
it can confuse the detector at the 2nd occurrence of b.

Just I've scratched an idea as attached one;
* record both of gid & recursion count into loader->composites.
* if same gid is found at the earlier recursion count, it is recognized as loop.

the composites list for the former case would be
"a:1 - b:2 - c:3 - b:4 - d:2 - e:2", we can detect the loop
by the existence of "b:2" and "b:4".
the composites list for the latter case would be
"a:1 - b:2 - b:2", we can expect that it is repeated but not looped.

It works for DejaVu, but soon I found this check was insufficient.
the case like
a-+-b-c-d
  +-e-f-b
can confuse my scratch again (b:2 and b:4 would be recognized
as looped).

Now I think we should ignore the "b-c-d" chain when we
are tracking "e-f-b" chain.

I think repeating alloc & free during the process of glyph
composition is not good idea (although I've not checked its overhead).
Maybe I will propose new function FT_List_Down() which moves
the specified node to the end of the list.

Regards,
mpsuzuki

Werner LEMBERG wrote:
>> It seems that the changeset 758d55e522eb426dad2f15adc1d945f7896d7b29
>> (between 2.6.1 and 2.6.2) is the point that FT2 starts the complain
>> against DejaVu. The changset was introduced to detected looped
>> reference. [...]
> 
> Thanks for your analysis.  It seems that the test to protect against
> recursion is a bit too simple.
> 
>> I guess the composite glyphs referring same component twice or more
>> can cause this warning. I will try to fix it...
> 
> Great! 
> 
> 
>     Werner
> 
diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c
index f37530d..a2036d1 100644
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -23,6 +23,7 @@
 #include "afmodule.h"
 #include "afpic.h"
 
+#include FT_INTERNAL_CALC_H
 
   /* Initialize glyph loader. */
 
diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c
index 9a8b458..96208b6 100644
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -1367,6 +1367,62 @@
 
 #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
 
+  /*************************************************************************/
+  /* storage to track the decomposition process, to detect a looped        */
+  /* reference in the composite glyph                                      */
+  typedef struct TT_GlyphDecomp_
+  {
+    FT_UInt  gid;
+    FT_UInt  recurse_count;
+  } TT_GlyphDecomp;
+
+  static TT_GlyphDecomp*
+  tt_new_glyphdecomp( FT_Memory  memory,
+                      FT_UInt    gid,
+                      FT_UInt    recurse_count )
+  {
+    FT_Error error;
+    TT_GlyphDecomp *gd = NULL;
+    FT_ALLOC( gd, sizeof(TT_GlyphDecomp) );
+
+    if (!error)
+    {
+      FT_TRACE5(( " tt_new_glyphdecomp: allocate for {%d, %d} @ 0x%p\n", gid, 
recurse_count, gd ));
+      gd->gid = gid;
+      gd->recurse_count = recurse_count;
+    }
+
+    return gd;
+  }
+
+  static void
+  tt_destroy_glyphdecomp( FT_Memory        memory,
+                          TT_GlyphDecomp*  gd,
+                          void*            user )
+  {
+    FT_TRACE5(( " tt_destroy_glyphdecomp: free {%d, %d} @ 0x%p\n", gd->gid, 
gd->recurse_count, gd ));
+    FT_FREE( gd );
+  }
+
+  static FT_Error
+  tt_lookup_earlier_glyphdecomp( FT_ListNode      node,
+                                 TT_GlyphDecomp*  gd_lookup )
+  {
+    TT_GlyphDecomp*  gd_node = (TT_GlyphDecomp*)(node->data);
+    if ( gd_node->gid != gd_lookup->gid )
+    {
+      FT_TRACE5(( " tt_lookup_earlier_glyphdecomp: different gid (%d != 
%d)\n", gd_node->gid, gd_lookup->gid ));
+      return FT_Err_Ok;
+    }
+    if ( gd_node->recurse_count < gd_lookup->recurse_count )
+    {
+      FT_TRACE5(( " tt_lookup_earlier_glyphdecomp: found earlier occurence (%d 
< %d)\n", gd_node->recurse_count, gd_lookup->recurse_count ));
+      return FT_Err_Invalid_Composite;
+    }
+    FT_TRACE5(( " tt_lookup_earlier_glyphdecomp: found later occurence (%d >= 
%d)\n", gd_node->recurse_count, gd_lookup->recurse_count ));
+    return FT_Err_Ok;
+  }
+
 
   /*************************************************************************/
   /*                                                                       */
@@ -1639,10 +1695,12 @@
       FT_UInt   start_point;
       FT_UInt   start_contour;
       FT_ULong  ins_pos;  /* position of composite instructions, if any */
+      TT_GlyphDecomp  gd_cur = { glyph_index, recurse_count };
 
 
       /* check whether we already have a composite glyph with this index */
-      if ( FT_List_Find( &loader->composites, (void*)glyph_index ) )
+      FT_TRACE2(( "TT_Load_Composite_Glyph: lookup gid-%d in 
loader->composites (%p)\n", glyph_index, &(loader->composites) ));
+      if ( FT_List_Iterate( &loader->composites, 
(FT_List_Iterator)tt_lookup_earlier_glyphdecomp, &gd_cur ) )
       {
         FT_TRACE1(( "TT_Load_Composite_Glyph:"
                     " infinite recursion detected\n" ));
@@ -1656,7 +1714,8 @@
 
         if ( FT_NEW( node ) )
           goto Exit;
-        node->data = (void*)glyph_index;
+        node->data = (void*)tt_new_glyphdecomp( memory, glyph_index, 
recurse_count );
+        FT_TRACE2(( "TT_Load_Composite_Glyph: append gid-%d to 
loader->composites (%p)\n", glyph_index, &(loader->composites) ));
         FT_List_Add( &loader->composites, node );
       }
 
@@ -2419,6 +2478,7 @@
     loader->glyph  = (FT_GlyphSlot)glyph;
     loader->stream = stream;
 
+    FT_TRACE2(( "tt_loader_init(): initialize loader->composites (%p)\n", 
&(loader->composites) ));
     loader->composites.head = NULL;
     loader->composites.tail = NULL;
 
@@ -2429,8 +2489,9 @@
   static void
   tt_loader_done( TT_Loader  loader )
   {
+    FT_TRACE2(( "tt_loader_done(): finalize loader->composites (%p)\n", 
&(loader->composites) ));
     FT_List_Finalize( &loader->composites,
-                      NULL,
+                      (FT_List_Destructor)tt_destroy_glyphdecomp,
                       loader->face->root.memory,
                       NULL );
   }

reply via email to

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