shithub: freetype+ttf2subf

Download patch

ref: 0f7c2f1aa58c2251d6c1a3f388a50bfa97cb097f
parent: 3604d5f5581bdf39d990dcc9b0e21a828dd0f24a
author: Werner Lemberg <[email protected]>
date: Mon Feb 4 15:55:58 EST 2002

Adding the function `FT_Get_Next_Char', doing the obvious thing
w.r.t. the selected charmap.

* include/freetype/freetype.h: Add prototype.
* include/freetype/internal/ftdriver.h: Add `FTDriver_getNextChar'
typedef.
(FT_Driver_Class): Use it.
* include/freetype/internal/psnames.h: Add `PS_Next_Unicode_Func'
typedef.
(PSNames_Interface): Use it.
* include/freetype/internal/tttypes.h: Add `TT_CharNext_Func'
typedef.
(TT_CMapTable): Use it.

* src/base/ftobjs.c (FT_Get_Next_Char): New function, implementing
high-level API.
* src/cff/cffdrivr.c (cff_get_next_char): New function.
(cff_driver_class): Add it.
* src/cid/cidriver.c (Cid_Get_Next_Char): New function.
(t1cid_driver_class): Add it.
* src/pcf/pcfdriver.c (PCF_Get_Next_Char): New function.
(pcf_driver_class): Add it.
* src/psnames/psmodule.c (PS_Next_Unicode): New function.
(psnames_interface): Add it.
* src/sfnt/ttcmap.c (code_to_next0, code_to_next2, code_to_next4,
code_to_next6, code_to_next_8_12, code_to_next_10): New auxiliary
functions.
(TT_CharMap_Load): Use them.
* src/truetype/ttdriver.c (Get_Next_Char): New function.
(tt_driver_class): Add it.
* src/type1/t1driver.c (Get_Next_Char): New function.
(t1_driver_class): Add it.
* src/winfnt/winfnt.c (FNT_Get_Next_Char): New function.
(winfnt_driver_class): Add it.

* src/pcf/pcfread.c (pcf_load_font): For now, report Unicode for
Unicode and Latin 1 encodings.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,43 @@
+2002-02-04  Keith Packard  <[email protected]>
+
+	Adding the function `FT_Get_Next_Char', doing the obvious thing
+	w.r.t. the selected charmap.
+
+	* include/freetype/freetype.h: Add prototype.
+	* include/freetype/internal/ftdriver.h: Add `FTDriver_getNextChar'
+	typedef.
+	(FT_Driver_Class): Use it.
+	* include/freetype/internal/psnames.h: Add `PS_Next_Unicode_Func'
+	typedef.
+	(PSNames_Interface): Use it.
+	* include/freetype/internal/tttypes.h: Add `TT_CharNext_Func'
+	typedef.
+	(TT_CMapTable): Use it.
+
+	* src/base/ftobjs.c (FT_Get_Next_Char): New function, implementing
+	high-level API.
+	* src/cff/cffdrivr.c (cff_get_next_char): New function.
+	(cff_driver_class): Add it.
+	* src/cid/cidriver.c (Cid_Get_Next_Char): New function.
+	(t1cid_driver_class): Add it.
+	* src/pcf/pcfdriver.c (PCF_Get_Next_Char): New function.
+	(pcf_driver_class): Add it.
+	* src/psnames/psmodule.c (PS_Next_Unicode): New function.
+	(psnames_interface): Add it.
+	* src/sfnt/ttcmap.c (code_to_next0, code_to_next2, code_to_next4,
+	code_to_next6, code_to_next_8_12, code_to_next_10): New auxiliary
+	functions.
+	(TT_CharMap_Load): Use them.
+	* src/truetype/ttdriver.c (Get_Next_Char): New function.
+	(tt_driver_class): Add it.
+	* src/type1/t1driver.c (Get_Next_Char): New function.
+	(t1_driver_class): Add it.
+	* src/winfnt/winfnt.c (FNT_Get_Next_Char): New function.
+	(winfnt_driver_class): Add it.
+
+	* src/pcf/pcfread.c (pcf_load_font): For now, report Unicode for
+	Unicode and Latin 1 encodings.
+
 2002-02-02  Keith Packard  <[email protected]>
 
 	* builds/unix/freetype-config.in: Add missing `fi'.
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -122,6 +122,7 @@
   /*    FT_Set_Transform                                                   */
   /*    FT_Load_Glyph                                                      */
   /*    FT_Get_Char_Index                                                  */
+  /*    FT_Get_Next_Char                                                   */
   /*    FT_Get_Name_Index                                                  */
   /*    FT_Load_Char                                                       */
   /*                                                                       */
@@ -2389,6 +2390,27 @@
   FT_EXPORT( FT_UInt )
   FT_Get_Char_Index( FT_Face   face,
                      FT_ULong  charcode );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Get_Next_Char                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Returns the next charcode that is defined in the charmap.          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the source face object.                    */
+  /*                                                                       */
+  /*    charcode :: The character code.                                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The charcode.  0 means `no encoded values above charcode'.         */
+  /*                                                                       */
+  FT_EXPORT( FT_ULong )
+  FT_Get_Next_Char( FT_Face   face,
+                    FT_ULong  charcode );
 
 
   /*************************************************************************/
