shithub: freetype+ttf2subf

Download patch

ref: 9a966b7d1bbc9e35eddb68136b73cbe006dff675
parent: cc272c51667fb0a286bf9b8e46096f74f50aa335
author: Werner Lemberg <[email protected]>
date: Mon Oct 15 13:21:32 EDT 2007

Add support for cmap type 14.

* devel/ftoption.h, include/freetype/config/ftoption.h
(TT_CONFIG_CMAP_FORMAT_14): New macro.

* include/freetype/internal/ftobjs.h (FT_CMap_CharVarIndexFunc,
FT_CMap_CharVarIsDefaultFunc, FT_CMap_VariantListFunc,
FT_CMap_CharVariantListFunc, FT_CMap_VariantCharListFunc): New
support function prototypes.
(FT_CMap_ClassRec): Add them.
Update all users.

* include/freetype/ttnameid.h (TT_APPLE_ID_VARIANT_SELECTOR): New
macro.

* include/freetype/freetype.h (FT_Get_Char_Variant_Index,
FT_Get_Char_Variant_IsDefault, FT_Get_Variant_Selectors,
FT_Get_Variants_Of_Char, FT_Get_Chars_Of_Variant): New API
functions.

* src/base/ftobjs.c (find_variant_selector_charmap): New auxiliary
function.
(FT_Set_Charmap): Disallow cmaps of type 14.
(FT_Get_Char_Variant_Index, FT_Get_Char_Variant_IsDefault,
FT_Get_Variant_Selectors, FT_Get_Variants_Of_Char,
FT_Get_Chars_Of_Variant): New API functions.

* src/sfnt/ttcmap.c (TT_PEEK_UINT24, TT_NEXT_UINT24): New macros.

(TT_CMap14Rec, tt_cmap14_init, tt_cmap14_validate,
tt_cmap14_char_index, tt_cmap14_char_next, tt_cmap14_get_info,
tt_cmap14_char_map_def_binary, tt_cmap14_char_map_nondef_binary,
tt_cmap14_find_variant, tt_cmap14_char_var_index,
tt_cmap14_char_var_isdefault, tt_cmap14_variants,
tt_cmap14_char_variants, tt_cmap14_def_char_count,
tt_cmap14_get_def_chars, tt_cmap14_get_nondef_chars,
tt_cmap14_variant_chars, tt_cmap14_class_rec): New functions and
structures for cmap 14 support.
(tt_cmap_classes): Register tt_cmap14_class_rec.
(tt_face_build_cmaps): One more error message.

* docs/CHANGES: Mention cmap 14 support.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+2007-10-15  George Williams  <[email protected]>
+
+	Add support for cmap type 14.
+
+	* devel/ftoption.h, include/freetype/config/ftoption.h
+	(TT_CONFIG_CMAP_FORMAT_14): New macro.
+
+	* include/freetype/internal/ftobjs.h (FT_CMap_CharVarIndexFunc,
+	FT_CMap_CharVarIsDefaultFunc, FT_CMap_VariantListFunc,
+	FT_CMap_CharVariantListFunc, FT_CMap_VariantCharListFunc): New
+	support function prototypes.
+	(FT_CMap_ClassRec): Add them.
+	Update all users.
+
+	* include/freetype/ttnameid.h (TT_APPLE_ID_VARIANT_SELECTOR): New
+	macro.
+
+	* include/freetype/freetype.h (FT_Get_Char_Variant_Index,
+	FT_Get_Char_Variant_IsDefault, FT_Get_Variant_Selectors,
+	FT_Get_Variants_Of_Char, FT_Get_Chars_Of_Variant): New API
+	functions.
+
+	* src/base/ftobjs.c (find_variant_selector_charmap): New auxiliary
+	function.
+	(FT_Set_Charmap): Disallow cmaps of type 14.
+	(FT_Get_Char_Variant_Index, FT_Get_Char_Variant_IsDefault,
+	FT_Get_Variant_Selectors, FT_Get_Variants_Of_Char,
+	FT_Get_Chars_Of_Variant): New API functions.
+
+	* src/sfnt/ttcmap.c (TT_PEEK_UINT24, TT_NEXT_UINT24): New macros.
+
+	(TT_CMap14Rec, tt_cmap14_init, tt_cmap14_validate,
+	tt_cmap14_char_index, tt_cmap14_char_next, tt_cmap14_get_info,
+	tt_cmap14_char_map_def_binary, tt_cmap14_char_map_nondef_binary,
+	tt_cmap14_find_variant, tt_cmap14_char_var_index,
+	tt_cmap14_char_var_isdefault, tt_cmap14_variants,
+	tt_cmap14_char_variants, tt_cmap14_def_char_count,
+	tt_cmap14_get_def_chars, tt_cmap14_get_nondef_chars,
+	tt_cmap14_variant_chars, tt_cmap14_class_rec): New functions and
+	structures for cmap 14 support.
+	(tt_cmap_classes): Register tt_cmap14_class_rec.
+	(tt_face_build_cmaps): One more error message.
+
+	* docs/CHANGES: Mention cmap 14 support.
+
 2007-10-01  Werner Lemberg  <[email protected]>
 
 	* src/base/ftobjs.c (find_unicode_charmap): If search for a UCS-4
@@ -6,10 +51,10 @@
 
 2007-08-29  suzuki toshiya  <[email protected]>
 
-	* src/base/ftmac.c: Introduction of abstract "short" data types,
-	ResFileRefNum and ResID. These types were introduced for Copland,
-	then backported to MPW. The variables exchanged with FileManager
-	QuickDraw frameworks are redefined by these data types. Patch was
+	* src/base/ftmac.c: Introduction of abstract `short' data types,
+	ResFileRefNum and ResID.  These types were introduced for Copland,
+	then backported to MPW.  The variables exchanged with FileManager
+	QuickDraw frameworks are redefined by these data types.  Patch was
 	proposed by Sean McBride.
 	* builds/mac/ftmac.c: Ditto.
 
--- a/devel/ftoption.h
+++ b/devel/ftoption.h
@@ -436,6 +436,7 @@
 #define TT_CONFIG_CMAP_FORMAT_8
 #define TT_CONFIG_CMAP_FORMAT_10
 #define TT_CONFIG_CMAP_FORMAT_12
+#define TT_CONFIG_CMAP_FORMAT_14
 
 
   /*************************************************************************/
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -1,6 +1,16 @@
 
 CHANGES BETWEEN 2.3.6 and 2.3.5
 
+  I. IMPORTANT BUG FIXES
+
+    - Microsoft  Unicode  cmaps  in  TrueType  fonts  are  now  always
+      preferred over Apple cmaps.  This is not a bug per se, but there
+      exist some buggy  fonts created for MS which  have broken  Apple
+      cmaps.  This affects  only the automatic  selection of FreeType;
+      it's always possible to manually select an Apple Unicode cmap if
+      desired.
+
+
   II. IMPORTANT CHANGES
 
     - The new function `FT_Get_CID_Registry_Ordering_Supplement' gives
