Commit 150c0dc616b18922f8524d4902f408dcd8c54dda

David Turner 2005-02-28T17:17:47

optimization of linear charmap scanning for Format 4

diff --git a/src/sfnt/ttcmap.c b/src/sfnt/ttcmap.c
index bc851ee..8193368 100644
--- a/src/sfnt/ttcmap.c
+++ b/src/sfnt/ttcmap.c
@@ -621,6 +621,174 @@
 
 #ifdef TT_CONFIG_CMAP_FORMAT_4
 
+#define  OPT_CMAP4
+
+#ifdef OPT_CMAP4
+
+  typedef struct TT_CMap4Rec_
+  {
+    TT_CMapRec   cmap;
+    FT_UInt32    old_charcode;   /* old charcode */
+    FT_UInt32    cur_charcode;   /* current charcode */
+    FT_UInt      cur_gindex;     /* current glyph index */
+
+    FT_UInt      table_length;
+    FT_UInt      num_ranges;
+    FT_UInt      cur_range;
+    FT_UInt      cur_start;
+    FT_UInt      cur_end;
+    FT_Int       cur_delta;
+    FT_Byte*     cur_values;
+
+  } TT_CMap4Rec, *TT_CMap4;
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  tt_cmap4_init( TT_CMap4  cmap,
+                 FT_Byte*  table )
+  {
+    FT_Byte*   p;
+
+    cmap->cmap.data = table;
+
+    p                  = table + 2;
+    cmap->table_length = FT_PEEK_USHORT(p);
+
+    p                  = table + 6;
+    cmap->num_ranges   = FT_PEEK_USHORT(p) >> 1;
+    cmap->cur_range    = cmap->num_ranges;
+    cmap->old_charcode = 0xFFFFFFFFUL;
+    cmap->cur_charcode = 0;
+    cmap->cur_gindex   = 0;
+
+    return 0;
+  }
+
+
+
+  static FT_Int
+  tt_cmap4_set_range( TT_CMap4  cmap,
+                      FT_UInt   range_index )
+  {
+    FT_Byte*  table = cmap->cmap.data;
+    FT_Byte*  p;
+    FT_UInt   num_ranges = cmap->num_ranges;
+
+    while ( range_index < num_ranges )
+    {
+      FT_UInt  offset;
+
+      p             = table + 14 + range_index*2;
+      cmap->cur_end = FT_PEEK_USHORT(p);
+
+      p              += 2 + num_ranges*2;
+      cmap->cur_start = FT_PEEK_USHORT(p);
+
+      p += num_ranges*2;
+      cmap->cur_delta = FT_PEEK_SHORT(p);
+
+      p += num_ranges*2;
+      offset = FT_PEEK_SHORT(p);
+
+      if ( offset != 0xFFFF )
+      {
+        cmap->cur_values = offset ? p + offset : NULL;
+        cmap->cur_range  = range_index;
+        return 0;
+      }
+
+      /* we skip empty segments */
+      range_index++;
+    }
+
+    cmap->old_charcode = 0xFFFFFFFFUL;
+    cmap->cur_charcode = 0;
+    cmap->cur_gindex   = 0;
+    cmap->cur_range    = num_ranges;
+    return -1;
+  }
+
+
+  static void
+  tt_cmap4_next( TT_CMap4  cmap )
+  {
+    FT_UInt  num_ranges = cmap->num_ranges;
+    FT_UInt  charcode   = cmap->cur_charcode + 1;
+
+    cmap->old_charcode = cmap->cur_charcode;
+
+    for ( ;; )
+    {
+      FT_Byte* values = cmap->cur_values;
+      FT_UInt  end    = cmap->cur_end;
+      FT_Int   delta  = cmap->cur_delta;
+
+      if ( charcode <= end )
+      {
+        if ( values )
+        {
+          FT_Byte*  p = values + 2*(charcode-cmap->cur_start);
+
+          do
+          {
+            FT_UInt  gindex = FT_NEXT_USHORT(p);
+
+            if ( gindex != 0 )
+            {
+              gindex = (FT_UInt)((gindex + delta) & 0xFFFF);
+              if ( gindex != 0 )
+              {
+                cmap->cur_charcode = charcode;
+                cmap->cur_gindex   = gindex;
+                return;
+              }
+            }
+          }
+          while ( ++charcode <= end );
+        }
+        else
+        {
+          do
+          {
+            FT_UInt  gindex = (FT_UInt)((charcode + delta) & 0xFFFFU);
+
+            if ( gindex != 0 )
+            {
+              cmap->cur_charcode = charcode;
+              cmap->cur_gindex   = gindex;
+              return;
+            }
+          }
+          while ( ++charcode <= end );
+        }
+      }
+
+     /* we need to find another range
+      */
+      if ( tt_cmap4_set_range( cmap, cmap->cur_range+1 ) < 0 )
+        break;
+
+      charcode = cmap->cur_start;
+    }
+  }
+
+
+  static void
+  tt_cmap4_reset( TT_CMap4  cmap,
+                  FT_UInt   code,
+                  FT_UInt   range_index )
+  {
+    if ( tt_cmap4_set_range( cmap, range_index ) >= 0 )
+    {
+      cmap->cur_charcode = code;
+      tt_cmap4_next( cmap );
+    }
+  }
+
+#endif /* OPT_CMAP4 */
+
+
+
   FT_CALLBACK_DEF( void )
   tt_cmap4_validate( FT_Byte*      table,
                      FT_Validator  valid )