--- a/include/freetype/internal/ftdriver.h
+++ b/include/freetype/internal/ftdriver.h
@@ -75,6 +75,10 @@
   (*FTDriver_getCharIndex)( FT_CharMap  charmap,
                             FT_Long     charcode );
 
+  typedef FT_Long
+  (*FTDriver_getNextChar)( FT_CharMap   charmap,
+                           FT_Long      charcode );
+
   typedef FT_Error
   (*FTDriver_getKerning)( FT_Face      face,
                           FT_UInt      left_glyph,
@@ -189,6 +193,7 @@
 
     FTDriver_getAdvances    get_advances;
 
+    FTDriver_getNextChar    get_next_char;
   } FT_Driver_Class;
 
 
--- a/include/freetype/internal/psnames.h
+++ b/include/freetype/internal/psnames.h
@@ -166,7 +166,11 @@
   (*PS_Lookup_Unicode_Func)( PS_Unicodes*  unicodes,
                              FT_UInt       unicode );
 
+  typedef FT_ULong
+  (*PS_Next_Unicode_Func)( PS_Unicodes*  unicodes,
+                           FT_ULong      unicode );
 
+
   /*************************************************************************/
   /*                                                                       */
   /* <Struct>                                                              */
@@ -221,6 +225,7 @@
     const unsigned short*      adobe_std_encoding;
     const unsigned short*      adobe_expert_encoding;
 
+    PS_Next_Unicode_Func       next_unicode;
   } PSNames_Interface;
 
 
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1049,7 +1049,11 @@
   (*TT_CharMap_Func)( TT_CMapTable*  charmap,
                       FT_ULong       char_code );
 
+  typedef FT_ULong
+  (*TT_CharNext_Func)( TT_CMapTable* charmap,
+                       FT_ULong      char_code );
 
+
   /* charmap table */
   struct  TT_CMapTable_
   {
@@ -1072,6 +1076,7 @@
     } c;
 
     TT_CharMap_Func  get_index;
+    TT_CharNext_Func get_next_char;
   };
 
 
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -1867,6 +1867,25 @@
     return result;
   }
 
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_ULong )
+  FT_Get_Next_Char( FT_Face   face,
+                    FT_ULong  charcode )
+  {
+    FT_ULong   result;
+    FT_Driver  driver;
+
+
+    result = 0;
+    if ( face && face->charmap )
+    {
+      driver = face->driver;
+      result = driver->clazz->get_next_char( face->charmap, charcode );
+    }
+    return result;
+  }
+
 
   /* documentation is in freetype.h */
 
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -320,6 +320,50 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
+  /*    cff_get_next_char                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Uses a charmap to return the next encoded charcode.                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charmap  :: A handle to the source charmap object.                 */
+  /*    charcode :: The character code.                                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Char code.  0 means `no encoded chars above the given one'.        */
+  /*                                                                       */
+  static FT_Long
+  cff_get_next_char( TT_CharMap  charmap,
+                     FT_Long     charcode )
+  {
+    FT_Error       error;
+    CFF_Face       face;
+    TT_CMapTable*  cmap;
+
+
+    cmap = &charmap->cmap;
+    face = (CFF_Face)charmap->root.face;
+
+    /* Load table if needed */
+    if ( !cmap->loaded )
+    {
+      SFNT_Interface*  sfnt = (SFNT_Interface*)face->sfnt;
+
+
+      error = sfnt->load_charmap( face, cmap, face->root.stream );
+      if ( error )
+        return 0;
+
+      cmap->loaded = TRUE;
+    }
+
+    return ( cmap->get_next_char ? cmap->get_next_char( cmap, charcode ) : 0 );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
   /*    cff_get_name_index                                                 */
   /*                                                                       */
   /* <Description>                                                         */
@@ -454,7 +498,9 @@
 
     (FTDriver_getKerning)   Get_Kerning,
     (FTDriver_attachFile)   0,
-    (FTDriver_getAdvances)  0
+    (FTDriver_getAdvances)  0,
+    
+    (FTDriver_getNextChar)  cff_get_next_char
   };
 
 