@@ -10,6 +20,9 @@
     - George Williams  contributed  code  to validate  the new  `MATH'
       OpenType  table (within  the `otvalid'  module).  The  `ftvalid'
       demo program has been extended accordingly.
+
+    - An API for cmap 14 support  (for Unicode Variant Selectors, UVS)
+      has been contributed by George Williams.
 
 ======================================================================
 
--- a/include/freetype/config/ftoption.h
+++ b/include/freetype/config/ftoption.h
@@ -436,6 +436,7 @@
 #define TT_CONFIG_CMAP_FORMAT_8
 #define TT_CONFIG_CMAP_FORMAT_10
 #define TT_CONFIG_CMAP_FORMAT_12
+#define TT_CONFIG_CMAP_FORMAT_14
 
 
   /*************************************************************************/
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -2852,6 +2852,8 @@
   /*    the face (i.e., if it is not listed in the `face->charmaps'        */
   /*    table).                                                            */
   /*                                                                       */
+  /*    It also fails if a type 14 charmap is selected.                    */
+  /*                                                                       */
   FT_EXPORT( FT_Error )
   FT_Set_Charmap( FT_Face     face,
                   FT_CharMap  charmap );
@@ -2988,6 +2990,162 @@
   FT_Get_Next_Char( FT_Face    face,
                     FT_ULong   char_code,
                     FT_UInt   *agindex );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Get_Char_Variant_Index                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Return the glyph index of a given character code as modified by    */
+  /*    the variation selector.                                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face ::                                                            */
+  /*      A handle to the source face object.                              */
+  /*                                                                       */
+  /*    charcode ::                                                        */
+  /*      The character code point in Unicode.                             */
+  /*                                                                       */
+  /*    variantSelector ::                                                 */
+  /*      The Unicode code point of the variation selector.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The glyph index.  0 means either `undefined character code', or    */
+  /*    `undefined selector code', or `no variation selector cmap          */
+  /*    subtable', or `current CharMap is not Unicode'.                    */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    If you use FreeType to manipulate the contents of font files       */
+  /*    directly, be aware that the glyph index returned by this function  */
+  /*    doesn't always correspond to the internal indices used within      */
+  /*    the file.  This is done to ensure that value 0 always corresponds  */
+  /*    to the `missing glyph'.                                            */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This function is only meaningful if:                               */
+  /*      a) the font has a variation selector cmap sub table              */
+  /*      b) the current charmap has a Unicode encoding                    */
+  /*                                                                       */
+  FT_EXPORT( FT_UInt )
+  FT_Get_Char_Variant_Index( FT_Face   face,
+                             FT_ULong  charcode,
+                             FT_ULong  variantSelector );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Get_Char_Variant_IsDefault                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Check whether this variant of this Unicode character is the one to */
+  /*    be found in the `cmap'.                                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face ::                                                            */
+  /*      A handle to the source face object.                              */
+  /*                                                                       */
+  /*    charcode ::                                                        */
+  /*      The character codepoint in Unicode.                              */
+  /*                                                                       */
+  /*    variantSelector ::                                                 */
+  /*      The Unicode codepoint of the variation selector.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    1 if found in the standard (Unicode) cmap, 0 if found in the       */
+  /*    variation selector cmap, or -1 if it is not a variant.             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This function is only meaningful if the font has a variation       */
+  /*    selector cmap subtable.                                            */
+  /*                                                                       */
+  FT_EXPORT( FT_Int )
+  FT_Get_Char_Variant_IsDefault( FT_Face   face,
+                                 FT_ULong  charcode,
+                                 FT_ULong  variantSelector );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Get_Variant_Selectors                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Return a zero-terminated list of Unicode variant selectors found   */
+  /*    in the font.                                                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A handle to the source face object.                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    A list of all the variant selector code points in the cmap         */
+  /*    or NULL if there is no valid variant selector cmap subtable.       */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    User is responsible for deallocating the returned list.            */
+  /*                                                                       */
+  FT_EXPORT( FT_UInt32* )
+  FT_Get_Variant_Selectors( FT_Face  face );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Get_Variants_Of_Char                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Return a zero-terminated list of Unicode variant selectors found   */
+  /*    for the specified character code.                                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face ::                                                            */
+  /*      A handle to the source face object.                              */
+  /*                                                                       */
+  /*    charcode ::                                                        */
+  /*      The character codepoint in Unicode.                              */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    A list of all the variant selector code points which are active    */
+  /*    for the given character or NULL if there is no valid variant       */
+  /*    selector cmap subtable (or if if this character has no variants).  */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    User is responsible for deallocating the returned list.            */
+  /*                                                                       */
+  FT_EXPORT( FT_UInt32* )
+  FT_Get_Variants_Of_Char( FT_Face   face,
+                           FT_ULong  charcode );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Get_Chars_Of_Variant                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Return a zero-terminated list of Unicode character codes found for */
+  /*    the specified variant selector.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face ::                                                            */
+  /*      A handle to the source face object.                              */
+  /*                                                                       */
+  /*    variantSelector ::                                                 */
+  /*      The variant selector code point in Unicode.                      */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    A list of all the code points which are specified by this selector */
+  /*    (both default and non-default codes are returned) or NULL if there */
+  /*    is no valid cmap or the variant selector is invalid.               */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    User is responsible for deallocating the returned list.            */
+  /*                                                                       */
+  FT_EXPORT( FT_UInt32* )
+  FT_Get_Chars_Of_Variant( FT_Face   face,
+                           FT_ULong  variantSelector );
 
 
   /*************************************************************************/
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -160,7 +160,32 @@
   (*FT_CMap_CharNextFunc)( FT_CMap     cmap,
                            FT_UInt32  *achar_code );
 