@@ -798,7 +966,6 @@
       FT_UInt   code = (FT_UInt)char_code;
       FT_Byte*  p;
 
-
       p         = table + 6;
       num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );  /* be paranoid! */
 
@@ -921,6 +1088,23 @@
     if ( char_code >= 0xFFFFUL )
       goto Exit;
 
+#ifdef OPT_CMAP4
+      {
+        TT_CMap4  cmap4 = (TT_CMap4)cmap;
+
+        if ( char_code == cmap4->old_charcode )
+        {
+          result = cmap4->cur_charcode;
+          gindex = cmap4->cur_gindex;
+          if ( result != 0 )
+          {
+            tt_cmap4_next( cmap4 );
+            goto Exit;
+          }
+        }
+      }
+#endif /* OPT_CMAP4 */
+
     code      = (FT_UInt)char_code + 1;
     p         = table + 6;
     num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT(p), 2 );  /* ensure even-ness */
@@ -993,6 +1177,9 @@
             if ( gindex != 0 )
             {
               result = code;
+#ifdef OPT_CMAP4
+              tt_cmap4_reset( (TT_CMap4)cmap, code, hi );
+#endif
               goto Exit;
             }
           }
@@ -1001,7 +1188,7 @@
       }
       else if ( offset == 0xFFFFU )
       {
-        /* an offset of 0xFFFF means an empty glyph in certain fonts! */
+        /* an offset of 0xFFFF means an empty segment in certain fonts! */
         code = end + 1;
       }
       else  /* offset == 0 */
@@ -1010,6 +1197,9 @@
         if ( gindex != 0 )
         {
           result = code;
+#ifdef OPT_CMAP4
+          tt_cmap4_reset( (TT_CMap4)cmap, code, hi );
+#endif
           goto Exit;
         }
         code++;
@@ -1108,9 +1298,13 @@
   const TT_CMap_ClassRec  tt_cmap4_class_rec =
   {
     {
+#ifdef OPT_CMAP4
+      sizeof ( TT_CMap4Rec ),
+      (FT_CMap_InitFunc)     tt_cmap4_init,
+#else
       sizeof ( TT_CMapRec ),
-
       (FT_CMap_InitFunc)     tt_cmap_init,
+#endif
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
       (FT_CMap_CharNextFunc) tt_cmap4_char_next