--- a/src/cid/cidriver.c
+++ b/src/cid/cidriver.c
@@ -185,6 +185,104 @@
   }
 
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Cid_Get_Next_Char                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Uses a charmap to return the next encoded char after.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charmap  :: A handle to the source charmap object.                 */
+  /*                                                                       */
+  /*    charcode :: The character code.                                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next char code.  0 means `no more char codes'.                     */
+  /*                                                                       */
+  static FT_Long
+  CID_Get_Next_Char( FT_CharMap  charmap,
+                     FT_Long     charcode )
+  {
+    T1_Face             face;
+    PSNames_Interface*  psnames;
+
+
+    face    = (T1_Face)charmap->face;
+    psnames = (PSNames_Interface*)face->psnames;
+
+    if ( psnames )
+      switch ( charmap->encoding )
+      {
+        /*******************************************************************/
+        /*                                                                 */
+        /* Unicode encoding support                                        */
+        /*                                                                 */
+      case ft_encoding_unicode:
+        /* use the `PSNames' module to synthetize the Unicode charmap */
+        return psnames->next_unicode (&face->unicode_map,
+                                      (FT_ULong)charcode );
+
+        /*******************************************************************/
+        /*                                                                 */
+        /* Custom Type 1 encoding                                          */
+        /*                                                                 */
+      case ft_encoding_adobe_custom:
+        {
+          T1_Encoding*  encoding = &face->type1.encoding;
+
+
+          charcode++;
+          if ( charcode < encoding->code_first )
+            charcode = encoding->code_first;
+          while ( charcode <= encoding->code_last )
+          {
+            if ( encoding->char_index[charcode] )
+              return charcode;
+            charcode++;
+          }
+        }
+        break;
+
+        /*******************************************************************/
+        /*                                                                 */
+        /* Adobe Standard & Expert encoding support                        */
+        /*                                                                 */
+      default:
+        while ( ++charcode < 256 )
+        {
+          FT_UInt      code;
+          FT_Int       n;
+          const char*  glyph_name;
+
+
+          code = psnames->adobe_std_encoding[charcode];
+          if ( charmap->encoding == ft_encoding_adobe_expert )
+            code = psnames->adobe_expert_encoding[charcode];
+
+          glyph_name = psnames->adobe_std_strings( code );
+          if ( !glyph_name )
+            continue;
+
+          for ( n = 0; n < face->type1.num_glyphs; n++ )
+          {
+            const char*  gname = face->type1.glyph_names[n];
+
+
+            if ( gname && gname[0] == glyph_name[0] &&
+                 strcmp( gname, glyph_name ) == 0   )
+            {
+              return charcode;
+            }
+          }
+        }
+      }
+
+    return 0;
+  }
+
+
   FT_CALLBACK_TABLE_DEF
   const FT_Driver_Class  t1cid_driver_class =
   {
@@ -228,7 +326,9 @@
     (FTDriver_getKerning)   0,
     (FTDriver_attachFile)   0,
 
-    (FTDriver_getAdvances)  0
+    (FTDriver_getAdvances)  0,
+    
+    (FTDriver_getNextChar)  CID_Get_Next_Char
   };
 
 
--- a/src/pcf/pcfdriver.c
+++ b/src/pcf/pcfdriver.c
@@ -276,6 +276,46 @@
   }
 
 