+  typedef FT_UInt
+  (*FT_CMap_CharVarIndexFunc)( FT_CMap    cmap,
+                               FT_CMap    unicode_cmap,
+                               FT_UInt32  char_code,
+                               FT_UInt32  variant_selector );
 
+  typedef FT_Bool
+  (*FT_CMap_CharVarIsDefaultFunc)( FT_CMap    cmap,
+                                   FT_UInt32  char_code,
+                                   FT_UInt32  variant_selector );
+
+  typedef FT_UInt32 *
+  (*FT_CMap_VariantListFunc)( FT_CMap    cmap,
+                              FT_Memory  mem );
+
+  typedef FT_UInt32 *
+  (*FT_CMap_CharVariantListFunc)( FT_CMap    cmap,
+                                  FT_Memory  mem,
+                                  FT_UInt32  char_code );
+
+  typedef FT_UInt32 *
+  (*FT_CMap_VariantCharListFunc)( FT_CMap    cmap,
+                                  FT_Memory  mem,
+                                  FT_UInt32  variant_selector );
+
+
   typedef struct  FT_CMap_ClassRec_
   {
     FT_ULong               size;
@@ -168,6 +193,15 @@
     FT_CMap_DoneFunc       done;
     FT_CMap_CharIndexFunc  char_index;
     FT_CMap_CharNextFunc   char_next;
+
+    /* Subsequent entries are special ones for format 14 -- the variant */
+    /* selector subtable which behaves like no other                    */
+
+    FT_CMap_CharVarIndexFunc      char_var_index;
+    FT_CMap_CharVarIsDefaultFunc  char_var_default;
+    FT_CMap_VariantListFunc       variant_list;
+    FT_CMap_CharVariantListFunc   charvariant_list;
+    FT_CMap_VariantCharListFunc   variantchar_list;
 
   } FT_CMap_ClassRec;
 
--- a/include/freetype/ttnameid.h
+++ b/include/freetype/ttnameid.h
@@ -108,13 +108,18 @@
    *
    *   TT_APPLE_ID_UNICODE_32 ::
    *     Unicode 3.1 and beyond, using UTF-32.
+   *
+   *   TT_APPLE_ID_VARIANT_SELECTOR ::
+   *     From Adobe, not Apple.  Not a normal cmap.  Specifies variations
+   *     on a real cmap.
    */
 
-#define TT_APPLE_ID_DEFAULT      0 /* Unicode 1.0 */
-#define TT_APPLE_ID_UNICODE_1_1  1 /* specify Hangul at U+34xx */
-#define TT_APPLE_ID_ISO_10646    2 /* deprecated */
-#define TT_APPLE_ID_UNICODE_2_0  3 /* or later */
-#define TT_APPLE_ID_UNICODE_32   4 /* 2.0 or later, full repertoire */
+#define TT_APPLE_ID_DEFAULT           0 /* Unicode 1.0 */
+#define TT_APPLE_ID_UNICODE_1_1       1 /* specify Hangul at U+34xx */
+#define TT_APPLE_ID_ISO_10646         2 /* deprecated */
+#define TT_APPLE_ID_UNICODE_2_0       3 /* or later */
+#define TT_APPLE_ID_UNICODE_32        4 /* 2.0 or later, full repertoire */
+#define TT_APPLE_ID_VARIANT_SELECTOR  5 /* variation selector data */
 
 
   /***********************************************************************
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -967,6 +967,45 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
+  /*    find_variant_selector_charmap                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function finds the variant selector charmap, if there is one. */
+  /*    There can only be one (platform=0, specific=5, format=14).         */
+  /*                                                                       */
+  static FT_CharMap
+  find_variant_selector_charmap( FT_Face  face )
+  {
+    FT_CharMap*  first;
+    FT_CharMap*  end;
+    FT_CharMap*  cur;
+
+
+    /* caller should have already checked that `face' is valid */
+    FT_ASSERT( face );
+
+    first = face->charmaps;
+
+    if ( !first )
+      return NULL;
+
+    end = first + face->num_charmaps;  /* points after the last one */
+
+    for ( cur = first; cur < end; ++cur )
+    {
+      if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE    &&
+           cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
+           FT_Get_CMap_Format( cur[0] ) == 14                  )
+        return cur[0];
+    }
+
+    return NULL;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
   /*    open_face                                                          */
   /*                                                                       */
   /* <Description>                                                         */
@@ -2631,6 +2670,8 @@
     cur = face->charmaps;
     if ( !cur )
       return FT_Err_Invalid_CharMap_Handle;
+    if ( FT_Get_CMap_Format( charmap ) == 14 )
+      return FT_Err_Invalid_Argument;
 
     limit = cur + face->num_charmaps;
 
@@ -2844,6 +2885,149 @@
 
     if ( agindex )
       *agindex = gindex;
+
+    return result;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_UInt )
+  FT_Get_Char_Variant_Index( FT_Face   face,
+                             FT_ULong  charcode,
+                             FT_ULong  variantSelector )
+  {
+    FT_UInt  result = 0;
+
+
+    if ( face && face->charmap &&
+        face->charmap->encoding == FT_ENCODING_UNICODE )
+    {
+      FT_CharMap  charmap = find_variant_selector_charmap( face );
+      FT_CMap     ucmap = FT_CMAP( face->charmap );
+
+
+      if ( charmap != NULL )
+      {
+        FT_CMap  vcmap = FT_CMAP( charmap );
+
+
+        result = vcmap->clazz->char_var_index( vcmap, ucmap, charcode,
+                                               variantSelector );
+      }
+    }
+
+    return result;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Int )
+  FT_Get_Char_Variant_IsDefault( FT_Face   face,
+                                 FT_ULong  charcode,
+                                 FT_ULong  variantSelector )
+  {
+    FT_Int  result = -1;
+
+
+    if ( face )
+    {
+      FT_CharMap  charmap = find_variant_selector_charmap( face );
+
+
+      if ( charmap != NULL )
+      {
+        FT_CMap  vcmap = FT_CMAP( charmap );
+
+
+        result = vcmap->clazz->char_var_default( vcmap, charcode,
+                                                 variantSelector );
+      }
+    }
+
+    return result;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_UInt32* )
+  FT_Get_Variant_Selectors( FT_Face  face )
+  {
+    FT_UInt32  *result = NULL;
+
+
+    if ( face )
+    {
+      FT_CharMap  charmap = find_variant_selector_charmap( face );
+
+
+      if ( charmap != NULL )
+      {
+        FT_CMap    vcmap  = FT_CMAP( charmap );
+        FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+        result = vcmap->clazz->variant_list( vcmap, memory );
+      }
+    }
+
+    return result;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_UInt32* )
+  FT_Get_Variants_Of_Char( FT_Face   face,
+                           FT_ULong  charcode )
+  {
+    FT_UInt32  *result = NULL;
+
+
+    if ( face )
+    {
+      FT_CharMap  charmap = find_variant_selector_charmap( face );
+
+
+      if ( charmap != NULL )
+      {
+        FT_CMap    vcmap  = FT_CMAP( charmap );
+        FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+        result = vcmap->clazz->charvariant_list( vcmap, memory, charcode );
+      }
+    }
+    return result;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_UInt32* )
+  FT_Get_Chars_Of_Variant( FT_Face   face,
+                           FT_ULong  variantSelector )
+  {
+    FT_UInt32  *result = NULL;
+
+
+    if ( face )
+    {
+      FT_CharMap  charmap = find_variant_selector_charmap( face );
+
+
+      if ( charmap != NULL )
+      {
+        FT_CMap    vcmap  = FT_CMAP( charmap );
+        FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+        result = vcmap->clazz->variantchar_list( vcmap, memory,
+                                                 variantSelector );
+      }
+    }
 
     return result;
   }
--- a/src/bdf/bdfdrivr.c
+++ b/src/bdf/bdfdrivr.c
@@ -181,7 +181,9 @@
     bdf_cmap_init,
     bdf_cmap_done,
     bdf_cmap_char_index,
-    bdf_cmap_char_next
+    bdf_cmap_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
--- a/src/cff/cffcmap.c
+++ b/src/cff/cffcmap.c
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    CFF character mapping table (cmap) support (body).                   */
 /*                                                                         */