+  static FT_Long
+  PCF_Get_Next_Char( FT_CharMap  charmap,
+                     FT_Long     char_code )
+  {
+    PCF_Face      face     = (PCF_Face)charmap->face;
+    PCF_Encoding  en_table = face->encodings;
+    int           low, high, mid;
+
+
+    FT_TRACE4(( "get_char_index %ld\n", char_code ));
+    
+    char_code++;
+    low  = 0;
+    high = face->nencodings - 1;
+
+    while ( low <= high )
+    {
+      mid = ( low + high ) / 2;
+      if ( char_code < en_table[mid].enc )
+        high = mid - 1;
+      else if ( char_code > en_table[mid].enc )
+        low = mid + 1;
+      else
+        return char_code;
+    }
+
+    if ( high < 0 )
+      high = 0;
+    
+    while ( high < face->nencodings )
+    {
+      if ( en_table[high].enc >= char_code )
+        return en_table[high].enc;
+      high++;
+    }
+
+    return 0;
+  }
+
+
   FT_CALLBACK_TABLE_DEF
   const FT_Driver_Class  pcf_driver_class =
   {
@@ -313,7 +353,9 @@
 
     (FTDriver_getKerning)   0,
     (FTDriver_attachFile)   0,
-    (FTDriver_getAdvances)  0
+    (FTDriver_getAdvances)  0,
+
+    (FTDriver_getNextChar)  PCF_Get_Next_Char
   };
 
 
--- a/src/pcf/pcfread.c
+++ b/src/pcf/pcfread.c
@@ -1021,10 +1021,14 @@
         root->available_sizes->height = 12;
       }
 
-      /* XXX: charmaps */
+      /* XXX: charmaps.  For now, report unicode for Unicode and Latin 1 */
       root->charmaps     = &face->charmap_handle;
       root->num_charmaps = 1;
 
+      face->charmap.encoding    = ft_encoding_none;
+      face->charmap.platform_id = 0;
+      face->charmap.encoding_id = 0;
+
       {
         PCF_Property  charset_registry = 0, charset_encoding = 0;
 
@@ -1049,28 +1053,21 @@
             strcpy( face->charset_registry, charset_registry->value.atom );
             strcpy( face->charset_encoding, charset_encoding->value.atom );
 
-#if 0
-            if ( !strcmp( charset_registry, "ISO10646" ) )
+            if ( !strcmp( face->charset_registry, "ISO10646" ) ||
+                 ( !strcmp( face->charset_registry, "ISO8859" ) &&
+                   !strcmp( face->charset_encoding, "1" ) ) )
             {
               face->charmap.encoding    = ft_encoding_unicode;
               face->charmap.platform_id = 3;
               face->charmap.encoding_id = 1;
-              face->charmap.face        = root;
-              face->charmap_handle
-
-              return PCF_Err_Ok;
             }
-#endif
           }
         }
       }
 
-      face->charmap.encoding    = ft_encoding_none;
-      face->charmap.platform_id = 0;
-      face->charmap.encoding_id = 0;
-      face->charmap.face        = root;
-      face->charmap_handle      = &face->charmap;
-      root->charmap             = face->charmap_handle;
+      face->charmap.face   = root;
+      face->charmap_handle = &face->charmap;
+      root->charmap        = face->charmap_handle;
     }
     return PCF_Err_Ok;
 
--- a/src/psnames/psmodule.c
+++ b/src/psnames/psmodule.c
@@ -238,6 +238,48 @@
   }
 
 
+  static FT_ULong
+  PS_Next_Unicode( PS_Unicodes*  table,
+                   FT_ULong      unicode )
+  {
+    PS_UniMap  *min, *max, *mid;
+
+
+    unicode++;
+    /* perform a binary search on the table */
+
+    min = table->maps;
+    max = min + table->num_maps - 1;
+
+    while ( min <= max )
+    {
+      mid = min + ( max - min ) / 2;
+      if ( mid->unicode == unicode )
+        return unicode;
+
+      if ( min == max )
+        break;
+
+      if ( mid->unicode < unicode )
+        min = mid + 1;
+      else
+        max = mid - 1;
+    }
+
+    if ( max < table->maps )
+      max = table->maps;
+    
+    while ( max < table->maps + table->num_maps )
+    {
+      if ( unicode < max->unicode )
+        return max->unicode;
+      max++;
+    }
+
+    return 0;
+  }
+
+
 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
 
 
@@ -272,6 +314,7 @@
     0,
     0,
     0,
+    0,
 
 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
 
@@ -279,7 +322,14 @@
     (PS_Adobe_Std_Strings_Func)PS_Standard_Strings,
 
     t1_standard_encoding,
-    t1_expert_encoding
+    t1_expert_encoding,
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+    (PS_Next_Unicode_Func)     PS_Next_Unicode
+#else
+    0
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
   };
 
 
--- a/src/sfnt/ttcmap.c
+++ b/src/sfnt/ttcmap.c
@@ -38,27 +38,51 @@
   code_to_index0( TT_CMapTable*  charmap,
                   FT_ULong       char_code );
 
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next0( TT_CMapTable*  charmap,
+                 FT_ULong       char_code );
+
   FT_CALLBACK_DEF( FT_UInt )
   code_to_index2( TT_CMapTable*  charmap,
                   FT_ULong       char_code );
 
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next2( TT_CMapTable*  charmap,
+                 FT_ULong       char_code );
+
   FT_CALLBACK_DEF( FT_UInt )
   code_to_index4( TT_CMapTable*  charmap,
                   FT_ULong       char_code );
 
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next4( TT_CMapTable*  charmap,
+                 FT_ULong       char_code );
+
   FT_CALLBACK_DEF( FT_UInt )
   code_to_index6( TT_CMapTable*  charmap,
                   FT_ULong       char_code );
 
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next6( TT_CMapTable*  charmap,
+                 FT_ULong       char_code );
+
   FT_CALLBACK_DEF( FT_UInt )
   code_to_index8_12( TT_CMapTable*  charmap,
                      FT_ULong       char_code );
 
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next8_12( TT_CMapTable*  charmap,
+                    FT_ULong       char_code );
+
   FT_CALLBACK_DEF( FT_UInt )
   code_to_index10( TT_CMapTable*  charmap,
                    FT_ULong       char_code );
 
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next10( TT_CMapTable*  charmap,
+                  FT_ULong       char_code );
 
+
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
@@ -125,6 +149,7 @@
         goto Fail;
 
       cmap->get_index = code_to_index0;
+      cmap->get_next_char = code_to_next0;
       break;
 
     case 2:
@@ -196,6 +221,7 @@
       FORGET_Frame();
 
       cmap->get_index = code_to_index2;
+      cmap->get_next_char = code_to_next2;
       break;
 
     case 4:
@@ -262,6 +288,7 @@
       cmap4->last_segment = cmap4->segments;
 
       cmap->get_index = code_to_index4;
+      cmap->get_next_char = code_to_next4;
       break;
 
     case 6:
@@ -287,6 +314,7 @@
 
       FORGET_Frame();
       cmap->get_index = code_to_index6;
+      cmap->get_next_char = code_to_next6;
       break;
 
     case 8:
@@ -328,6 +356,7 @@
       cmap8_12->last_group = cmap8_12->groups;
 
       cmap->get_index = code_to_index8_12;
+      cmap->get_next_char = code_to_next8_12;
       break;
 
     case 10:
@@ -354,6 +383,7 @@
 
       FORGET_Frame();
       cmap->get_index = code_to_index10;
+      cmap->get_next_char = code_to_next10;
       break;
 
     default:   /* corrupt character mapping table */