-/*  Copyright 2002, 2003, 2004, 2005, 2006 by                              */
+/*  Copyright 2002, 2003, 2004, 2005, 2006, 2007 by                        */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -107,7 +107,9 @@
     (FT_CMap_InitFunc)     cff_cmap_encoding_init,
     (FT_CMap_DoneFunc)     cff_cmap_encoding_done,
     (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index,
-    (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next
+    (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
@@ -213,7 +215,9 @@
     (FT_CMap_InitFunc)     cff_cmap_unicode_init,
     (FT_CMap_DoneFunc)     cff_cmap_unicode_done,
     (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index,
-    (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next
+    (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
--- a/src/pcf/pcfdrivr.c
+++ b/src/pcf/pcfdrivr.c
@@ -2,7 +2,7 @@
 
     FreeType font driver for pcf files
 
-    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 by
+    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006, 2007 by
     Francesco Zappa Nardelli
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -187,7 +187,9 @@
     pcf_cmap_init,
     pcf_cmap_done,
     pcf_cmap_char_index,
-    pcf_cmap_char_next
+    pcf_cmap_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
--- a/src/pfr/pfrcmap.c
+++ b/src/pfr/pfrcmap.c
@@ -158,7 +158,9 @@
     (FT_CMap_InitFunc)     pfr_cmap_init,
     (FT_CMap_DoneFunc)     pfr_cmap_done,
     (FT_CMap_CharIndexFunc)pfr_cmap_char_index,
-    (FT_CMap_CharNextFunc) pfr_cmap_char_next
+    (FT_CMap_CharNextFunc) pfr_cmap_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
--- a/src/psaux/t1cmap.c
+++ b/src/psaux/t1cmap.c
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Type 1 character map support (body).                                 */
 /*                                                                         */
-/*  Copyright 2002, 2003, 2006 by                                          */
+/*  Copyright 2002, 2003, 2006, 2007 by                                    */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -135,7 +135,9 @@
     (FT_CMap_InitFunc)     t1_cmap_standard_init,
     (FT_CMap_DoneFunc)     t1_cmap_std_done,
     (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
-    (FT_CMap_CharNextFunc) t1_cmap_std_char_next
+    (FT_CMap_CharNextFunc) t1_cmap_std_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
@@ -154,7 +156,9 @@
     (FT_CMap_InitFunc)     t1_cmap_expert_init,
     (FT_CMap_DoneFunc)     t1_cmap_std_done,
     (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
-    (FT_CMap_CharNextFunc) t1_cmap_std_char_next
+    (FT_CMap_CharNextFunc) t1_cmap_std_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
@@ -245,7 +249,9 @@
     (FT_CMap_InitFunc)     t1_cmap_custom_init,
     (FT_CMap_DoneFunc)     t1_cmap_custom_done,
     (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index,
-    (FT_CMap_CharNextFunc) t1_cmap_custom_char_next
+    (FT_CMap_CharNextFunc) t1_cmap_custom_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
@@ -326,7 +332,9 @@
     (FT_CMap_InitFunc)     t1_cmap_unicode_init,
     (FT_CMap_DoneFunc)     t1_cmap_unicode_done,
     (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index,
-    (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next
+    (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
 
--- a/src/sfnt/ttcmap.c
+++ b/src/sfnt/ttcmap.c
@@ -39,11 +39,13 @@
 
 #define TT_PEEK_SHORT   FT_PEEK_SHORT
 #define TT_PEEK_USHORT  FT_PEEK_USHORT
+#define TT_PEEK_UINT24  FT_PEEK_UOFF3
 #define TT_PEEK_LONG    FT_PEEK_LONG
 #define TT_PEEK_ULONG   FT_PEEK_ULONG
 
 #define TT_NEXT_SHORT   FT_NEXT_SHORT
 #define TT_NEXT_USHORT  FT_NEXT_USHORT
+#define TT_NEXT_UINT24  FT_NEXT_UOFF3
 #define TT_NEXT_LONG    FT_NEXT_LONG
 #define TT_NEXT_ULONG   FT_NEXT_ULONG
 
@@ -171,7 +173,9 @@
       (FT_CMap_InitFunc)     tt_cmap_init,
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap0_char_index,
-      (FT_CMap_CharNextFunc) tt_cmap0_char_next
+      (FT_CMap_CharNextFunc) tt_cmap0_char_next,
+
+      NULL, NULL, NULL, NULL, NULL
     },
     0,
     (TT_CMap_ValidateFunc)   tt_cmap0_validate,
@@ -544,7 +548,9 @@
       (FT_CMap_InitFunc)     tt_cmap_init,
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap2_char_index,
-      (FT_CMap_CharNextFunc) tt_cmap2_char_next
+      (FT_CMap_CharNextFunc) tt_cmap2_char_next,
+
+      NULL, NULL, NULL, NULL, NULL
     },
     2,
     (TT_CMap_ValidateFunc)   tt_cmap2_validate,
@@ -1320,7 +1326,9 @@
       (FT_CMap_InitFunc)     tt_cmap4_init,
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
-      (FT_CMap_CharNextFunc) tt_cmap4_char_next
+      (FT_CMap_CharNextFunc) tt_cmap4_char_next,
+
+      NULL, NULL, NULL, NULL, NULL
     },
     4,
     (TT_CMap_ValidateFunc)   tt_cmap4_validate,
@@ -1481,7 +1489,9 @@
       (FT_CMap_InitFunc)     tt_cmap_init,
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap6_char_index,
-      (FT_CMap_CharNextFunc) tt_cmap6_char_next
+      (FT_CMap_CharNextFunc) tt_cmap6_char_next,
+
+      NULL, NULL, NULL, NULL, NULL
     },
     6,
     (TT_CMap_ValidateFunc)   tt_cmap6_validate,
@@ -1735,7 +1745,9 @@
       (FT_CMap_InitFunc)     tt_cmap_init,
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap8_char_index,
-      (FT_CMap_CharNextFunc) tt_cmap8_char_next
+      (FT_CMap_CharNextFunc) tt_cmap8_char_next,
+
+      NULL, NULL, NULL, NULL, NULL
     },
     8,
     (TT_CMap_ValidateFunc)   tt_cmap8_validate,
@@ -1884,7 +1896,9 @@
       (FT_CMap_InitFunc)     tt_cmap_init,
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap10_char_index,
-      (FT_CMap_CharNextFunc) tt_cmap10_char_next
+      (FT_CMap_CharNextFunc) tt_cmap10_char_next,
+
+      NULL, NULL, NULL, NULL, NULL
     },
     10,
     (TT_CMap_ValidateFunc)   tt_cmap10_validate,
@@ -2201,7 +2215,9 @@
       (FT_CMap_InitFunc)     tt_cmap12_init,
       (FT_CMap_DoneFunc)     NULL,
       (FT_CMap_CharIndexFunc)tt_cmap12_char_index,
-      (FT_CMap_CharNextFunc) tt_cmap12_char_next
+      (FT_CMap_CharNextFunc) tt_cmap12_char_next,
+
+      NULL, NULL, NULL, NULL, NULL
     },
     12,
     (TT_CMap_ValidateFunc)   tt_cmap12_validate,
@@ -2208,10 +2224,703 @@
     (TT_CMap_Info_GetFunc)   tt_cmap12_get_info
   };
 
-
 #endif /* TT_CONFIG_CMAP_FORMAT_12 */
 
 
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           FORMAT 14                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME         OFFSET  TYPE    DESCRIPTION                            */
+  /*                                                                       */
+  /*   format         0     USHORT  must be 14                             */
+  /*   length         2     ULONG   table length in bytes                  */
+  /*   numSelector    6     ULONG   number of variation sel. records       */
+  /*                                                                       */
+  /* Followed by numSelector records, each of which looks like             */
+  /*                                                                       */
+  /*   varSelector    0     UINT24  Unicode codepoint of sel.              */
+  /*   defaultOff     3     ULONG   offset to a default UVS table          */
+  /*                                describing any variants to be found in */
+  /*                                the normal Unicode subtable.           */
+  /*   nonDefOff      7     ULONG   offset to a non-default UVS table      */
+  /*                                describing any variants not in the     */
+  /*                                standard cmap, with GIDs here          */
+  /* (either offset may be 0 NULL)                                         */
+  /*                                                                       */
+  /* Selectors are sorted by code point.                                   */
+  /*                                                                       */
+  /* A default Unicode Variation Selector (UVS) subtable is just a list of */
+  /* ranges of code points which are to be found in the standard cmap.  No */
+  /* glyph IDs (GIDs) here.                                                */
+  /*                                                                       */
+  /*   numRanges      0     ULONG   number of ranges following             */
+  /*                                                                       */
+  /* A range looks like                                                    */
+  /*                                                                       */
+  /*   uniStart       0     UINT24  code point of the first character in   */
+  /*                                this range                             */
+  /*   additionalCnt  3     UBYTE   count of additional characters in this */
+  /*                                range (zero means a range of a single  */
+  /*                                character)                             */
+  /*                                                                       */
+  /* Ranges are sorted by `uniStart'.                                      */
+  /*                                                                       */
+  /* A non-default Unicode Variation Selector (UVS) subtable is a list of  */
+  /* mappings from codepoint to GID.                                       */
+  /*                                                                       */
+  /*   numMappings    0     ULONG   number of mappings                     */
+  /*                                                                       */
+  /* A range looks like                                                    */
+  /*                                                                       */
+  /*   uniStart       0     UINT24  code point of the first character in   */
+  /*                                this range                             */
+  /*   GID            3     USHORT  and its GID                            */
+  /*                                                                       */
+  /* Ranges are sorted by `uniStart'.                                      */
+  
+#ifdef TT_CONFIG_CMAP_FORMAT_14
+
+  typedef struct  TT_CMap14Rec_
+  {
+    TT_CMapRec  cmap;
+    FT_ULong    num_selectors;
+
+  } TT_CMap14Rec, *TT_CMap14;
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  tt_cmap14_init( TT_CMap14  cmap,
+                  FT_Byte*   table )
+  {
+    cmap->cmap.data = table;
+
+    table               += 6;
+    cmap->num_selectors = FT_PEEK_ULONG( table );
+
+    return SFNT_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  tt_cmap14_validate( FT_Byte*      table,
+                      FT_Validator  valid )
+  {
+    FT_Byte*  p             = table + 2;
+    FT_ULong  length        = TT_NEXT_ULONG( p );
+    FT_ULong  num_selectors = TT_NEXT_ULONG( p );
+
+
+    if ( table + length > valid->limit || length < 10 + 11 * num_selectors )
+      FT_INVALID_TOO_SHORT;
+
+    /* check selectors, they must be in increasing order */
+    {
+      FT_ULong  n, varSel, defOff, nondefOff, last = 0;
+
+
+      for ( n = 0; n < num_selectors; n++ )
+      {
+        varSel    = TT_NEXT_UINT24( p );
+        defOff    = TT_NEXT_ULONG( p );
+        nondefOff = TT_NEXT_ULONG( p );
+
+        if ( defOff >= length || nondefOff >= length )
+          FT_INVALID_TOO_SHORT;
+
+        if ( n > 0 && varSel <= last )
+          FT_INVALID_DATA;
+        last = varSel;
+
+        /* check the default table (these glyphs should be reached     */
+        /* through the normal Unicode cmap, no GIDs, just check order) */
+        if ( defOff != 0 )
+        {
+          FT_Byte*  defp      = table + defOff;
+          FT_ULong  numRanges = TT_NEXT_ULONG( defp );
+          FT_ULong  i, base, cnt;
+
+
+          for ( i = 0; i < numRanges; ++i )
+          {
+            base = TT_NEXT_UINT24( defp );
+            cnt  = FT_NEXT_BYTE( defp );
+
+            if ( base + cnt >= 0x110000UL )              /* end of Unicode */
+              FT_INVALID_DATA;
+
+            if ( i > 0 && base <= last )
+              FT_INVALID_DATA;
+            last = base + cnt;
+          }
+        }
+
+        /* and the non-default table (these glyphs are specified here) */
+        if ( nondefOff != 0 ) {
+          FT_Byte*  ndp         = table + nondefOff;
+          FT_ULong  numMappings = TT_NEXT_ULONG( ndp );
+          FT_ULong  i, uni, gid;
+
+
+          for ( i = 0; i < numMappings; ++i )
+          {
+            uni = TT_NEXT_UINT24( ndp );
+            gid = TT_NEXT_USHORT( ndp );
+
+            if ( uni >= 0x110000UL )                     /* end of Unicode */
+              FT_INVALID_DATA;
+
+            if ( i > 0 && uni <= last )
+              FT_INVALID_DATA;
+            last = uni;
+
+            if ( valid->level >= FT_VALIDATE_TIGHT    &&
+                 gid >= TT_VALID_GLYPH_COUNT( valid ) )
+              FT_INVALID_GLYPH_ID;
+          }
+        }
+      }
+    }
+
+    return SFNT_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap14_char_index( TT_CMap    cmap,
+                        FT_UInt32  char_code )
+  {
+    FT_UNUSED( cmap );
+    FT_UNUSED( char_code );
+
+    /* This can't happen */
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap14_char_next( TT_CMap     cmap,
+                       FT_UInt32  *pchar_code )
+  {
+    FT_UNUSED( cmap );
+
+    /* This can't happen */
+    *pchar_code = 0;
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  tt_cmap14_get_info( TT_CMap       cmap,
+                      TT_CMapInfo  *cmap_info )
+  {
+    FT_UNUSED( cmap );
+
+    cmap_info->format = 14;
+    /* subtable 14 does not define a language field */
+    cmap_info->language = 0xFFFFFFFFUL;
+
+    return SFNT_Err_Ok;
+  }
+
+
+  static FT_UInt
+  tt_cmap14_char_map_def_binary( FT_Byte    *base,
+                                 FT_UInt32   char_code )
+  {
+    FT_Byte*   p;
+    FT_UInt32  numRanges = TT_PEEK_ULONG( base );
+    FT_UInt32  start, cnt;
+    FT_UInt32  max, min, mid;
+
+
+    if ( !numRanges )
+      return FALSE;
+
+    /* make compiler happy */
+    mid = numRanges;
+
+    min = 0;
+    max = numRanges;
+
+    /* binary search */
+    while ( min < max )
+    {
+      mid = ( min + max ) >> 1;
+      p   = base + 4 + 4 * mid;
+
+      start = TT_NEXT_UINT24( p );
+      cnt   = FT_NEXT_BYTE( p );
+
+      if ( char_code < start )
+        max = mid;
+      else if ( char_code > start+cnt )
+        min = mid + 1;
+      else
+        return TRUE;
+    }
+
+    return FALSE;
+  }
+
+
+  static FT_UInt
+  tt_cmap14_char_map_nondef_binary( FT_Byte    *base,
+                                    FT_UInt32   char_code )
+  {
+    FT_Byte*   p;
+    FT_UInt32  numMappings = TT_PEEK_ULONG( base );
+    FT_UInt32  uni, gid;
+    FT_UInt32  max, min, mid;
+
+
+    if ( !numMappings )
+      return 0;
+
+    /* make compiler happy */
+    mid = numMappings;
+
+    min = 0;
+    max = numMappings;
+
+    /* binary search */
+    while ( min < max )
+    {
+      mid = ( min + max ) >> 1;
+      p   = base + 4 + 5 * mid;
+
+      uni = TT_NEXT_UINT24( p );
+      gid = TT_NEXT_USHORT( p );
+
+      if ( char_code < uni )
+        max = mid;
+      else if ( char_code > uni )
+        min = mid + 1;
+      else
+        return gid;
+    }
+
+    return 0;
+  }
+
+
+  static FT_Byte*
+  tt_cmap14_find_variant( FT_Byte    *base,
+                          FT_UInt32   variantCode )
+  {
+    FT_Byte*   p;
+    FT_UInt32  numVar = TT_PEEK_ULONG( base );
+    FT_ULong   varSel;
+    FT_UInt32  max, min, mid;
+
+
+    if ( !numVar )
+      return NULL;
+
+    /* make compiler happy */
+    mid = numVar;
+
+    min = 0;
+    max = numVar;
+
+    /* binary search */
+    while ( min < max )
+    {
+      mid = ( min + max ) >> 1;
+      p   = base + 4 + 11 * mid;
+
+      varSel = TT_NEXT_UINT24( p );
+
+      if ( variantCode < varSel )
+        max = mid;
+      else if ( variantCode > varSel )
+        min = mid + 1;
+      else
+        return p;
+    }
+
+    return NULL;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap14_char_var_index( TT_CMap   cmap,
+                            TT_CMap   ucmap,
+                            FT_ULong  charcode,
+                            FT_ULong  variantSelector)
+  {
+    FT_Byte   *p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+    FT_ULong   defOff;
+    FT_ULong   nondefOff;
+
+
+    if ( !p )
+      return 0;
+
+    defOff    = TT_NEXT_ULONG( p );
+    nondefOff = TT_NEXT_ULONG( p );
+
+    if ( defOff != 0                                                    &&
+         tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+    {
+      /* This is the default variant of this charcode.  GID not stored */
+      /* here; stored in the normal Unicode charmap instead.           */
+      return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode );
+    }
+
+    if ( nondefOff != 0 )
+      return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+                                               charcode );
+
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Int )
+  tt_cmap14_char_var_isdefault( TT_CMap   cmap,
+                                FT_ULong  charcode,
+                                FT_ULong  variantSelector )
+  {
+    FT_Byte   *p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+    FT_ULong   defOff;
+    FT_ULong   nondefOff;
+
+
+    if ( !p )
+      return -1;
+
+    defOff    = TT_NEXT_ULONG( p );
+    nondefOff = TT_NEXT_ULONG( p );
+
+    if ( defOff != 0                                                    &&
+         tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+      return 1;
+
+    if ( nondefOff != 0                                            &&
+         tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+                                           charcode ) != 0         )
+      return 0;
+
+    return -1;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt32 * )
+  tt_cmap14_variants( TT_CMap    cmap,
+                      FT_Memory  memory )
+  {
+    TT_CMap14   cmap14 = (TT_CMap14)cmap;
+    FT_Byte*    p      = cmap->data + 10;
+    FT_UInt32*  ret;
+    FT_UInt     i;
+    FT_Error    error;
+
+
+    if ( FT_ALLOC( ret,
+                   ( cmap14->num_selectors + 1 ) * sizeof ( FT_UInt32 ) ) )
+      return NULL;
+
+    for ( i = 0; i < cmap14->num_selectors; ++i )
+    {
+      ret[i] = TT_NEXT_UINT24( p );
+      p += 8;
+    }
+    ret[i] = 0;
+
+    return ret;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt32 * )
+  tt_cmap14_char_variants( TT_CMap    cmap,
+                           FT_Memory  memory,
+                           FT_ULong   charCode )
+  {
+    TT_CMap14   cmap14 = (TT_CMap14)  cmap;
+    FT_Byte*    p = cmap->data + 10;
+    FT_UInt32  *ret;
+    FT_UInt     i, j;
+    FT_UInt32   varSel;
+    FT_ULong    defOff;
+    FT_ULong    nondefOff;
+    FT_Error    error;
+
+
+    if ( FT_ALLOC( ret,
+                   ( cmap14->num_selectors + 1 ) * sizeof ( FT_UInt32 ) ) )
+      return NULL;
+
+    for ( i = j = 0; i < cmap14->num_selectors; ++i )
+    {
+      varSel    = TT_NEXT_UINT24( p );
+      defOff    = TT_NEXT_ULONG( p );
+      nondefOff = TT_NEXT_ULONG( p );
+      if ( ( defOff != 0                                               &&
+             tt_cmap14_char_map_def_binary( cmap->data + defOff,
+                                            charCode )                 ) ||
+           ( nondefOff != 0                                            &&
+             tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+                                               charCode ) != 0         ) )
+        ret[j++] = varSel;
+    }
+    ret[j] = 0;
+
+    return ret;
+  }
+
+
+  static FT_UInt
+  tt_cmap14_def_char_count( FT_Byte  *p )
+  {
+    FT_UInt32  numRanges;
+    FT_UInt    tot;
+    FT_UInt    cnt;
+    FT_UInt    i;
+
+
+    numRanges = TT_NEXT_ULONG( p );
+
+    tot = 0;
+    for ( i = 0; i < numRanges; ++i )
+    {
+      p += 3;
+      cnt = FT_NEXT_BYTE( p );
+      tot += cnt + 1;
+    }
+
+    return tot;
+  }
+
+
+  static FT_UInt*
+  tt_cmap14_get_def_chars( FT_Byte    *p,
+                           FT_Memory   memory )
+  {
+    FT_UInt32   numRanges;
+    FT_UInt     uni;
+    FT_UInt     cnt;
+    FT_UInt     i, j, k;
+    FT_UInt32  *ret;
+    FT_Error    error;
+
+
+    cnt       = tt_cmap14_def_char_count( p );
+    numRanges = TT_NEXT_ULONG( p );
+
+    if ( FT_ALLOC( ret , ( cnt + 1 ) * sizeof ( FT_UInt32 ) ) )
+      return NULL;
+
+    for ( i = j = 0; i < numRanges; ++i )
+    {
+      uni = TT_NEXT_UINT24( p );
+      cnt = FT_NEXT_BYTE( p );
+
+      for ( k = 0; k <= cnt; ++k )
+        ret[j++] = uni + k;
+    }
+    ret[j] = 0;
+
+    return ret;
+  }
+    
+
+  static FT_UInt*
+  tt_cmap14_get_nondef_chars( FT_Byte    *p,
+                              FT_Memory   memory )
+  {
+    FT_UInt32   numMappings;
+    FT_UInt     i;
+    FT_UInt32  *ret;
+    FT_Error    error;
+
+
+    numMappings = TT_NEXT_ULONG( p );
+
+    if ( FT_ALLOC( ret, ( numMappings + 1 ) * sizeof ( FT_UInt32 ) ) )
+      return NULL;
+
+    for ( i = 0; i < numMappings; ++i )
+    {
+      ret[i] = TT_NEXT_UINT24( p );
+      p += 2;
+    }
+    ret[i] = 0;
+
+    return( ret );
+  }
+  
+
+  FT_CALLBACK_DEF( FT_UInt32 * )
+  tt_cmap14_variant_chars( TT_CMap    cmap,
+                           FT_Memory  memory,
+                           FT_ULong   variantSelector )
+  {
+    FT_Byte    *p  = tt_cmap14_find_variant( cmap->data + 6,
+                                             variantSelector );
+    FT_UInt32  *ret;
+    FT_Int      i;
+    FT_ULong    defOff;
+    FT_ULong    nondefOff;
+
+
+    if ( !p )
+      return NULL;
+
+    defOff    = TT_NEXT_ULONG( p );
+    nondefOff = TT_NEXT_ULONG( p );
+
+    if ( defOff == 0 && nondefOff == 0 )
+      return NULL;
+
+    if ( defOff == 0 )
+      return tt_cmap14_get_nondef_chars( cmap->data + nondefOff, memory );
+    else if ( nondefOff == 0 )
+      return tt_cmap14_get_def_chars( cmap->data + defOff, memory );
+    else
+    {
+      /* Both a default and a non-default glyph set?  That's probably not */
+      /* good font design, but the spec allows for it...                  */
+      FT_UInt32  numRanges;
+      FT_UInt32  numMappings;
+      FT_UInt32  duni;
+      FT_UInt32  dcnt;
+      FT_UInt32  nuni;
+      FT_Byte*   dp;
+      FT_UInt    di, ni, k;
+      FT_Error   error;
+
+
+      p  = cmap->data + nondefOff;
+      dp = cmap->data + defOff;
+
+      numMappings = TT_NEXT_ULONG( p );
+      dcnt        = tt_cmap14_def_char_count( dp );
+      numRanges   = TT_NEXT_ULONG( dp );
+
+      if ( numMappings == 0 )
+        return tt_cmap14_get_def_chars( cmap->data + defOff, memory );
+      if ( dcnt == 0 )
+        return tt_cmap14_get_nondef_chars( cmap->data + nondefOff, memory );
+
+      if ( FT_ALLOC( ret,
+           ( dcnt + numMappings + 1 ) * sizeof ( FT_UInt32 ) ) )
+        return NULL;
+
+      duni = TT_NEXT_UINT24( dp );
+      dcnt = FT_NEXT_BYTE( dp );
+      di   = 1;
+      nuni = TT_NEXT_UINT24( p );
+      p   += 2;
+      ni   = 1;
+      i    = 0;
+
+      for ( ;; )
+      {
+        if ( nuni > duni + dcnt )
+        {
+          for ( k = 0; k <= dcnt; ++k )
+            ret[i++] = duni + k;
+
+          ++di;
+
+          if ( di <= numRanges )
+          {
+            duni = TT_NEXT_UINT24( dp );
+            dcnt = FT_NEXT_BYTE( dp );
+          }
+          else
+            break;
+        }
+        else
+        {
+          if ( nuni < duni )
+            ret[i++] = nuni;
+          /* If it is within the default range then ignore it -- */
+          /* that should not have happened                       */
+          ++ni;
+          if ( ni <= numMappings )
+          {
+            nuni = TT_NEXT_UINT24( p );
+            p += 2;
+          }
+          else
+            break;
+        }
+      }
+
+      if ( ni <= numMappings )
+      {
+        /* If we get here then we have run out of all default ranges.   */
+        /* We have read one non-default mapping which we haven't stored */
+        /* and there may be others that need to be read.                */
+        ret[i++] = nuni;
+        while ( ni < numMappings )
+        {
+          ret[i++] = TT_NEXT_UINT24( p );
+          p += 2;
+          ++ni;
+        }
+      }
+      else if ( di < numRanges )
+      {
+        /* If we get here then we have run out of all non-default     */
+        /* mappings.  We have read one default range which we haven't */
+        /* stored and there may be others that need to be read.       */
+        for ( k = 0; k <= dcnt; ++k )
+          ret[i++] = duni + k;
+
+        while ( di < numRanges )
+        {
+          duni = TT_NEXT_UINT24( dp );
+          dcnt = FT_NEXT_BYTE( dp );
+
+          for ( k = 0; k <= dcnt; ++k )
+            ret[i++] = duni + k;
+          ++di;
+        }
+      }
+
+      ret[i] = 0;
+
+      return ret;
+    }
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap14_class_rec =
+  {
+    {
+      sizeof ( TT_CMap14Rec ),
+
+      (FT_CMap_InitFunc)     tt_cmap14_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap14_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap14_char_next,
+      /* Format 14 extension functions */
+      (FT_CMap_CharVarIndexFunc)    tt_cmap14_char_var_index,
+      (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault,
+      (FT_CMap_VariantListFunc)     tt_cmap14_variants,
+      (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants,
+      (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars
+    },
+    14,
+    (TT_CMap_ValidateFunc)tt_cmap14_validate,
+    (TT_CMap_Info_GetFunc)tt_cmap14_get_info
+  };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_0 */
+
+
   static const TT_CMap_Class  tt_cmap_classes[] =
   {
 #ifdef TT_CONFIG_CMAP_FORMAT_0
@@ -2242,6 +2951,10 @@
     &tt_cmap12_class_rec,
 #endif
 
+#ifdef TT_CONFIG_CMAP_FORMAT_14
+    &tt_cmap14_class_rec,
+#endif
+
     NULL,
   };
 
@@ -2318,6 +3031,10 @@
               FT_CMap  ttcmap;
 
 
+              /* It might make sense to store the single variation selector */
+              /* cmap somewhere special.  But it would have to be in the    */
+              /* public FT_FaceRec, and we can't change that.               */
+
               if ( !FT_CMap_New( (FT_CMap_Class)clazz,
                                  cmap, &charmap, &ttcmap ) )
               {
@@ -2333,6 +3050,12 @@
             }
             break;
           }
+        }
+
+        if ( *pclazz == NULL )
+        {
+          FT_ERROR(( "tt_face_build_cmaps:" ));
+          FT_ERROR(( " unsupported cmap sub-table ignored!\n" ));
         }
       }
     }
--- a/src/winfonts/winfnt.c
+++ b/src/winfonts/winfnt.c
@@ -652,7 +652,9 @@
     (FT_CMap_InitFunc)     fnt_cmap_init,
     (FT_CMap_DoneFunc)     NULL,
     (FT_CMap_CharIndexFunc)fnt_cmap_char_index,
-    (FT_CMap_CharNextFunc) fnt_cmap_char_next
+    (FT_CMap_CharNextFunc) fnt_cmap_char_next,
+
+    NULL, NULL, NULL, NULL, NULL
   };
 
   static FT_CMap_Class const  fnt_cmap_class = &fnt_cmap_class_rec;