@@ -471,6 +501,37 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
+  /*    code_to_next0                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finds the next encoded character after the given one.  Uses        */
+  /*    format 0. `charCode' must be in the range 0x00-0xFF (otherwise 0   */
+  /*    is returned).                                                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*    cmap0    :: A pointer to a cmap table in format 0.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next char code.  0 if no higher one is encoded.                    */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next0( TT_CMapTable*  cmap,
+                 FT_ULong       charCode )
+  {
+    TT_CMap0*  cmap0 = &cmap->c.cmap0;
+
+
+    while ( ++charCode <= 0xFF )
+      if ( cmap0->glyphIdArray[charCode] )
+        return ( charCode );
+    return ( 0 );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
   /*    code_to_index2                                                     */
   /*                                                                       */
   /* <Description>                                                         */
@@ -536,6 +597,89 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
+  /*    code_to_next2                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 2.                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*    cmap2    :: A pointer to a cmap table in format 2.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next2( TT_CMapTable*  cmap,
+                 FT_ULong       charCode )
+  {
+    FT_UInt             index1, offset;
+    FT_UInt             char_lo;
+    FT_ULong            char_hi;
+    TT_CMap2SubHeader*  sh2;
+    TT_CMap2*           cmap2;
+
+
+    cmap2 = &cmap->c.cmap2;
+    charCode++;
+
+    /*
+     * This is relatively simplistic -- look for a subHeader containing
+     * glyphs and then walk to the first glyph in that subHeader.
+     */
+    while ( charCode < 0x10000 )
+    {
+      char_lo = (FT_UInt)( charCode & 0xFF );
+      char_hi = charCode >> 8;
+  
+      if ( char_hi == 0 )
+      {
+        /* an 8-bit character code -- we use the subHeader 0 in this case */
+        /* to test whether the character code is in the charmap           */
+        index1 = cmap2->subHeaderKeys[char_lo];
+        if ( index1 != 0 )
+        {
+          charCode++;
+          continue;
+        }
+      }
+      else
+      {
+        /* a 16-bit character code */
+        index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
+        if ( index1 == 0 )
+        {
+          charCode = ( char_hi + 1 ) << 8;
+          continue;
+        }
+      }
+  
+      sh2      = cmap2->subHeaders + index1;
+      char_lo -= sh2->firstCode;
+  
+      if ( char_lo > (FT_UInt)sh2->entryCount )
+      {
+        charCode = ( char_hi + 1 ) << 8;
+        continue;
+      }
+      
+      offset = sh2->idRangeOffset / 2 + char_lo;
+      if ( offset >= (FT_UInt)cmap2->numGlyphId ||
+           cmap2->glyphIdArray[offset] == 0     )
+      {
+        charCode++;
+        continue;
+      }
+      
+      return charCode;
+    }
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
   /*    code_to_index4                                                     */
   /*                                                                       */
   /* <Description>                                                         */
@@ -620,6 +764,73 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
+  /*    code_to_next4                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 4.                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*    cmap     :: A pointer to a cmap table in format 4.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next4( TT_CMapTable*  cmap,
+                 FT_ULong       charCode )
+  {
+    FT_UInt          index1, segCount;
+    TT_CMap4*        cmap4;
+    TT_CMap4Segment  *seg4, *limit;
+
+
+    cmap4    = &cmap->c.cmap4;
+    segCount = cmap4->segCountX2 / 2;
+    limit    = cmap4->segments + segCount;
+
+    charCode++;
+
+    for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
+    {
+      /* The ranges are sorted in increasing order.  If we are out of */
+      /* the range here, the char code isn't in the charmap, so exit. */
+
+      if ( charCode <= (FT_UInt)seg4->endCount )
+        goto Found;
+    }
+    return 0;
+
+  Found:
+    if ( charCode < seg4->startCount )
+      charCode = seg4->startCount;
+
+    /* if the idRangeOffset is 0, all chars in the map exist */
+
+    if ( seg4->idRangeOffset == 0 )
+      return ( charCode );
+    
+    while ( charCode <= (FT_UInt) seg4->endCount )
+    {
+      /* otherwise, we must use the glyphIdArray to do it */
+      index1 = (FT_UInt)( seg4->idRangeOffset / 2
+                          + ( charCode - seg4->startCount )
+                          + ( seg4 - cmap4->segments )
+                          - segCount );
+
+      if ( index1 < (FT_UInt)cmap4->numGlyphId &&
+           cmap4->glyphIdArray[index1] != 0    )
+        return ( charCode );
+      charCode++;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
   /*    code_to_index6                                                     */
   /*                                                                       */
   /* <Description>                                                         */
@@ -653,6 +864,48 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
+  /*    code_to_next6                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 6.                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*    cmap     :: A pointer to a cmap table in format 6.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next6( TT_CMapTable*  cmap,
+                 FT_ULong       charCode )
+  {
+    TT_CMap6*  cmap6;
+
+
+    charCode++;
+    
+    cmap6 = &cmap->c.cmap6;
+    
+    if ( charCode < cmap6->firstCode )
+      charCode = cmap6->firstCode;
+    
+    charCode -= cmap6->firstCode;
+
+    while ( charCode < (FT_UInt)cmap6->entryCount )
+    {
+      if ( cmap6->glyphIdArray[charCode] != 0 )
+        return charCode + cmap6->firstCode;
+      charCode++;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
   /*    code_to_index8_12                                                  */
   /*                                                                       */
   /* <Description>                                                         */
@@ -718,6 +971,51 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
+  /*    code_to_next8_12                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 8 or 12.             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*    cmap     :: A pointer to a cmap table in format 8 or 12.           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next8_12( TT_CMapTable*  cmap,
+                    FT_ULong       charCode )
+  {
+    TT_CMap8_12*  cmap8_12;
+    TT_CMapGroup  *group, *limit;
+
+
+    charCode++;
+    cmap8_12 = &cmap->c.cmap8_12;
+    limit    = cmap8_12->groups + cmap8_12->nGroups;
+
+    for ( group = cmap8_12->groups; group < limit; group++ )
+    {
+      /* the ranges are sorted in increasing order.  If we are out of */
+      /* the range here, the char code isn't in the charmap, so exit. */
+
+      if ( charCode <= group->endCharCode )
+        goto Found;
+    }
+    return 0;
+
+  Found:
+    if ( charCode < group->startCharCode )
+      charCode = group->startCharCode;
+    
+    return charCode;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
   /*    code_to_index10                                                    */
   /*                                                                       */
   /* <Description>                                                         */
@@ -750,6 +1048,51 @@
       result = cmap10->glyphs[charCode];
 
     return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_next10                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 10.                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*    cmap     :: A pointer to a cmap table in format 10.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next10( TT_CMapTable*  cmap,
+                  FT_ULong       charCode )
+  {
+    TT_CMap10*  cmap10;
+
+
+    charCode++;
+    cmap10 = &cmap->c.cmap10;
+    
+    if ( charCode < cmap10->startCharCode )
+      charCode = cmap10->startCharCode;
+    
+    charCode -= cmap10->startCharCode;
+
+    /* the overflow trick for comparison works here also since the number */
+    /* of glyphs (even if numChars is specified as ULong in the specs) in */
+    /* an OpenType font is limited to 64k                                 */
+
+    while ( charCode < cmap10->numChars )
+    {
+      if ( cmap10->glyphs[charCode] )
+        return ( charCode + cmap10->startCharCode );
+      charCode++;
+    }
+
+    return 0;
   }
 
 
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -394,8 +394,55 @@
 
 
   /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Get_Next_Char                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Uses a charmap to return the next encoded char.                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charmap  :: A handle to the source charmap object.                 */
+  /*    charcode :: The character code.                                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next char code.  0 means `no more encoded characters'.             */
+  /*                                                                       */
+  static FT_UInt
+  Get_Next_Char( TT_CharMap  charmap,
+                 FT_Long     charcode )
+  {
+    FT_Error       error;
+    TT_Face        face;
+    TT_CMapTable*  cmap;
+
+
+    cmap = &charmap->cmap;
+    face = (TT_Face)charmap->root.face;
+
+    /* Load table if needed */
+    if ( !cmap->loaded )
+    {
+      SFNT_Interface*  sfnt = (SFNT_Interface*)face->sfnt;
+
+
+      error = sfnt->load_charmap( face, cmap, face->root.stream );
+      if ( error )
+        return 0;
+
+      cmap->loaded = TRUE;
+    }
+
+    if ( cmap->get_next_char )
+      return cmap->get_next_char ( cmap, charcode );
+    else
+      return 0;
+  }
+
+
   /*************************************************************************/
   /*************************************************************************/
+  /*************************************************************************/
   /****                                                                 ****/
   /****                                                                 ****/
   /****                D R I V E R  I N T E R F A C E                   ****/
@@ -473,7 +520,9 @@
 
     (FTDriver_getKerning)   Get_Kerning,
     (FTDriver_attachFile)   0,
-    (FTDriver_getAdvances)  0
+    (FTDriver_getAdvances)  0,
+    
+    (FTDriver_getNextChar)  Get_Next_Char
   };
 
 
--- a/src/type1/t1driver.c
+++ b/src/type1/t1driver.c
@@ -327,6 +327,100 @@
   }
 
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Get_Next_Char                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Uses a charmap to return the next encoded char.                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charmap  :: A handle to the source charmap object.                 */
+  /*    charcode :: The character code.                                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next char code.  0 means `no more char codes'.                     */
+  /*                                                                       */
+  static FT_Long
+  Get_Next_Char( FT_CharMap  charmap,
+                 FT_Long     charcode )
+  {
+    T1_Face             face;
+    PSNames_Interface*  psnames;
+
+
+    face    = (T1_Face)charmap->face;
+    psnames = (PSNames_Interface*)face->psnames;
+
+    if ( psnames )
+      switch ( charmap->encoding )
+      {
+        /*******************************************************************/
+        /*                                                                 */
+        /* Unicode encoding support                                        */
+        /*                                                                 */
+      case ft_encoding_unicode:
+        /* use the `PSNames' module to synthetize the Unicode charmap */
+        return psnames->next_unicode( &face->unicode_map,
+                                      (FT_ULong)charcode );
+
+        /*******************************************************************/
+        /*                                                                 */
+        /* Custom Type 1 encoding                                          */
+        /*                                                                 */
+      case ft_encoding_adobe_custom:
+        {
+          T1_Encoding*  encoding = &face->type1.encoding;
+
+
+          charcode++;
+          if ( charcode < encoding->code_first )
+            charcode = encoding->code_first;
+          while ( charcode <= encoding->code_last  )
+          {
+            if ( encoding->char_index[charcode] )
+              return charcode;
+            charcode++;
+          }
+        }
+
+        /*******************************************************************/
+        /*                                                                 */
+        /* Adobe Standard & Expert encoding support                        */
+        /*                                                                 */
+      default:
+        while ( ++charcode < 256 )
+        {
+          FT_UInt      code;
+          FT_Int       n;
+          const char*  glyph_name;
+
+
+          code = psnames->adobe_std_encoding[charcode];
+          if ( charmap->encoding == ft_encoding_adobe_expert )
+            code = psnames->adobe_expert_encoding[charcode];
+
+          glyph_name = psnames->adobe_std_strings( code );
+          if ( !glyph_name )
+            continue;
+
+          for ( n = 0; n < face->type1.num_glyphs; n++ )
+          {
+            const char*  gname = face->type1.glyph_names[n];
+
+
+            if ( gname && gname[0] == glyph_name[0] &&
+                 strcmp( gname, glyph_name ) == 0   )
+              return charcode;
+          }
+        }
+      }
+
+    return 0;
+  }
+
+
   FT_CALLBACK_TABLE_DEF
   const FT_Driver_Class  t1_driver_class =
   {
@@ -371,7 +465,9 @@
     (FTDriver_getKerning)   Get_Kerning,
     (FTDriver_attachFile)   T1_Read_AFM,
 #endif
-    (FTDriver_getAdvances)  0
+    (FTDriver_getAdvances)  0,
+    
+    (FTDriver_getNextChar)  Get_Next_Char
   };
 
 
--- a/src/winfonts/winfnt.c
+++ b/src/winfonts/winfnt.c
@@ -494,7 +494,28 @@
     return result;
   }
 
+  static FT_Long
+  FNT_Get_Next_Char( FT_CharMap  charmap,
+                     FT_Long     char_code )
+  {
+    char_code++;
+    if ( charmap )
+    {
+      FNT_Font*  font  = ((FNT_Face)charmap->face)->fonts;
+      FT_Long    first = font->header.first_char;
 
+
+      if ( char_code < first )
+        char_code = first;
+      if ( char_code <= font->header.last_char )
+        return char_code;
+    }
+    else
+      return char_code;
+    return 0;
+  }
+
+
   static FT_Error
   FNT_Load_Glyph( FT_GlyphSlot  slot,
                   FNT_Size      size,
@@ -622,7 +643,9 @@
 
     (FTDriver_getKerning)   0,
     (FTDriver_attachFile)   0,
-    (FTDriver_getAdvances)  0
+    (FTDriver_getAdvances)  0,
+
+    (FTDriver_getNextChar)  FNT_Get_Next_Char
   };