[DO NOT MERGE] Update FreeType to 2.6.2 + update from 2.6.0

1. Update to a512b0fe7a (several patches past 2.6.2). 
   Major changes include
   - stem-darkening is OFF for CFF fonts by default
   - general code tightening
   - header file location is back to include/freetype (used be include/)
2. A bit more details are added to README.android for the reference.

This CL requires a pdfium change (the way it includes FT header
files : https://googleplex-android-review.git.corp.google.com/#/c/846889

An AOSP master CL 
(https://android-review.googlesource.com/#/c/196504/) is ported
to mnc-dev.

Bug: 24296662

Change-Id: Iec6784838d89098f332e6d1ed79663efd91a8441
Signed-off-by: Jungshik Shin <jungshik@google.com>
(cherry picked from commit 99748bb350b2a34821953d97ca4ca185ad2e6c08)
diff --git a/README.android b/README.android
index ed61907..c3139d5 100644
--- a/README.android
+++ b/README.android
@@ -1,4 +1,16 @@
-Freetype
+Name: FreeType
+Version: 2.6.2 + update
+Revision: a512b0fe7a8d9db0e5aa9c0a4db1e92cb861722d
 
-Not all modules in include/config/ftmodule.h are enabled.
-Some options in include/config/ftoption.h are enabled/disabled.
+Local modifications:
+
+1. Drop unused build files (Jamfiles, {module,rules}.mk) 
+2. Drop src directories for unused modules: 
+   bdf, cid, pcf, pfr, type1, type42, winfonts
+3. Drop src/{bzip2,tools,lzw,otvalid,gxvalid}
+4. Customize include/freetype/config/{ftmodule,ftoption}.h by applying
+   module_option.diff
+
+To faciliate an easier update, all the files in src/{base,autofit} are kept
+even if some of them are for dropped modules/options. Android.mk can be used
+to control exactly what's built.
diff --git a/include/config/ftconfig.h b/include/freetype/config/ftconfig.h
similarity index 99%
rename from include/config/ftconfig.h
rename to include/freetype/config/ftconfig.h
index 086db76..d4d7993 100644
--- a/include/config/ftconfig.h
+++ b/include/freetype/config/ftconfig.h
@@ -335,9 +335,9 @@
 #if ( __GNUC__ >= 2                         || \
       defined( __IBM__TYPEOF__ )            || \
       ( __SUNPRO_C >= 0x5110 && !__STDC__ ) )
-#define TYPEOF( type )  (__typeof__ (type))
+#define FT_TYPEOF( type )  (__typeof__ (type))
 #else
-#define TYPEOF( type )  /* empty */
+#define FT_TYPEOF( type )  /* empty */
 #endif
 
 
diff --git a/include/config/ftheader.h b/include/freetype/config/ftheader.h
similarity index 89%
rename from include/config/ftheader.h
rename to include/freetype/config/ftheader.h
index 4906bc1..55f833d 100644
--- a/include/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -107,7 +107,7 @@
    *
    */
 #ifndef FT_CONFIG_CONFIG_H
-#define FT_CONFIG_CONFIG_H  <config/ftconfig.h>
+#define FT_CONFIG_CONFIG_H  <freetype/config/ftconfig.h>
 #endif
 
 
@@ -122,7 +122,7 @@
    *
    */
 #ifndef FT_CONFIG_STANDARD_LIBRARY_H
-#define FT_CONFIG_STANDARD_LIBRARY_H  <config/ftstdlib.h>
+#define FT_CONFIG_STANDARD_LIBRARY_H  <freetype/config/ftstdlib.h>
 #endif
 
 
@@ -137,7 +137,7 @@
    *
    */
 #ifndef FT_CONFIG_OPTIONS_H
-#define FT_CONFIG_OPTIONS_H  <config/ftoption.h>
+#define FT_CONFIG_OPTIONS_H  <freetype/config/ftoption.h>
 #endif
 
 
@@ -153,7 +153,7 @@
    *
    */
 #ifndef FT_CONFIG_MODULES_H
-#define FT_CONFIG_MODULES_H  <config/ftmodule.h>
+#define FT_CONFIG_MODULES_H  <freetype/config/ftmodule.h>
 #endif
 
   /* */
@@ -170,7 +170,7 @@
    *   base FreeType~2 API.
    *
    */
-#define FT_FREETYPE_H  <freetype.h>
+#define FT_FREETYPE_H  <freetype/freetype.h>
 
 
   /*************************************************************************
@@ -185,7 +185,7 @@
    *   It is included by @FT_FREETYPE_H.
    *
    */
-#define FT_ERRORS_H  <fterrors.h>
+#define FT_ERRORS_H  <freetype/fterrors.h>
 
 
   /*************************************************************************
@@ -198,7 +198,7 @@
    *   list of FreeType~2 module error offsets (and messages).
    *
    */
-#define FT_MODULE_ERRORS_H  <ftmoderr.h>
+#define FT_MODULE_ERRORS_H  <freetype/ftmoderr.h>
 
 
   /*************************************************************************
@@ -214,7 +214,7 @@
    *   It is included by @FT_FREETYPE_H.
    *
    */
-#define FT_SYSTEM_H  <ftsystem.h>
+#define FT_SYSTEM_H  <freetype/ftsystem.h>
 
 
   /*************************************************************************
@@ -230,7 +230,7 @@
    *   It is included by @FT_FREETYPE_H.
    *
    */
-#define FT_IMAGE_H  <ftimage.h>
+#define FT_IMAGE_H  <freetype/ftimage.h>
 
 
   /*************************************************************************
@@ -245,7 +245,7 @@
    *   It is included by @FT_FREETYPE_H.
    *
    */
-#define FT_TYPES_H  <fttypes.h>
+#define FT_TYPES_H  <freetype/fttypes.h>
 
 
   /*************************************************************************
@@ -260,7 +260,7 @@
    *   (Most applications will never need to include this file.)
    *
    */
-#define FT_LIST_H  <ftlist.h>
+#define FT_LIST_H  <freetype/ftlist.h>
 
 
   /*************************************************************************
@@ -273,7 +273,7 @@
    *   scalable outline management API of FreeType~2.
    *
    */
-#define FT_OUTLINE_H  <ftoutln.h>
+#define FT_OUTLINE_H  <freetype/ftoutln.h>
 
 
   /*************************************************************************
@@ -286,7 +286,7 @@
    *   API which manages multiple @FT_Size objects per face.
    *
    */
-#define FT_SIZES_H  <ftsizes.h>
+#define FT_SIZES_H  <freetype/ftsizes.h>
 
 
   /*************************************************************************
@@ -299,7 +299,7 @@
    *   module management API of FreeType~2.
    *
    */
-#define FT_MODULE_H  <ftmodapi.h>
+#define FT_MODULE_H  <freetype/ftmodapi.h>
 
 
   /*************************************************************************
@@ -312,7 +312,7 @@
    *   renderer module management API of FreeType~2.
    *
    */
-#define FT_RENDER_H  <ftrender.h>
+#define FT_RENDER_H  <freetype/ftrender.h>
 
 
   /*************************************************************************
@@ -325,7 +325,7 @@
    *   structures and macros related to the auto-hinting module.
    *
    */
-#define FT_AUTOHINTER_H  <ftautoh.h>
+#define FT_AUTOHINTER_H  <freetype/ftautoh.h>
 
 
   /*************************************************************************
@@ -338,7 +338,7 @@
    *   structures and macros related to the CFF driver module.
    *
    */
-#define FT_CFF_DRIVER_H  <ftcffdrv.h>
+#define FT_CFF_DRIVER_H  <freetype/ftcffdrv.h>
 
 
   /*************************************************************************
@@ -351,7 +351,7 @@
    *   structures and macros related to the TrueType driver module.
    *
    */
-#define FT_TRUETYPE_DRIVER_H  <ftttdrv.h>
+#define FT_TRUETYPE_DRIVER_H  <freetype/ftttdrv.h>
 
 
   /*************************************************************************
@@ -364,7 +364,7 @@
    *   types and API specific to the Type~1 format.
    *
    */
-#define FT_TYPE1_TABLES_H  <t1tables.h>
+#define FT_TYPE1_TABLES_H  <freetype/t1tables.h>
 
 
   /*************************************************************************
@@ -379,7 +379,7 @@
    *   definitions, taken from the TrueType and OpenType specifications.
    *
    */
-#define FT_TRUETYPE_IDS_H  <ttnameid.h>
+#define FT_TRUETYPE_IDS_H  <freetype/ttnameid.h>
 
 
   /*************************************************************************
@@ -392,7 +392,7 @@
    *   types and API specific to the TrueType (as well as OpenType) format.
    *
    */
-#define FT_TRUETYPE_TABLES_H  <tttables.h>
+#define FT_TRUETYPE_TABLES_H  <freetype/tttables.h>
 
 
   /*************************************************************************
@@ -406,7 +406,7 @@
    *   SFNT-based font formats (i.e., TrueType and OpenType).
    *
    */
-#define FT_TRUETYPE_TAGS_H  <tttags.h>
+#define FT_TRUETYPE_TAGS_H  <freetype/tttags.h>
 
 
   /*************************************************************************
@@ -420,7 +420,7 @@
    *   face.
    *
    */
-#define FT_BDF_H  <ftbdf.h>
+#define FT_BDF_H  <freetype/ftbdf.h>
 
 
   /*************************************************************************
@@ -434,7 +434,7 @@
    *   face.
    *
    */
-#define FT_CID_H  <ftcid.h>
+#define FT_CID_H  <freetype/ftcid.h>
 
 
   /*************************************************************************
@@ -447,7 +447,7 @@
    *   definitions of an API which supports gzip-compressed files.
    *
    */
-#define FT_GZIP_H  <ftgzip.h>
+#define FT_GZIP_H  <freetype/ftgzip.h>
 
 
   /*************************************************************************
@@ -460,7 +460,7 @@
    *   definitions of an API which supports LZW-compressed files.
    *
    */
-#define FT_LZW_H  <ftlzw.h>
+#define FT_LZW_H  <freetype/ftlzw.h>
 
 
   /*************************************************************************
@@ -473,7 +473,7 @@
    *   definitions of an API which supports bzip2-compressed files.
    *
    */
-#define FT_BZIP2_H  <ftbzip2.h>
+#define FT_BZIP2_H  <freetype/ftbzip2.h>
 
 
   /*************************************************************************
@@ -486,7 +486,7 @@
    *   definitions of an API which supports Windows FNT files.
    *
    */
-#define FT_WINFONTS_H   <ftwinfnt.h>
+#define FT_WINFONTS_H   <freetype/ftwinfnt.h>
 
 
   /*************************************************************************
@@ -499,7 +499,7 @@
    *   API of the optional glyph management component.
    *
    */
-#define FT_GLYPH_H  <ftglyph.h>
+#define FT_GLYPH_H  <freetype/ftglyph.h>
 
 
   /*************************************************************************
@@ -512,7 +512,7 @@
    *   API of the optional bitmap conversion component.
    *
    */
-#define FT_BITMAP_H  <ftbitmap.h>
+#define FT_BITMAP_H  <freetype/ftbitmap.h>
 
 
   /*************************************************************************
@@ -525,7 +525,7 @@
    *   API of the optional exact bounding box computation routines.
    *
    */
-#define FT_BBOX_H  <ftbbox.h>
+#define FT_BBOX_H  <freetype/ftbbox.h>
 
 
   /*************************************************************************
@@ -538,7 +538,7 @@
    *   API of the optional FreeType~2 cache sub-system.
    *
    */
-#define FT_CACHE_H  <ftcache.h>
+#define FT_CACHE_H  <freetype/ftcache.h>
 
 
   /*************************************************************************
@@ -612,7 +612,7 @@
    *   compiled on the Mac (note that the base API still works though).
    *
    */
-#define FT_MAC_H  <ftmac.h>
+#define FT_MAC_H  <freetype/ftmac.h>
 
 
   /*************************************************************************
@@ -625,7 +625,7 @@
    *   optional multiple-masters management API of FreeType~2.
    *
    */
-#define FT_MULTIPLE_MASTERS_H  <ftmm.h>
+#define FT_MULTIPLE_MASTERS_H  <freetype/ftmm.h>
 
 
   /*************************************************************************
@@ -639,7 +639,7 @@
    *   SFNT-based font formats (i.e., TrueType and OpenType).
    *
    */
-#define FT_SFNT_NAMES_H  <ftsnames.h>
+#define FT_SFNT_NAMES_H  <freetype/ftsnames.h>
 
 
   /*************************************************************************
@@ -653,7 +653,7 @@
    *   GPOS, GSUB, JSTF).
    *
    */
-#define FT_OPENTYPE_VALIDATE_H  <ftotval.h>
+#define FT_OPENTYPE_VALIDATE_H  <freetype/ftotval.h>
 
 
   /*************************************************************************
@@ -667,7 +667,7 @@
    *   mort, morx, bsln, just, kern, opbd, trak, prop).
    *
    */
-#define FT_GX_VALIDATE_H  <ftgxval.h>
+#define FT_GX_VALIDATE_H  <freetype/ftgxval.h>
 
 
   /*************************************************************************
@@ -680,7 +680,7 @@
    *   FreeType~2 API which accesses PFR-specific data.
    *
    */
-#define FT_PFR_H  <ftpfr.h>
+#define FT_PFR_H  <freetype/ftpfr.h>
 
 
   /*************************************************************************
@@ -692,7 +692,7 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which provides functions to stroke outline paths.
    */
-#define FT_STROKER_H  <ftstroke.h>
+#define FT_STROKER_H  <freetype/ftstroke.h>
 
 
   /*************************************************************************
@@ -704,7 +704,7 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which performs artificial obliquing and emboldening.
    */
-#define FT_SYNTHESIS_H  <ftsynth.h>
+#define FT_SYNTHESIS_H  <freetype/ftsynth.h>
 
 
   /*************************************************************************
@@ -716,7 +716,7 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which provides functions specific to font formats.
    */
-#define FT_FONT_FORMATS_H  <ftfntfmt.h>
+#define FT_FONT_FORMATS_H  <freetype/ftfntfmt.h>
 
   /* deprecated */
 #define FT_XFREE86_H  FT_FONT_FORMATS_H
@@ -732,7 +732,7 @@
    *   FreeType~2 API which performs trigonometric computations (e.g.,
    *   cosines and arc tangents).
    */
-#define FT_TRIGONOMETRY_H  <fttrigon.h>
+#define FT_TRIGONOMETRY_H  <freetype/fttrigon.h>
 
 
   /*************************************************************************
@@ -744,7 +744,7 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which performs color filtering for subpixel rendering.
    */
-#define FT_LCD_FILTER_H  <ftlcdfil.h>
+#define FT_LCD_FILTER_H  <freetype/ftlcdfil.h>
 
 
   /*************************************************************************
@@ -756,7 +756,7 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which performs color filtering for subpixel rendering.
    */
-#define FT_UNPATENTED_HINTING_H  <ttunpat.h>
+#define FT_UNPATENTED_HINTING_H  <freetype/ttunpat.h>
 
 
   /*************************************************************************
@@ -768,7 +768,7 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which performs color filtering for subpixel rendering.
    */
-#define FT_INCREMENTAL_H  <ftincrem.h>
+#define FT_INCREMENTAL_H  <freetype/ftincrem.h>
 
 
   /*************************************************************************
@@ -780,7 +780,7 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which returns entries from the TrueType GASP table.
    */
-#define FT_GASP_H  <ftgasp.h>
+#define FT_GASP_H  <freetype/ftgasp.h>
 
 
   /*************************************************************************
@@ -792,30 +792,30 @@
    *   A macro used in #include statements to name the file containing the
    *   FreeType~2 API which returns individual and ranged glyph advances.
    */
-#define FT_ADVANCES_H  <ftadvanc.h>
+#define FT_ADVANCES_H  <freetype/ftadvanc.h>
 
 
   /* */
 
-#define FT_ERROR_DEFINITIONS_H  <fterrdef.h>
+#define FT_ERROR_DEFINITIONS_H  <freetype/fterrdef.h>
 
 
   /* The internals of the cache sub-system are no longer exposed.  We */
   /* default to FT_CACHE_H at the moment just in case, but we know of */
   /* no rogue client that uses them.                                  */
   /*                                                                  */
-#define FT_CACHE_MANAGER_H           <ftcache.h>
-#define FT_CACHE_INTERNAL_MRU_H      <ftcache.h>
-#define FT_CACHE_INTERNAL_MANAGER_H  <ftcache.h>
-#define FT_CACHE_INTERNAL_CACHE_H    <ftcache.h>
-#define FT_CACHE_INTERNAL_GLYPH_H    <ftcache.h>
-#define FT_CACHE_INTERNAL_IMAGE_H    <ftcache.h>
-#define FT_CACHE_INTERNAL_SBITS_H    <ftcache.h>
+#define FT_CACHE_MANAGER_H           <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_MRU_H      <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_MANAGER_H  <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_CACHE_H    <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_GLYPH_H    <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_IMAGE_H    <freetype/ftcache.h>
+#define FT_CACHE_INTERNAL_SBITS_H    <freetype/ftcache.h>
 
 
-#define FT_INCREMENTAL_H          <ftincrem.h>
+#define FT_INCREMENTAL_H          <freetype/ftincrem.h>
 
-#define FT_TRUETYPE_UNPATENTED_H  <ttunpat.h>
+#define FT_TRUETYPE_UNPATENTED_H  <freetype/ttunpat.h>
 
 
   /*
@@ -823,7 +823,7 @@
    * only when building the library.
    */
 #ifdef FT2_BUILD_LIBRARY
-#define  FT_INTERNAL_INTERNAL_H  <internal/internal.h>
+#define  FT_INTERNAL_INTERNAL_H  <freetype/internal/internal.h>
 #include FT_INTERNAL_INTERNAL_H
 #endif /* FT2_BUILD_LIBRARY */
 
diff --git a/include/config/ftmodule.h b/include/freetype/config/ftmodule.h
similarity index 100%
rename from include/config/ftmodule.h
rename to include/freetype/config/ftmodule.h
diff --git a/include/config/ftoption.h b/include/freetype/config/ftoption.h
similarity index 97%
rename from include/config/ftoption.h
rename to include/freetype/config/ftoption.h
index 6e8a528..3819586 100644
--- a/include/config/ftoption.h
+++ b/include/freetype/config/ftoption.h
@@ -38,9 +38,9 @@
   /*    library from a single source directory.                            */
   /*                                                                       */
   /*  - You can put a copy of this file in your build directory, more      */
-  /*    precisely in `$BUILD/config/ftoption.h', where `$BUILD' is the     */
-  /*    name of a directory that is included _before_ the FreeType include */
-  /*    path during compilation.                                           */
+  /*    precisely in `$BUILD/freetype/config/ftoption.h', where `$BUILD'   */
+  /*    is the name of a directory that is included _before_ the FreeType  */
+  /*    include path during compilation.                                   */
   /*                                                                       */
   /*    The default FreeType Makefiles and Jamfiles use the build          */
   /*    directory `builds/<system>' by default, but you can easily change  */
@@ -51,7 +51,7 @@
   /*    locate this file during the build.  For example,                   */
   /*                                                                       */
   /*      #define FT_CONFIG_OPTIONS_H  <myftoptions.h>                     */
-  /*      #include <config/ftheader.h>                                     */
+  /*      #include <freetype/config/ftheader.h>                            */
   /*                                                                       */
   /*    will use `$BUILD/myftoptions.h' instead of this file for macro     */
   /*    definitions.                                                       */
@@ -59,7 +59,7 @@
   /*    Note also that you can similarly pre-define the macro              */
   /*    FT_CONFIG_MODULES_H used to locate the file listing of the modules */
   /*    that are statically linked to the library at compile time.  By     */
-  /*    default, this file is <config/ftmodule.h>.                         */
+  /*    default, this file is <freetype/config/ftmodule.h>.                */
   /*                                                                       */
   /* We highly recommend using the third method whenever possible.         */
   /*                                                                       */
@@ -693,6 +693,24 @@
 
 
   /*************************************************************************/
+  /*                                                                       */
+  /* Option TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES controls the maximum     */
+  /* number of bytecode instructions executed for a single run of the      */
+  /* bytecode interpreter, needed to prevent infinite loops.  You don't    */
+  /* want to change this except for very special situations (e.g., making  */
+  /* a library fuzzer spend less time to handle broken fonts).             */
+  /*                                                                       */
+  /* It is not expected that this value is ever modified by a configuring  */
+  /* script; instead, it gets surrounded with #ifndef ... #endif so that   */
+  /* the value can be set as a preprocessor option on the compiler's       */
+  /* command line.                                                         */
+  /*                                                                       */
+#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES
+#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES  1000000L
+#endif
+
+
+  /*************************************************************************/
   /*************************************************************************/
   /****                                                                 ****/
   /****      T Y P E 1   D R I V E R    C O N F I G U R A T I O N       ****/
diff --git a/include/config/ftstdlib.h b/include/freetype/config/ftstdlib.h
similarity index 99%
rename from include/config/ftstdlib.h
rename to include/freetype/config/ftstdlib.h
index 8ef43c0..4b471d4 100644
--- a/include/config/ftstdlib.h
+++ b/include/freetype/config/ftstdlib.h
@@ -64,6 +64,7 @@
 #define FT_INT_MAX     INT_MAX
 #define FT_INT_MIN     INT_MIN
 #define FT_UINT_MAX    UINT_MAX
+#define FT_LONG_MAX    LONG_MAX
 #define FT_ULONG_MAX   ULONG_MAX
 
 
diff --git a/include/freetype.h b/include/freetype/freetype.h
similarity index 92%
rename from include/freetype.h
rename to include/freetype/freetype.h
index bca93e5..f68718d 100644
--- a/include/freetype.h
+++ b/include/freetype/freetype.h
@@ -876,17 +876,36 @@
   /*                           font formats can have multiple faces in     */
   /*                           a font file.                                */
   /*                                                                       */
-  /*    face_index          :: The index of the face in the font file.  It */
-  /*                           is set to~0 if there is only one face in    */
+  /*    face_index          :: This field holds two different values.      */
+  /*                           Bits 0-15 are the index of the face in the  */
+  /*                           font file (starting with value~0).  They    */
+  /*                           are set to~0 if there is only one face in   */
   /*                           the font file.                              */
   /*                                                                       */
+  /*                           Bits 16-30 are relevant to GX variation     */
+  /*                           fonts only, holding the named instance      */
+  /*                           index for the current face index (starting  */
+  /*                           with value~1; value~0 indicates font access */
+  /*                           without GX variation data).  For non-GX     */
+  /*                           fonts, bits 16-30 are ignored.  If we have  */
+  /*                           the third named instance of face~4, say,    */
+  /*                           `face_index' is set to 0x00030004.          */
+  /*                                                                       */
+  /*                           Bit 31 is always zero (this is,             */
+  /*                           `face_index' is always a positive value).   */
+  /*                                                                       */
   /*    face_flags          :: A set of bit flags that give important      */
   /*                           information about the face; see             */
   /*                           @FT_FACE_FLAG_XXX for the details.          */
   /*                                                                       */
-  /*    style_flags         :: A set of bit flags indicating the style of  */
-  /*                           the face; see @FT_STYLE_FLAG_XXX for the    */
-  /*                           details.                                    */
+  /*    style_flags         :: The lower 16~bits contain a set of bit      */
+  /*                           flags indicating the style of the face; see */
+  /*                           @FT_STYLE_FLAG_XXX for the details.  Bits   */
+  /*                           16-30 hold the number of named instances    */
+  /*                           available for the current face if we have a */
+  /*                           GX variation (sub)font.  Bit 31 is always   */
+  /*                           zero (this is, `style_flags' is always a    */
+  /*                           positive value).                            */
   /*                                                                       */
   /*    num_glyphs          :: The number of glyphs in the face.  If the   */
   /*                           face is scalable and has sbits (see         */
@@ -1392,7 +1411,7 @@
   /*    FT_STYLE_FLAG_XXX                                                  */
   /*                                                                       */
   /* <Description>                                                         */
-  /*    A list of bit-flags used to indicate the style of a given face.    */
+  /*    A list of bit flags used to indicate the style of a given face.    */
   /*    These are used in the `style_flags' field of @FT_FaceRec.          */
   /*                                                                       */
   /* <Values>                                                              */
@@ -1824,7 +1843,7 @@
   /*    FT_OPEN_XXX                                                        */
   /*                                                                       */
   /* <Description>                                                         */
-  /*    A list of bit-field constants used within the `flags' field of the */
+  /*    A list of bit field constants used within the `flags' field of the */
   /*    @FT_Open_Args structure.                                           */
   /*                                                                       */
   /* <Values>                                                              */
@@ -1971,13 +1990,12 @@
   /* <Input>                                                               */
   /*    pathname   :: A path to the font file.                             */
   /*                                                                       */
-  /*    face_index :: The index of the face within the font.  The first    */
-  /*                  face has index~0.                                    */
+  /*    face_index :: See @FT_Open_Face for a detailed description of this */
+  /*                  parameter.                                           */
   /*                                                                       */
   /* <Output>                                                              */
   /*    aface      :: A handle to a new face object.  If `face_index' is   */
   /*                  greater than or equal to zero, it must be non-NULL.  */
-  /*                  See @FT_Open_Face for more details.                  */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0~means success.                             */
@@ -2010,13 +2028,12 @@
   /*                                                                       */
   /*    file_size  :: The size of the memory chunk used by the font data.  */
   /*                                                                       */
-  /*    face_index :: The index of the face within the font.  The first    */
-  /*                  face has index~0.                                    */
+  /*    face_index :: See @FT_Open_Face for a detailed description of this */
+  /*                  parameter.                                           */
   /*                                                                       */
   /* <Output>                                                              */
   /*    aface      :: A handle to a new face object.  If `face_index' is   */
   /*                  greater than or equal to zero, it must be non-NULL.  */
-  /*                  See @FT_Open_Face for more details.                  */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0~means success.                             */
@@ -2048,13 +2065,43 @@
   /*    args       :: A pointer to an `FT_Open_Args' structure that must   */
   /*                  be filled by the caller.                             */
   /*                                                                       */
-  /*    face_index :: The index of the face within the font.  The first    */
-  /*                  face has index~0.                                    */
+  /*    face_index :: This field holds two different values.  Bits 0-15    */
+  /*                  are the index of the face in the font file (starting */
+  /*                  with value~0).  Set it to~0 if there is only one     */
+  /*                  face in the font file.                               */
+  /*                                                                       */
+  /*                  Bits 16-30 are relevant to GX variation fonts only,  */
+  /*                  specifying the named instance index for the current  */
+  /*                  face index (starting with value~1; value~0 makes     */
+  /*                  FreeType ignore named instances).  For non-GX fonts, */
+  /*                  bits 16-30 are ignored.  Assuming that you want to   */
+  /*                  access the third named instance in face~4,           */
+  /*                  `face_index' should be set to 0x00030004.  If you    */
+  /*                  want to access face~4 without GX variation handling, */
+  /*                  simply set `face_index' to value~4.                  */
+  /*                                                                       */
+  /*                  FT_Open_Face and its siblings can be used to quickly */
+  /*                  check whether the font format of a given font        */
+  /*                  resource is supported by FreeType.  In general, if   */
+  /*                  the `face_index' argument is negative, the           */
+  /*                  function's return value is~0 if the font format is   */
+  /*                  recognized, or non-zero otherwise.  The function     */
+  /*                  allocates a more or less empty face handle in        */
+  /*                  `*aface' (if `aface' isn't NULL); the only two       */
+  /*                  useful fields in this special case are               */
+  /*                  `face->num_faces' and `face->style_flags'.  For any  */
+  /*                  negative value of `face_index', `face->num_faces'    */
+  /*                  gives the number of faces within the font file.  For */
+  /*                  the negative value `-(N+1)' (with `N' a 16-bit       */
+  /*                  value), bits 16-30 in `face->style_flags' give the   */
+  /*                  number of named instances in face `N' if we have a   */
+  /*                  GX variation font (or zero otherwise).  After        */
+  /*                  examination, the returned @FT_Face structure should  */
+  /*                  be deallocated with a call to @FT_Done_Face.         */
   /*                                                                       */
   /* <Output>                                                              */
   /*    aface      :: A handle to a new face object.  If `face_index' is   */
   /*                  greater than or equal to zero, it must be non-NULL.  */
-  /*                  See note below.                                      */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0~means success.                             */
@@ -2064,16 +2111,6 @@
   /*    slot for the face object that can be accessed directly through     */
   /*    `face->glyph'.                                                     */
   /*                                                                       */
-  /*    FT_Open_Face can be used to quickly check whether the font         */
-  /*    format of a given font resource is supported by FreeType.  If the  */
-  /*    `face_index' field is negative, the function's return value is~0   */
-  /*    if the font format is recognized, or non-zero otherwise;           */
-  /*    the function returns a more or less empty face handle in `*aface'  */
-  /*    (if `aface' isn't NULL).  The only useful field in this special    */
-  /*    case is `face->num_faces' that gives the number of faces within    */
-  /*    the font file.  After examination, the returned @FT_Face structure */
-  /*    should be deallocated with a call to @FT_Done_Face.                */
-  /*                                                                       */
   /*    Each new face object created with this function also owns a        */
   /*    default @FT_Size object, accessible as `face->size'.               */
   /*                                                                       */
@@ -2084,6 +2121,74 @@
   /*    See the discussion of reference counters in the description of     */
   /*    @FT_Reference_Face.                                                */
   /*                                                                       */
+  /*    To loop over all faces, use code similar to the following snippet  */
+  /*    (omitting the error handling).                                     */
+  /*                                                                       */
+  /*    {                                                                  */
+  /*      ...                                                              */
+  /*      FT_Face  face;                                                   */
+  /*      FT_Long  i, num_faces;                                           */
+  /*                                                                       */
+  /*                                                                       */
+  /*      error = FT_Open_Face( library, args, -1, &face );                */
+  /*      if ( error ) { ... }                                             */
+  /*                                                                       */
+  /*      num_faces = face->num_faces;                                     */
+  /*      FT_Done_Face( face );                                            */
+  /*                                                                       */
+  /*      for ( i = 0; i < num_faces; i++ )                                */
+  /*      {                                                                */
+  /*        ...                                                            */
+  /*        error = FT_Open_Face( library, args, i, &face );               */
+  /*        ...                                                            */
+  /*        FT_Done_Face( face );                                          */
+  /*        ...                                                            */
+  /*      }                                                                */
+  /*    }                                                                  */
+  /*                                                                       */
+  /*    To loop over all valid values for `face_index', use something      */
+  /*    similar to the following snippet, again without error handling.    */
+  /*    The code accesses all faces immediately (thus only a single call   */
+  /*    of `FT_Open_Face' within the do-loop), with and without named      */
+  /*    instances.                                                         */
+  /*                                                                       */
+  /*    {                                                                  */
+  /*      ...                                                              */
+  /*      FT_Face  face;                                                   */
+  /*                                                                       */
+  /*      FT_Long  num_faces     = 0;                                      */
+  /*      FT_Long  num_instances = 0;                                      */
+  /*                                                                       */
+  /*      FT_Long  face_idx     = 0;                                       */
+  /*      FT_Long  instance_idx = 0;                                       */
+  /*                                                                       */
+  /*                                                                       */
+  /*      do                                                               */
+  /*      {                                                                */
+  /*        FT_Long  id = ( instance_idx << 16 ) + face_idx;               */
+  /*                                                                       */
+  /*                                                                       */
+  /*        error = FT_Open_Face( library, args, id, &face );              */
+  /*        if ( error ) { ... }                                           */
+  /*                                                                       */
+  /*        num_faces     = face->num_faces;                               */
+  /*        num_instances = face->style_flags >> 16;                       */
+  /*                                                                       */
+  /*        ...                                                            */
+  /*                                                                       */
+  /*        FT_Done_Face( face );                                          */
+  /*                                                                       */
+  /*        if ( instance_idx < num_instances )                            */
+  /*          instance_idx++;                                              */
+  /*        else                                                           */
+  /*        {                                                              */
+  /*          face_idx++;                                                  */
+  /*          instance_idx = 0;                                            */
+  /*        }                                                              */
+  /*                                                                       */
+  /*      } while ( face_idx < num_faces )                                 */
+  /*    }                                                                  */
+  /*                                                                       */
   FT_EXPORT( FT_Error )
   FT_Open_Face( FT_Library           library,
                 const FT_Open_Args*  args,
@@ -2521,7 +2626,7 @@
    *   FT_LOAD_XXX
    *
    * @description:
-   *   A list of bit-field constants used with @FT_Load_Glyph to indicate
+   *   A list of bit field constants used with @FT_Load_Glyph to indicate
    *   what kind of operations to perform during glyph loading.
    *
    * @values:
@@ -2638,6 +2743,16 @@
    *     bitmaps transparently.  Those bitmaps will be in the
    *     @FT_PIXEL_MODE_GRAY format.
    *
+   *   FT_LOAD_COMPUTE_METRICS ::
+   *     This flag sets computing glyph metrics without the use of bundled
+   *     metrics tables (for example, the `hdmx' table in TrueType fonts).
+   *     Well-behaving fonts have optimized bundled metrics and these should
+   *     be used.  This flag is mainly used by font validating or font
+   *     editing applications, which need to ignore, verify, or edit those
+   *     tables.
+   *
+   *     Currently, this flag is only implemented for TrueType fonts.
+   *
    *   FT_LOAD_CROP_BITMAP ::
    *     Ignored.  Deprecated.
    *
@@ -2683,6 +2798,7 @@
 #define FT_LOAD_NO_AUTOHINT                  ( 1L << 15 )
   /* Bits 16..19 are used by `FT_LOAD_TARGET_' */
 #define FT_LOAD_COLOR                        ( 1L << 20 )
+#define FT_LOAD_COMPUTE_METRICS              ( 1L << 21 )
 
   /* */
 
@@ -2705,9 +2821,6 @@
    *   have specified (e.g., the TrueType bytecode interpreter).  You can set
    *   @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used.
    *
-   *   Also note that @FT_LOAD_TARGET_LIGHT is an exception, in that it
-   *   always implies @FT_LOAD_FORCE_AUTOHINT.
-   *
    * @values:
    *   FT_LOAD_TARGET_NORMAL ::
    *     This corresponds to the default hinting algorithm, optimized for
@@ -2715,11 +2828,14 @@
    *     @FT_LOAD_TARGET_MONO instead.
    *
    *   FT_LOAD_TARGET_LIGHT ::
-   *     A lighter hinting algorithm for non-monochrome modes.  Many
-   *     generated glyphs are more fuzzy but better resemble its original
-   *     shape.  A bit like rendering on Mac OS~X.
-   *
-   *     As a special exception, this target implies @FT_LOAD_FORCE_AUTOHINT.
+   *     A lighter hinting algorithm for gray-level modes.  Many generated
+   *     glyphs are fuzzier but better resemble their original shape.  This
+   *     is achieved by snapping glyphs to the pixel grid only vertically
+   *     (Y-axis), as is done by Microsoft's ClearType and Adobe's
+   *     proprietary font renderer.  This preserves inter-glyph spacing in
+   *     horizontal text.  The snapping is done either by the native font
+   *     driver if the driver itself and the font support it or by the
+   *     auto-hinter.
    *
    *   FT_LOAD_TARGET_MONO ::
    *     Strong hinting algorithm that should only be used for monochrome
@@ -2826,7 +2942,10 @@
   /*    field in the @FT_GlyphSlotRec structure gives the format of the    */
   /*    returned bitmap.                                                   */
   /*                                                                       */
-  /*    All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity.   */
+  /*    All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity,   */
+  /*    indicating pixel coverage.  Use linear alpha blending and gamma    */
+  /*    correction to correctly render non-monochrome glyph bitmaps onto a */
+  /*    surface; see @FT_Render_Glyph.                                     */
   /*                                                                       */
   /* <Values>                                                              */
   /*    FT_RENDER_MODE_NORMAL ::                                           */
@@ -2912,6 +3031,83 @@
   /*    To get meaningful results, font scaling values must be set with    */
   /*    functions like @FT_Set_Char_Size before calling FT_Render_Glyph.   */
   /*                                                                       */
+  /*    When FreeType outputs a bitmap of a glyph, it really outputs an    */
+  /*    alpha coverage map.  If a pixel is completely covered by a         */
+  /*    filled-in outline, the bitmap contains 0xFF at that pixel, meaning */
+  /*    that 0xFF/0xFF fraction of that pixel is covered, meaning the      */
+  /*    pixel is 100% black (or 0% bright).  If a pixel is only 50%        */
+  /*    covered (value 0x80), the pixel is made 50% black (50% bright or a */
+  /*    middle shade of grey).  0% covered means 0% black (100% bright or  */
+  /*    white).                                                            */
+  /*                                                                       */
+  /*    On high-DPI screens like on smartphones and tablets, the pixels    */
+  /*    are so small that their chance of being completely covered and     */
+  /*    therefore completely black are fairly good.  On the low-DPI        */
+  /*    screens, however, the situation is different.  The pixels are too  */
+  /*    large for most of the details of a glyph and shades of gray are    */
+  /*    the norm rather than the exception.                                */
+  /*                                                                       */
+  /*    This is relevant because all our screens have a second problem:    */
+  /*    they are not linear.  1~+~1 is not~2.  Twice the value does not    */
+  /*    result in twice the brightness.  When a pixel is only 50% covered, */
+  /*    the coverage map says 50% black, and this translates to a pixel    */
+  /*    value of 128 when you use 8~bits per channel (0-255).  However,    */
+  /*    this does not translate to 50% brightness for that pixel on our    */
+  /*    sRGB and gamma~2.2 screens.  Due to their non-linearity, they      */
+  /*    dwell longer in the darks and only a pixel value of about 186      */
+  /*    results in 50% brightness – 128 ends up too dark on both bright    */
+  /*    and dark backgrounds.  The net result is that dark text looks      */
+  /*    burnt-out, pixely and blotchy on bright background, bright text    */
+  /*    too frail on dark backgrounds, and colored text on colored         */
+  /*    background (for example, red on green) seems to have dark halos or */
+  /*    `dirt' around it.  The situation is especially ugly for diagonal   */
+  /*    stems like in `w' glyph shapes where the quality of FreeType's     */
+  /*    anti-aliasing depends on the correct display of grays.  On         */
+  /*    high-DPI screens where smaller, fully black pixels reign supreme,  */
+  /*    this doesn't matter, but on our low-DPI screens with all the gray  */
+  /*    shades, it does.  0% and 100% brightness are the same things in    */
+  /*    linear and non-linear space, just all the shades in-between        */
+  /*    aren't.                                                            */
+  /*                                                                       */
+  /*    The blending function for placing text over a background is        */
+  /*                                                                       */
+  /*    {                                                                  */
+  /*      dst = alpha * src + (1 - alpha) * dst    ,                       */
+  /*    }                                                                  */
+  /*                                                                       */
+  /*    which is known as the OVER operator.                               */
+  /*                                                                       */
+  /*    To correctly composite an antialiased pixel of a glyph onto a      */
+  /*    surface,                                                           */
+  /*                                                                       */
+  /*    1. take the foreground and background colors (e.g., in sRGB space) */
+  /*       and apply gamma to get them in a linear space,                  */
+  /*                                                                       */
+  /*    2. use OVER to blend the two linear colors using the glyph pixel   */
+  /*       as the alpha value (remember, the glyph bitmap is an alpha      */
+  /*       coverage bitmap), and                                           */
+  /*                                                                       */
+  /*    3. apply inverse gamma to the blended pixel and write it back to   */
+  /*       the image.                                                      */
+  /*                                                                       */
+  /*    Internal testing at Adobe found that a target inverse gamma of~1.8 */
+  /*    for step~3 gives good results across a wide range of displays with */
+  /*    an sRGB gamma curve or a similar one.                              */
+  /*                                                                       */
+  /*    This process can cost performance.  There is an approximation that */
+  /*    does not need to know about the background color; see              */
+  /*    https://bel.fi/alankila/lcd/ and                                   */
+  /*    https://bel.fi/alankila/lcd/alpcor.html for details.               */
+  /*                                                                       */
+  /*    *ATTENTION*: Linear blending is even more important when dealing   */
+  /*    with subpixel-rendered glyphs to prevent color-fringing!  A        */
+  /*    subpixel-rendered glyph must first be filtered with a filter that  */
+  /*    gives equal weight to the three color primaries and does not       */
+  /*    exceed a sum of 0x100, see section @lcd_filtering.  Then the       */
+  /*    only difference to gray linear blending is that subpixel-rendered  */
+  /*    linear blending is done 3~times per pixel: red foreground subpixel */
+  /*    to red background subpixel and so on for green and blue.           */
+  /*                                                                       */
   FT_EXPORT( FT_Error )
   FT_Render_Glyph( FT_GlyphSlot    slot,
                    FT_Render_Mode  render_mode );
@@ -2927,15 +3123,22 @@
   /*    @FT_Get_Kerning.                                                   */
   /*                                                                       */
   /* <Values>                                                              */
-  /*    FT_KERNING_DEFAULT  :: Return scaled and grid-fitted kerning       */
-  /*                           distances (value is~0).                     */
+  /*    FT_KERNING_DEFAULT  :: Return grid-fitted kerning distances in     */
+  /*                           pixels (value is~0).  Whether they are      */
+  /*                           scaled depends on @FT_LOAD_NO_SCALE.        */
   /*                                                                       */
-  /*    FT_KERNING_UNFITTED :: Return scaled but un-grid-fitted kerning    */
-  /*                           distances.                                  */
+  /*    FT_KERNING_UNFITTED :: Return un-grid-fitted kerning distances in  */
+  /*                           26.6 fractional pixels.  Whether they are   */
+  /*                           scaled depends on @FT_LOAD_NO_SCALE.        */
   /*                                                                       */
   /*    FT_KERNING_UNSCALED :: Return the kerning vector in original font  */
   /*                           units.                                      */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    FT_KERNING_DEFAULT returns full pixel values; it also makes        */
+  /*    FreeType heuristically scale down kerning distances at small ppem  */
+  /*    values so that they don't become too big.                          */
+  /*                                                                       */
   typedef enum  FT_Kerning_Mode_
   {
     FT_KERNING_DEFAULT  = 0,
@@ -2972,9 +3175,10 @@
   /*                   kerning vector.                                     */
   /*                                                                       */
   /* <Output>                                                              */
-  /*    akerning    :: The kerning vector.  This is either in font units   */
-  /*                   or in pixels (26.6 format) for scalable formats,    */
-  /*                   and in pixels for fixed-sizes formats.              */
+  /*    akerning    :: The kerning vector.  This is either in font units,  */
+  /*                   fractional pixels (26.6 format), or pixels for      */
+  /*                   scalable formats, and in pixels for fixed-sizes     */
+  /*                   formats.                                            */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0~means success.                             */
@@ -3259,6 +3463,13 @@
   /*      }                                                                */
   /*    }                                                                  */
   /*                                                                       */
+  /*    Be aware that character codes can have values up to 0xFFFFFFFF;    */
+  /*    this might happen for non-Unicode or malformed cmaps.  However,    */
+  /*    even with regular Unicode encoding, so-called `last resort fonts'  */
+  /*    (using SFNT cmap format 13, see function @FT_Get_CMap_Format)      */
+  /*    normally have entries for all Unicode characters up to 0x1FFFFF,   */
+  /*    which can cause *a lot* of iterations.                             */
+  /*                                                                       */
   /*    Note that `*agindex' is set to~0 if the charmap is empty.  The     */
   /*    result itself can be~0 in two cases: if the charmap is empty or    */
   /*    if the value~0 is the first valid character code.                  */
@@ -3454,6 +3665,9 @@
   /*      bitmaps available in the font, then the font is unembeddable.    */
   /*                                                                       */
   /* <Note>                                                                */
+  /*    The flags are ORed together, thus more than a single value can be  */
+  /*    returned.                                                          */
+  /*                                                                       */
   /*    While the fsType flags can indicate that a font may be embedded, a */
   /*    license with the font vendor may be separately required to use the */
   /*    font in this way.                                                  */
@@ -3839,7 +4053,8 @@
   /*    a :: The number to be rounded.                                     */
   /*                                                                       */
   /* <Return>                                                              */
-  /*    The result of `(a + 0x8000) & -0x10000'.                           */
+  /*    `a' rounded to nearest 16.16 fixed integer, halfway cases away     */
+  /*    from zero.                                                         */
   /*                                                                       */
   FT_EXPORT( FT_Fixed )
   FT_RoundFix( FT_Fixed  a );
@@ -3858,7 +4073,7 @@
   /*    a :: The number for which the ceiling function is to be computed.  */
   /*                                                                       */
   /* <Return>                                                              */
-  /*    The result of `(a + 0x10000 - 1) & -0x10000'.                      */
+  /*    `a' rounded towards plus infinity.                                 */
   /*                                                                       */
   FT_EXPORT( FT_Fixed )
   FT_CeilFix( FT_Fixed  a );
@@ -3877,7 +4092,7 @@
   /*    a :: The number for which the floor function is to be computed.    */
   /*                                                                       */
   /* <Return>                                                              */
-  /*    The result of `a & -0x10000'.                                      */
+  /*    `a' rounded towards minus infinity.                                */
   /*                                                                       */
   FT_EXPORT( FT_Fixed )
   FT_FloorFix( FT_Fixed  a );
@@ -3958,7 +4173,7 @@
    */
 #define FREETYPE_MAJOR  2
 #define FREETYPE_MINOR  6
-#define FREETYPE_PATCH  0
+#define FREETYPE_PATCH  2
 
 
   /*************************************************************************/
diff --git a/include/ftadvanc.h b/include/freetype/ftadvanc.h
similarity index 100%
rename from include/ftadvanc.h
rename to include/freetype/ftadvanc.h
diff --git a/include/ftautoh.h b/include/freetype/ftautoh.h
similarity index 87%
rename from include/ftautoh.h
rename to include/freetype/ftautoh.h
index cf7b76f..d0f6445 100644
--- a/include/ftautoh.h
+++ b/include/freetype/ftautoh.h
@@ -247,8 +247,8 @@
    */
   typedef struct  FT_Prop_GlyphToScriptMap_
   {
-    FT_Face   face;
-    FT_Byte*  map;
+    FT_Face     face;
+    FT_UShort*  map;
 
   } FT_Prop_GlyphToScriptMap;
 
@@ -439,6 +439,59 @@
    */
 
 
+  /**************************************************************************
+   *
+   * @property:
+   *   no-stem-darkening[autofit]
+   *
+   * @description:
+   *   *Experimental* *only,* *requires* *linear* *alpha* *blending* *and*
+   *   *gamma* *correction*
+   *
+   *   Stem darkening emboldens glyphs at smaller sizes to make them more
+   *   readable on common low-DPI screens when using linear alpha blending
+   *   and gamma correction, see @FT_Render_Glyph.  When not using linear
+   *   alpha blending and gamma correction, glyphs will appear heavy and
+   *   fuzzy!
+   *
+   *   Gamma correction essentially lightens fonts since shades of grey are
+   *   shifted to higher pixel values (=~higher brightness) to match the
+   *   original intention to the reality of our screens.  The side-effect is
+   *   that glyphs `thin out'.  Mac OS~X and Adobe's proprietary font
+   *   rendering library implement a counter-measure: stem darkening at
+   *   smaller sizes where shades of gray dominate.  By emboldening a glyph
+   *   slightly in relation to its pixel size, individual pixels get higher
+   *   coverage of filled-in outlines and are therefore `blacker'.  This
+   *   counteracts the `thinning out' of glyphs, making text remain readable
+   *   at smaller sizes.  All glyphs that pass through the auto-hinter will
+   *   be emboldened unless this property is set to TRUE.
+   *
+   *   See the description of the CFF driver for algorithmic details.  Total
+   *   consistency with the CFF driver is currently not achieved because the
+   *   emboldening method differs and glyphs must be scaled down on the
+   *   Y-axis to keep outline points inside their precomputed blue zones.
+   *   The smaller the size (especially 9ppem and down), the higher the loss
+   *   of emboldening versus the CFF driver.
+   *
+   */
+
+
+  /**************************************************************************
+   *
+   * @property:
+   *   darkening-parameters[autofit]
+   *
+   * @description:
+   *   *Experimental* *only*
+   *
+   *   See the description of the CFF driver for details.  This
+   *   implementation appropriates the
+   *   CFF_CONFIG_OPTION_DARKENING_PARAMETER_* #defines for consistency.
+   *   Note the differences described in @no-stem-darkening[autofit].
+   *
+   */
+
+
   /* */
 
 
diff --git a/include/ftbbox.h b/include/freetype/ftbbox.h
similarity index 100%
rename from include/ftbbox.h
rename to include/freetype/ftbbox.h
diff --git a/include/ftbdf.h b/include/freetype/ftbdf.h
similarity index 100%
rename from include/ftbdf.h
rename to include/freetype/ftbdf.h
diff --git a/include/ftbitmap.h b/include/freetype/ftbitmap.h
similarity index 100%
rename from include/ftbitmap.h
rename to include/freetype/ftbitmap.h
diff --git a/include/ftbzip2.h b/include/freetype/ftbzip2.h
similarity index 100%
rename from include/ftbzip2.h
rename to include/freetype/ftbzip2.h
diff --git a/include/ftcache.h b/include/freetype/ftcache.h
similarity index 100%
rename from include/ftcache.h
rename to include/freetype/ftcache.h
diff --git a/include/ftcffdrv.h b/include/freetype/ftcffdrv.h
similarity index 98%
rename from include/ftcffdrv.h
rename to include/freetype/ftcffdrv.h
index 6c8e416..8500346 100644
--- a/include/ftcffdrv.h
+++ b/include/freetype/ftcffdrv.h
@@ -111,8 +111,8 @@
    *
    * @order:
    *   hinting-engine
-   *   no-stem-darkening
-   *   darkening-parameters
+   *   no-stem-darkening[cff]
+   *   darkening-parameters[cff]
    *
    */
 
@@ -175,7 +175,7 @@
   /**************************************************************************
    *
    * @property:
-   *   no-stem-darkening
+   *   no-stem-darkening[cff]
    *
    * @description:
    *   By default, the Adobe CFF engine darkens stems at smaller sizes,
@@ -205,7 +205,7 @@
   /**************************************************************************
    *
    * @property:
-   *   darkening-parameters
+   *   darkening-parameters[cff]
    *
    * @description:
    *   By default, the Adobe CFF engine darkens stems as follows (if the
diff --git a/include/ftchapters.h b/include/freetype/ftchapters.h
similarity index 89%
rename from include/ftchapters.h
rename to include/freetype/ftchapters.h
index d333761..ab43895 100644
--- a/include/ftchapters.h
+++ b/include/freetype/ftchapters.h
@@ -119,3 +119,17 @@
 /*    lcd_filtering                                                        */
 /*                                                                         */
 /***************************************************************************/
+
+/***************************************************************************/
+/*                                                                         */
+/* <Chapter>                                                               */
+/*    error_codes                                                          */
+/*                                                                         */
+/* <Title>                                                                 */
+/*    Error Codes                                                          */
+/*                                                                         */
+/* <Sections>                                                              */
+/*    error_enumerations                                                   */
+/*    error_code_values                                                    */
+/*                                                                         */
+/***************************************************************************/
diff --git a/include/ftcid.h b/include/freetype/ftcid.h
similarity index 100%
rename from include/ftcid.h
rename to include/freetype/ftcid.h
diff --git a/include/fterrdef.h b/include/freetype/fterrdef.h
similarity index 82%
rename from include/fterrdef.h
rename to include/freetype/fterrdef.h
index 1bf0751..3bf4e63 100644
--- a/include/fterrdef.h
+++ b/include/freetype/fterrdef.h
@@ -16,18 +16,43 @@
 /***************************************************************************/
 
 
-  /*******************************************************************/
-  /*******************************************************************/
-  /*****                                                         *****/
-  /*****                LIST OF ERROR CODES/MESSAGES             *****/
-  /*****                                                         *****/
-  /*******************************************************************/
-  /*******************************************************************/
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Section>                                                             */
+  /*   error_code_values                                                   */
+  /*                                                                       */
+  /* <Title>                                                               */
+  /*   Error Code Values                                                   */
+  /*                                                                       */
+  /* <Abstract>                                                            */
+  /*   All possible error codes returned by FreeType functions.            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*   The list below is taken verbatim from the file `fterrdef.h'         */
+  /*   (loaded automatically by including `FT_FREETYPE_H').  The first     */
+  /*   argument of the `FT_ERROR_DEF_' macro is the error label; by        */
+  /*   default, the prefix `FT_Err_' gets added so that you get error      */
+  /*   names like `FT_Err_Cannot_Open_Resource'.  The second argument is   */
+  /*   the error code, and the last argument an error string, which is not */
+  /*   used by FreeType.                                                   */
+  /*                                                                       */
+  /*   Within your application you should *only* use error names and       */
+  /*   *never* its numeric values!  The latter might (and actually do)     */
+  /*   change in forthcoming FreeType versions.                            */
+  /*                                                                       */
+  /*   Macro `FT_NOERRORDEF_' defines `FT_Err_Ok', which is always zero.   */
+  /*   See the `Error Enumerations' subsection how to automatically        */
+  /*   generate a list of error strings.                                   */
+  /*                                                                       */
+  /*************************************************************************/
 
 
-  /* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */
-  /* including this file.                                           */
-
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Enum>                                                                */
+  /*    FT_Err_XXX                                                         */
+  /*                                                                       */
+  /*************************************************************************/
 
   /* generic errors */
 
@@ -218,7 +243,7 @@
   FT_ERRORDEF_( No_Unicode_Glyph_Name,                       0xA3,
                 "no Unicode glyph name found" )
   FT_ERRORDEF_( Glyph_Too_Big,                               0xA4,
-                "glyph to big for hinting" )
+                "glyph too big for hinting" )
 
   /* BDF errors */
 
@@ -245,5 +270,7 @@
   FT_ERRORDEF_( Corrupted_Font_Glyphs,                       0xBA,
                 "Font glyphs corrupted or missing fields" )
 
+  /* */
+
 
 /* END */
diff --git a/include/fterrors.h b/include/freetype/fterrors.h
similarity index 61%
rename from include/fterrors.h
rename to include/freetype/fterrors.h
index 376bee6..0507b9a 100644
--- a/include/fterrors.h
+++ b/include/freetype/fterrors.h
@@ -18,68 +18,86 @@
 
   /*************************************************************************/
   /*                                                                       */
-  /* This special header file is used to define the handling of FT2        */
-  /* enumeration constants.  It can also be used to generate error message */
-  /* strings with a small macro trick explained below.                     */
+  /* <Section>                                                             */
+  /*   error_enumerations                                                  */
   /*                                                                       */
-  /* I - Error Formats                                                     */
-  /* -----------------                                                     */
+  /* <Title>                                                               */
+  /*   Error Enumerations                                                  */
+  /*                                                                       */
+  /* <Abstract>                                                            */
+  /*   How to handle errors and error strings.                             */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*   The header file `fterrors.h' (which is automatically included by    */
+  /*   `freetype.h' defines the handling of FreeType's enumeration         */
+  /*   constants.  It can also be used to generate error message strings   */
+  /*   with a small macro trick explained below.                           */
+  /*                                                                       */
+  /*   *Error* *Formats*                                                   */
   /*                                                                       */
   /*   The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be   */
-  /*   defined in ftoption.h in order to make the higher byte indicate     */
+  /*   defined in `ftoption.h' in order to make the higher byte indicate   */
   /*   the module where the error has happened (this is not compatible     */
-  /*   with standard builds of FreeType 2).  See the file `ftmoderr.h' for */
-  /*   more details.                                                       */
+  /*   with standard builds of FreeType&nbsp;2, however).  See the file    */
+  /*   `ftmoderr.h' for more details.                                      */
   /*                                                                       */
+  /*   *Error* *Message* *Strings*                                         */
   /*                                                                       */
-  /* II - Error Message strings                                            */
-  /* --------------------------                                            */
-  /*                                                                       */
-  /*   The error definitions below are made through special macros that    */
-  /*   allow client applications to build a table of error message strings */
-  /*   if they need it.  The strings are not included in a normal build of */
-  /*   FreeType 2 to save space (most client applications do not use       */
-  /*   them).                                                              */
+  /*   Error definitions are set up with special macros that allow client  */
+  /*   applications to build a table of error message strings.  The        */
+  /*   strings are not included in a normal build of FreeType&nbsp;2 to    */
+  /*   save space (most client applications do not use them).              */
   /*                                                                       */
   /*   To do so, you have to define the following macros before including  */
-  /*   this file:                                                          */
-  /*                                                                       */
-  /*   FT_ERROR_START_LIST ::                                              */
-  /*     This macro is called before anything else to define the start of  */
-  /*     the error list.  It is followed by several FT_ERROR_DEF calls     */
-  /*     (see below).                                                      */
-  /*                                                                       */
-  /*   FT_ERROR_DEF( e, v, s ) ::                                          */
-  /*     This macro is called to define one single error.                  */
-  /*     `e' is the error code identifier (e.g. FT_Err_Invalid_Argument).  */
-  /*     `v' is the error numerical value.                                 */
-  /*     `s' is the corresponding error string.                            */
-  /*                                                                       */
-  /*   FT_ERROR_END_LIST ::                                                */
-  /*     This macro ends the list.                                         */
-  /*                                                                       */
-  /*   Additionally, you have to undefine __FTERRORS_H__ before #including */
   /*   this file.                                                          */
   /*                                                                       */
-  /*   Here is a simple example:                                           */
+  /*   {                                                                   */
+  /*     FT_ERROR_START_LIST                                               */
+  /*   }                                                                   */
   /*                                                                       */
+  /*   This macro is called before anything else to define the start of    */
+  /*   the error list.  It is followed by several FT_ERROR_DEF calls.      */
+  /*                                                                       */
+  /*   {                                                                   */
+  /*     FT_ERROR_DEF( e, v, s )                                           */
+  /*   }                                                                   */
+  /*                                                                       */
+  /*   This macro is called to define one single error.  `e' is the error  */
+  /*   code identifier (e.g., `Invalid_Argument'), `v' is the error's      */
+  /*   numerical value, and `s' is the corresponding error string.         */
+  /*                                                                       */
+  /*   {                                                                   */
+  /*     FT_ERROR_END_LIST                                                 */
+  /*   }                                                                   */
+  /*                                                                       */
+  /*   This macro ends the list.                                           */
+  /*                                                                       */
+  /*   Additionally, you have to undefine `__FTERRORS_H__' before          */
+  /*   #including this file.                                               */
+  /*                                                                       */
+  /*   Here is a simple example.                                           */
+  /*                                                                       */
+  /*   {                                                                   */
+  /*     #undef __FTERRORS_H__                                             */
+  /*     #define FT_ERRORDEF( e, v, s )  { e, s },                         */
+  /*     #define FT_ERROR_START_LIST     {                                 */
+  /*     #define FT_ERROR_END_LIST       { 0, NULL } };                    */
+  /*                                                                       */
+  /*     const struct                                                      */
   /*     {                                                                 */
-  /*       #undef __FTERRORS_H__                                           */
-  /*       #define FT_ERRORDEF( e, v, s )  { e, s },                       */
-  /*       #define FT_ERROR_START_LIST     {                               */
-  /*       #define FT_ERROR_END_LIST       { 0, 0 } };                     */
+  /*       int          err_code;                                          */
+  /*       const char*  err_msg;                                           */
+  /*     } ft_errors[] =                                                   */
   /*                                                                       */
-  /*       const struct                                                    */
-  /*       {                                                               */
-  /*         int          err_code;                                        */
-  /*         const char*  err_msg;                                         */
-  /*       } ft_errors[] =                                                 */
+  /*     #include FT_ERRORS_H                                              */
+  /*   }                                                                   */
   /*                                                                       */
-  /*       #include FT_ERRORS_H                                            */
-  /*     }                                                                 */
+  /*   Note that `FT_Err_Ok' is _not_ defined with `FT_ERRORDEF' but with  */
+  /*   `FT_NOERRORDEF'; it is always zero.                                 */
   /*                                                                       */
   /*************************************************************************/
 
+  /* */
 
 #ifndef __FTERRORS_H__
 #define __FTERRORS_H__
diff --git a/include/ftfntfmt.h b/include/freetype/ftfntfmt.h
similarity index 100%
rename from include/ftfntfmt.h
rename to include/freetype/ftfntfmt.h
diff --git a/include/ftgasp.h b/include/freetype/ftgasp.h
similarity index 100%
rename from include/ftgasp.h
rename to include/freetype/ftgasp.h
diff --git a/include/ftglyph.h b/include/freetype/ftglyph.h
similarity index 100%
rename from include/ftglyph.h
rename to include/freetype/ftglyph.h
diff --git a/include/ftgxval.h b/include/freetype/ftgxval.h
similarity index 100%
rename from include/ftgxval.h
rename to include/freetype/ftgxval.h
diff --git a/include/ftgzip.h b/include/freetype/ftgzip.h
similarity index 100%
rename from include/ftgzip.h
rename to include/freetype/ftgzip.h
diff --git a/include/ftimage.h b/include/freetype/ftimage.h
similarity index 100%
rename from include/ftimage.h
rename to include/freetype/ftimage.h
diff --git a/include/ftincrem.h b/include/freetype/ftincrem.h
similarity index 100%
rename from include/ftincrem.h
rename to include/freetype/ftincrem.h
diff --git a/include/ftlcdfil.h b/include/freetype/ftlcdfil.h
similarity index 60%
rename from include/ftlcdfil.h
rename to include/freetype/ftlcdfil.h
index 4cd999a..a9dd3ea 100644
--- a/include/ftlcdfil.h
+++ b/include/freetype/ftlcdfil.h
@@ -41,56 +41,78 @@
    *   LCD Filtering
    *
    * @abstract:
-   *   Reduce color fringes of LCD-optimized bitmaps.
+   *   Reduce color fringes of subpixel-rendered bitmaps.
    *
    * @description:
-   *   The @FT_Library_SetLcdFilter API can be used to specify a low-pass
-   *   filter, which is then applied to LCD-optimized bitmaps generated
-   *   through @FT_Render_Glyph.  This is useful to reduce color fringes
-   *   that would occur with unfiltered rendering.
+   *   Subpixel rendering exploits the color-striped structure of LCD
+   *   pixels, increasing the available resolution in the direction of the
+   *   stripe (usually horizontal RGB) by a factor of~3.  Since these
+   *   subpixels are color pixels, using them unfiltered creates severe
+   *   color fringes.  Use the @FT_Library_SetLcdFilter API to specify a
+   *   low-pass filter, which is then applied to subpixel-rendered bitmaps
+   *   generated through @FT_Render_Glyph.  The filter sacrifices some of
+   *   the higher resolution to reduce color fringes, making the glyph image
+   *   slightly blurrier.  Positional improvements will remain.
    *
    *   Note that no filter is active by default, and that this function is
    *   *not* implemented in default builds of the library.  You need to
    *   #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your `ftoption.h' file
    *   in order to activate it.
    *
-   *   FreeType generates alpha coverage maps, which are linear by nature.
-   *   For instance, the value 0x80 in bitmap representation means that
-   *   (within numerical precision) 0x80/0xFF fraction of that pixel is
-   *   covered by the glyph's outline.  The blending function for placing
-   *   text over a background is
+   *   A filter should have two properties:
    *
-   *   {
-   *     dst = alpha * src + (1 - alpha) * dst    ,
-   *   }
+   *   1) It should be normalized, meaning the sum of the 5~components
+   *      should be 256 (0x100).  It is possible to go above or under this
+   *      target sum, however: going under means tossing out contrast, going
+   *      over means invoking clamping and thereby non-linearities that
+   *      increase contrast somewhat at the expense of greater distortion
+   *      and color-fringing.  Contrast is better enhanced through stem
+   *      darkening.
    *
-   *   which is known as OVER.  However, when calculating the output of the
-   *   OVER operator, the source colors should first be transformed to a
-   *   linear color space, then alpha blended in that space, and transformed
-   *   back to the output color space.
+   *   2) It should be color-balanced, meaning a filter `{~a, b, c, b, a~}'
+   *      where a~+ b~=~c.  It distributes the computed coverage for one
+   *      subpixel to all subpixels equally, sacrificing some won resolution
+   *      but drastically reducing color-fringing.  Positioning improvements
+   *      remain!  Note that color-fringing can only really be minimized
+   *      when using a color-balanced filter and alpha-blending the glyph
+   *      onto a surface in linear space; see @FT_Render_Glyph.
    *
-   *   When linear light blending is used, the default FIR5 filtering
-   *   weights (as given by FT_LCD_FILTER_DEFAULT) are no longer optimal, as
-   *   they have been designed for black on white rendering while lacking
-   *   gamma correction.  To preserve color neutrality, weights for a FIR5
-   *   filter should be chosen according to two free parameters `a' and `c',
-   *   and the FIR weights should be
+   *   Regarding the form, a filter can be a `boxy' filter or a `beveled'
+   *   filter.  Boxy filters are sharper but are less forgiving of non-ideal
+   *   gamma curves of a screen (viewing angles!), beveled filters are
+   *   fuzzier but more tolerant.
    *
-   *   {
-   *     [a - c, a + c, 2 * a, a + c, a - c]    .
-   *   }
+   *   Examples:
    *
-   *   This formula generates equal weights for all the color primaries
-   *   across the filter kernel, which makes it colorless.  One suggested
-   *   set of weights is
+   *   - [0x10 0x40 0x70 0x40 0x10] is beveled and neither balanced nor
+   *     normalized.
    *
-   *   {
-   *     [0x10, 0x50, 0x60, 0x50, 0x10]    ,
-   *   }
+   *   - [0x1A 0x33 0x4D 0x33 0x1A] is beveled and balanced but not
+   *     normalized.
    *
-   *   where `a' has value 0x30 and `b' value 0x20.  The weights in filter
-   *   may have a sum larger than 0x100, which increases coloration slightly
-   *   but also improves contrast.
+   *   - [0x19 0x33 0x66 0x4c 0x19] is beveled and normalized but not
+   *     balanced.
+   *
+   *   - [0x00 0x4c 0x66 0x4c 0x00] is boxily beveled and normalized but not
+   *     balanced.
+   *
+   *   - [0x00 0x55 0x56 0x55 0x00] is boxy, normalized, and almost
+   *     balanced.
+   *
+   *   - [0x08 0x4D 0x56 0x4D 0x08] is beveled, normalized and, almost
+   *     balanced.
+   *
+   *   It is important to understand that linear alpha blending and gamma
+   *   correction is critical for correctly rendering glyphs onto surfaces
+   *   without artifacts and even more critical when subpixel rendering is
+   *   involved.
+   *
+   *   Each of the 3~alpha values (subpixels) is independently used to blend
+   *   one color channel.  That is, red alpha blends the red channel of the
+   *   text color with the red channel of the background pixel.  The
+   *   distribution of density values by the color-balanced filter assumes
+   *   alpha blending is done in linear space; only then color artifacts
+   *   cancel out.
    */
 
 
@@ -111,10 +133,21 @@
    *     The default filter reduces color fringes considerably, at the cost
    *     of a slight blurriness in the output.
    *
+   *     It is a beveled, normalized, and color-balanced five-tap filter
+   *     that is more forgiving to screens with non-ideal gamma curves and
+   *     viewing angles.  Note that while color-fringing is reduced, it can
+   *     only be minimized by using linear alpha blending and gamma
+   *     correction to render glyphs onto surfaces.
+   *
    *   FT_LCD_FILTER_LIGHT ::
-   *     The light filter is a variant that produces less blurriness at the
-   *     cost of slightly more color fringes than the default one.  It might
-   *     be better, depending on taste, your monitor, or your personal vision.
+   *     The light filter is a variant that is sharper at the cost of
+   *     slightly more color fringes than the default one.
+   *
+   *     It is a boxy, normalized, and color-balanced three-tap filter that
+   *     is less forgiving to screens with non-ideal gamma curves and
+   *     viewing angles.  This filter works best when the rendering system
+   *     uses linear alpha blending and gamma correction to render glyphs
+   *     onto surfaces.
    *
    *   FT_LCD_FILTER_LEGACY ::
    *     This filter corresponds to the original libXft color filter.  It
@@ -126,14 +159,23 @@
    *     This filter is only provided for comparison purposes, and might be
    *     disabled or stay unsupported in the future.
    *
+   *   FT_LCD_FILTER_LEGACY1 ::
+   *     For historical reasons, the FontConfig library returns a different
+   *     enumeration value for legacy LCD filtering.  To make code work that
+   *     (incorrectly) forwards FontConfig's enumeration value to
+   *     @FT_Library_SetLcdFilter without proper mapping, it is thus easiest
+   *     to have another enumeration value, which is completely equal to
+   *     `FT_LCD_FILTER_LEGACY'.
+   *
    * @since:
-   *   2.3.0
+   *   2.3.0 (`FT_LCD_FILTER_LEGACY1' since 2.6.2)
    */
   typedef enum  FT_LcdFilter_
   {
     FT_LCD_FILTER_NONE    = 0,
     FT_LCD_FILTER_DEFAULT = 1,
     FT_LCD_FILTER_LIGHT   = 2,
+    FT_LCD_FILTER_LEGACY1 = 3,
     FT_LCD_FILTER_LEGACY  = 16,
 
     FT_LCD_FILTER_MAX   /* do not remove */
@@ -208,9 +250,8 @@
    * @description:
    *   Use this function to override the filter weights selected by
    *   @FT_Library_SetLcdFilter.  By default, FreeType uses the quintuple
-   *   (0x00, 0x55, 0x56, 0x55, 0x00) for FT_LCD_FILTER_LIGHT, and (0x10,
-   *   0x40, 0x70, 0x40, 0x10) for FT_LCD_FILTER_DEFAULT and
-   *   FT_LCD_FILTER_LEGACY.
+   *   (0x00, 0x55, 0x56, 0x55, 0x00) for FT_LCD_FILTER_LIGHT, and (0x08,
+   *   0x4D, 0x56, 0x4D, 0x08) for FT_LCD_FILTER_DEFAULT.
    *
    * @input:
    *   library ::
diff --git a/include/ftlist.h b/include/freetype/ftlist.h
similarity index 100%
rename from include/ftlist.h
rename to include/freetype/ftlist.h
diff --git a/include/ftlzw.h b/include/freetype/ftlzw.h
similarity index 100%
rename from include/ftlzw.h
rename to include/freetype/ftlzw.h
diff --git a/include/ftmac.h b/include/freetype/ftmac.h
similarity index 100%
rename from include/ftmac.h
rename to include/freetype/ftmac.h
diff --git a/include/ftmm.h b/include/freetype/ftmm.h
similarity index 97%
rename from include/ftmm.h
rename to include/freetype/ftmm.h
index 6ef4798..96dd66e 100644
--- a/include/ftmm.h
+++ b/include/freetype/ftmm.h
@@ -203,9 +203,13 @@
   /*                                                                       */
   /*    axis            :: An axis descriptor table.                       */
   /*                       GX fonts contain slightly more data than MM.    */
+  /*                       Memory management of this pointer is done       */
+  /*                       internally by FreeType.                         */
   /*                                                                       */
   /*    namedstyle      :: A named style table.                            */
   /*                       Only meaningful with GX.                        */
+  /*                       Memory management of this pointer is done       */
+  /*                       internally by FreeType.                         */
   /*                                                                       */
   typedef struct  FT_MM_Var_
   {
@@ -255,7 +259,8 @@
   /*                                                                       */
   /* <Output>                                                              */
   /*    amaster :: The Multiple Masters/GX var descriptor.                 */
-  /*               Allocates a data structure, which the user must free.   */
+  /*               Allocates a data structure, which the user must         */
+  /*               deallocate with `free' after use.                       */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0~means success.                             */
diff --git a/include/ftmodapi.h b/include/freetype/ftmodapi.h
similarity index 97%
rename from include/ftmodapi.h
rename to include/freetype/ftmodapi.h
index 2ef3f46..89d9347 100644
--- a/include/ftmodapi.h
+++ b/include/freetype/ftmodapi.h
@@ -63,7 +63,7 @@
   /*      psaux                                                            */
   /*      pshinter                                                         */
   /*      psnames                                                          */
-  /*      raster1, raster5                                                 */
+  /*      raster1                                                          */
   /*      sfnt                                                             */
   /*      smooth, smooth-lcd, smooth-lcdv                                  */
   /*      truetype                                                         */
@@ -111,12 +111,14 @@
 #define FT_MODULE_HINTER              4  /* this module is a glyph hinter */
 #define FT_MODULE_STYLER              8  /* this module is a styler       */
 
-#define FT_MODULE_DRIVER_SCALABLE     0x100   /* the driver supports      */
+#define FT_MODULE_DRIVER_SCALABLE      0x100  /* the driver supports      */
                                               /* scalable fonts           */
-#define FT_MODULE_DRIVER_NO_OUTLINES  0x200   /* the driver does not      */
+#define FT_MODULE_DRIVER_NO_OUTLINES   0x200  /* the driver does not      */
                                               /* support vector outlines  */
-#define FT_MODULE_DRIVER_HAS_HINTER   0x400   /* the driver provides its  */
+#define FT_MODULE_DRIVER_HAS_HINTER    0x400  /* the driver provides its  */
                                               /* own hinter               */
+#define FT_MODULE_DRIVER_HINTS_LIGHTLY 0x800  /* the driver's hinter      */
+                                              /* produces LIGHT hints     */
 
 
   /* deprecated values */
@@ -125,9 +127,10 @@
 #define ft_module_hinter              FT_MODULE_HINTER
 #define ft_module_styler              FT_MODULE_STYLER
 
-#define ft_module_driver_scalable     FT_MODULE_DRIVER_SCALABLE
-#define ft_module_driver_no_outlines  FT_MODULE_DRIVER_NO_OUTLINES
-#define ft_module_driver_has_hinter   FT_MODULE_DRIVER_HAS_HINTER
+#define ft_module_driver_scalable       FT_MODULE_DRIVER_SCALABLE
+#define ft_module_driver_no_outlines    FT_MODULE_DRIVER_NO_OUTLINES
+#define ft_module_driver_has_hinter     FT_MODULE_DRIVER_HAS_HINTER
+#define ft_module_driver_hints_lightly  FT_MODULE_DRIVER_HINTS_LIGHTLY
 
 
   typedef FT_Pointer  FT_Module_Interface;
diff --git a/include/ftmoderr.h b/include/freetype/ftmoderr.h
similarity index 100%
rename from include/ftmoderr.h
rename to include/freetype/ftmoderr.h
diff --git a/include/ftotval.h b/include/freetype/ftotval.h
similarity index 100%
rename from include/ftotval.h
rename to include/freetype/ftotval.h
diff --git a/include/ftoutln.h b/include/freetype/ftoutln.h
similarity index 99%
rename from include/ftoutln.h
rename to include/freetype/ftoutln.h
index 106cfde..b6ec70d 100644
--- a/include/ftoutln.h
+++ b/include/freetype/ftoutln.h
@@ -354,8 +354,8 @@
   /*                                                                       */
   /*    {                                                                  */
   /*      FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );                   */
-  /*      if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE )             */
-  /*        FT_Outline_Embolden( &face->slot->outline, strength );         */
+  /*      if ( face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )            */
+  /*        FT_Outline_Embolden( &face->glyph->outline, strength );        */
   /*    }                                                                  */
   /*                                                                       */
   /*    To get meaningful results, font scaling values must be set with    */
diff --git a/include/ftpfr.h b/include/freetype/ftpfr.h
similarity index 100%
rename from include/ftpfr.h
rename to include/freetype/ftpfr.h
diff --git a/include/ftrender.h b/include/freetype/ftrender.h
similarity index 100%
rename from include/ftrender.h
rename to include/freetype/ftrender.h
diff --git a/include/ftsizes.h b/include/freetype/ftsizes.h
similarity index 100%
rename from include/ftsizes.h
rename to include/freetype/ftsizes.h
diff --git a/include/ftsnames.h b/include/freetype/ftsnames.h
similarity index 100%
rename from include/ftsnames.h
rename to include/freetype/ftsnames.h
diff --git a/include/ftstroke.h b/include/freetype/ftstroke.h
similarity index 100%
rename from include/ftstroke.h
rename to include/freetype/ftstroke.h
diff --git a/include/ftsynth.h b/include/freetype/ftsynth.h
similarity index 100%
rename from include/ftsynth.h
rename to include/freetype/ftsynth.h
diff --git a/include/ftsystem.h b/include/freetype/ftsystem.h
similarity index 100%
rename from include/ftsystem.h
rename to include/freetype/ftsystem.h
diff --git a/include/fttrigon.h b/include/freetype/fttrigon.h
similarity index 98%
rename from include/fttrigon.h
rename to include/freetype/fttrigon.h
index 3d821ba..485ec51 100644
--- a/include/fttrigon.h
+++ b/include/freetype/fttrigon.h
@@ -225,8 +225,8 @@
    *
    * @description:
    *   Return the unit vector corresponding to a given angle.  After the
-   *   call, the value of `vec.x' will be `sin(angle)', and the value of
-   *   `vec.y' will be `cos(angle)'.
+   *   call, the value of `vec.x' will be `cos(angle)', and the value of
+   *   `vec.y' will be `sin(angle)'.
    *
    *   This function is useful to retrieve both the sinus and cosinus of a
    *   given angle quickly.
diff --git a/include/ftttdrv.h b/include/freetype/ftttdrv.h
similarity index 71%
rename from include/ftttdrv.h
rename to include/freetype/ftttdrv.h
index f56040b..dc0081a 100644
--- a/include/ftttdrv.h
+++ b/include/freetype/ftttdrv.h
@@ -52,6 +52,83 @@
    *
    *   The TrueType driver's module name is `truetype'.
    *
+   *   We start with a list of definitions, kindly provided by Greg
+   *   Hitchcock.
+   *
+   *   _Bi-Level_ _Rendering_
+   *
+   *   Monochromatic rendering, exclusively used in the early days of
+   *   TrueType by both Apple and Microsoft.  Microsoft's GDI interface
+   *   supported hinting of the right-side bearing point, such that the
+   *   advance width could be non-linear.  Most often this was done to
+   *   achieve some level of glyph symmetry.  To enable reasonable
+   *   performance (e.g., not having to run hinting on all glyphs just to
+   *   get the widths) there was a bit in the head table indicating if the
+   *   side bearing was hinted, and additional tables, `hdmx' and `LTSH', to
+   *   cache hinting widths across multiple sizes and device aspect ratios.
+   *
+   *   _Font_ _Smoothing_
+   *
+   *   Microsoft's GDI implementation of anti-aliasing.  Not traditional
+   *   anti-aliasing as the outlines were hinted before the sampling.  The
+   *   widths matched the bi-level rendering.
+   *
+   *   _ClearType_ _Rendering_
+   *
+   *   Technique that uses physical subpixels to improve rendering on LCD
+   *   (and other) displays.  Because of the higher resolution, many methods
+   *   of improving symmetry in glyphs through hinting the right-side
+   *   bearing were no longer necessary.  This lead to what GDI calls
+   *   `natural widths' ClearType, see
+   *   http://www.beatstamm.com/typography/RTRCh4.htm#Sec21.  Since hinting
+   *   has extra resolution, most non-linearity went away, but it is still
+   *   possible for hints to change the advance widths in this mode.
+   *
+   *   _ClearType_ _Compatible_ _Widths_
+   *
+   *   One of the earliest challenges with ClearType was allowing the
+   *   implementation in GDI to be selected without requiring all UI and
+   *   documents to reflow.  To address this, a compatible method of
+   *   rendering ClearType was added where the font hints are executed once
+   *   to determine the width in bi-level rendering, and then re-run in
+   *   ClearType, with the difference in widths being absorbed in the font
+   *   hints for ClearType (mostly in the white space of hints); see
+   *   http://www.beatstamm.com/typography/RTRCh4.htm#Sec20.  Somewhat by
+   *   definition, compatible width ClearType allows for non-linear widths,
+   *   but only when the bi-level version has non-linear widths.
+   *
+   *   _ClearType_ _Subpixel_ _Positioning_
+   *
+   *   One of the nice benefits of ClearType is the ability to more crisply
+   *   display fractional widths; unfortunately, the GDI model of integer
+   *   bitmaps did not support this.  However, the WPF and Direct Write
+   *   frameworks do support fractional widths.  DWrite calls this `natural
+   *   mode', not to be confused with GDI's `natural widths'.  Subpixel
+   *   positioning, in the current implementation of Direct Write,
+   *   unfortunately does not support hinted advance widths, see
+   *   http://www.beatstamm.com/typography/RTRCh4.htm#Sec22.  Note that the
+   *   TrueType interpreter fully allows the advance width to be adjusted in
+   *   this mode, just the DWrite client will ignore those changes.
+   *
+   *   _ClearType_ _Backwards_ _Compatibility_
+   *
+   *   This is a set of exceptions made in the TrueType interpreter to
+   *   minimize hinting techniques that were problematic with the extra
+   *   resolution of ClearType; see
+   *   http://www.beatstamm.com/typography/RTRCh4.htm#Sec1 and
+   *   http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx.
+   *   This technique is not to be confused with ClearType compatible
+   *   widths.  ClearType backwards compatibility has no direct impact on
+   *   changing advance widths, but there might be an indirect impact on
+   *   disabling some deltas.  This could be worked around in backwards
+   *   compatibility mode.
+   *
+   *   _Native_ _ClearType_ _Mode_
+   *
+   *   (Not to be confused with `natural widths'.)  This mode removes all
+   *   the exceptions in the TrueType interpreter when running with
+   *   ClearType.  Any issues on widths would still apply, though.
+   *
    */
 
 
diff --git a/include/fttypes.h b/include/freetype/fttypes.h
similarity index 100%
rename from include/fttypes.h
rename to include/freetype/fttypes.h
diff --git a/include/ftwinfnt.h b/include/freetype/ftwinfnt.h
similarity index 100%
rename from include/ftwinfnt.h
rename to include/freetype/ftwinfnt.h
diff --git a/include/internal/autohint.h b/include/freetype/internal/autohint.h
similarity index 100%
rename from include/internal/autohint.h
rename to include/freetype/internal/autohint.h
diff --git a/include/internal/ftcalc.h b/include/freetype/internal/ftcalc.h
similarity index 95%
rename from include/internal/ftcalc.h
rename to include/freetype/internal/ftcalc.h
index 75752c3..a76682b 100644
--- a/include/internal/ftcalc.h
+++ b/include/freetype/internal/ftcalc.h
@@ -47,7 +47,7 @@
   FT_MulFix_arm( FT_Int32  a,
                  FT_Int32  b )
   {
-    register FT_Int32  t, t2;
+    FT_Int32  t, t2;
 
 
     __asm
@@ -80,7 +80,7 @@
   FT_MulFix_arm( FT_Int32  a,
                  FT_Int32  b )
   {
-    register FT_Int32  t, t2;
+    FT_Int32  t, t2;
 
 
     __asm__ __volatile__ (
@@ -116,7 +116,7 @@
   FT_MulFix_i386( FT_Int32  a,
                   FT_Int32  b )
   {
-    register FT_Int32  result;
+    FT_Int32  result;
 
 
     __asm__ __volatile__ (
@@ -152,7 +152,7 @@
   FT_MulFix_i386( FT_Int32  a,
                   FT_Int32  b )
   {
-    register FT_Int32  result;
+    FT_Int32  result;
 
     __asm
     {
@@ -300,6 +300,18 @@
 
 
   /*
+   *  This function normalizes a vector and returns its original length.
+   *  The normalized vector is a 16.16 fixed-point unit vector with length
+   *  close to 0x10000.  The accuracy of the returned length is limited to
+   *  16 bits also.  The function utilizes quick inverse square root
+   *  approximation without divisions and square roots relying on Newton's
+   *  iterations instead.
+   */
+  FT_BASE( FT_UInt32 )
+  FT_Vector_NormLen( FT_Vector*  vector );
+
+
+  /*
    *  Return -1, 0, or +1, depending on the orientation of a given corner.
    *  We use the Cartesian coordinate system, with positive vertical values
    *  going upwards.  The function returns +1 if the corner turns to the
diff --git a/include/internal/ftdebug.h b/include/freetype/internal/ftdebug.h
similarity index 100%
rename from include/internal/ftdebug.h
rename to include/freetype/internal/ftdebug.h
diff --git a/include/internal/ftdriver.h b/include/freetype/internal/ftdriver.h
similarity index 100%
rename from include/internal/ftdriver.h
rename to include/freetype/internal/ftdriver.h
diff --git a/include/internal/ftgloadr.h b/include/freetype/internal/ftgloadr.h
similarity index 100%
rename from include/internal/ftgloadr.h
rename to include/freetype/internal/ftgloadr.h
diff --git a/include/internal/ftmemory.h b/include/freetype/internal/ftmemory.h
similarity index 100%
rename from include/internal/ftmemory.h
rename to include/freetype/internal/ftmemory.h
diff --git a/include/internal/ftobjs.h b/include/freetype/internal/ftobjs.h
similarity index 99%
rename from include/internal/ftobjs.h
rename to include/freetype/internal/ftobjs.h
index 37317a4..9a333fc 100644
--- a/include/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -83,12 +83,12 @@
             x > y ? x + ( 3 * y >> 3 )   \
                   : y + ( 3 * x >> 3 ) )
 
-  /* we use the TYPEOF macro to suppress signedness compilation warnings */
-#define FT_PAD_FLOOR( x, n )  ( (x) & ~TYPEOF( x )( (n)-1 ) )
+  /* we use FT_TYPEOF to suppress signedness compilation warnings */
+#define FT_PAD_FLOOR( x, n )  ( (x) & ~FT_TYPEOF( x )( (n)-1 ) )
 #define FT_PAD_ROUND( x, n )  FT_PAD_FLOOR( (x) + ((n)/2), n )
 #define FT_PAD_CEIL( x, n )   FT_PAD_FLOOR( (x) + ((n)-1), n )
 
-#define FT_PIX_FLOOR( x )     ( (x) & ~TYPEOF( x )63 )
+#define FT_PIX_FLOOR( x )     ( (x) & ~FT_TYPEOF( x )63 )
 #define FT_PIX_ROUND( x )     FT_PIX_FLOOR( (x) + 32 )
 #define FT_PIX_CEIL( x )      FT_PIX_FLOOR( (x) + 63 )
 
@@ -506,6 +506,9 @@
 #define FT_DRIVER_HAS_HINTER( x )  ( FT_MODULE_CLASS( x )->module_flags & \
                                      FT_MODULE_DRIVER_HAS_HINTER )
 
+#define FT_DRIVER_HINTS_LIGHTLY( x )  ( FT_MODULE_CLASS( x )->module_flags & \
+                                        FT_MODULE_DRIVER_HINTS_LIGHTLY )
+
 
   /*************************************************************************/
   /*                                                                       */
diff --git a/include/internal/ftpic.h b/include/freetype/internal/ftpic.h
similarity index 100%
rename from include/internal/ftpic.h
rename to include/freetype/internal/ftpic.h
diff --git a/include/internal/ftrfork.h b/include/freetype/internal/ftrfork.h
similarity index 100%
rename from include/internal/ftrfork.h
rename to include/freetype/internal/ftrfork.h
diff --git a/include/internal/ftserv.h b/include/freetype/internal/ftserv.h
similarity index 96%
rename from include/internal/ftserv.h
rename to include/freetype/internal/ftserv.h
index 8f837e4..11a0c7f 100644
--- a/include/internal/ftserv.h
+++ b/include/freetype/internal/ftserv.h
@@ -734,24 +734,24 @@
    *  The header files containing the services.
    */
 
-#define FT_SERVICE_BDF_H                <internal/services/svbdf.h>
-#define FT_SERVICE_CID_H                <internal/services/svcid.h>
-#define FT_SERVICE_GLYPH_DICT_H         <internal/services/svgldict.h>
-#define FT_SERVICE_GX_VALIDATE_H        <internal/services/svgxval.h>
-#define FT_SERVICE_KERNING_H            <internal/services/svkern.h>
-#define FT_SERVICE_MULTIPLE_MASTERS_H   <internal/services/svmm.h>
-#define FT_SERVICE_OPENTYPE_VALIDATE_H  <internal/services/svotval.h>
-#define FT_SERVICE_PFR_H                <internal/services/svpfr.h>
-#define FT_SERVICE_POSTSCRIPT_CMAPS_H   <internal/services/svpscmap.h>
-#define FT_SERVICE_POSTSCRIPT_INFO_H    <internal/services/svpsinfo.h>
-#define FT_SERVICE_POSTSCRIPT_NAME_H    <internal/services/svpostnm.h>
-#define FT_SERVICE_PROPERTIES_H         <internal/services/svprop.h>
-#define FT_SERVICE_SFNT_H               <internal/services/svsfnt.h>
-#define FT_SERVICE_TRUETYPE_ENGINE_H    <internal/services/svtteng.h>
-#define FT_SERVICE_TT_CMAP_H            <internal/services/svttcmap.h>
-#define FT_SERVICE_WINFNT_H             <internal/services/svwinfnt.h>
-#define FT_SERVICE_FONT_FORMAT_H        <internal/services/svfntfmt.h>
-#define FT_SERVICE_TRUETYPE_GLYF_H      <internal/services/svttglyf.h>
+#define FT_SERVICE_BDF_H                <freetype/internal/services/svbdf.h>
+#define FT_SERVICE_CID_H                <freetype/internal/services/svcid.h>
+#define FT_SERVICE_GLYPH_DICT_H         <freetype/internal/services/svgldict.h>
+#define FT_SERVICE_GX_VALIDATE_H        <freetype/internal/services/svgxval.h>
+#define FT_SERVICE_KERNING_H            <freetype/internal/services/svkern.h>
+#define FT_SERVICE_MULTIPLE_MASTERS_H   <freetype/internal/services/svmm.h>
+#define FT_SERVICE_OPENTYPE_VALIDATE_H  <freetype/internal/services/svotval.h>
+#define FT_SERVICE_PFR_H                <freetype/internal/services/svpfr.h>
+#define FT_SERVICE_POSTSCRIPT_CMAPS_H   <freetype/internal/services/svpscmap.h>
+#define FT_SERVICE_POSTSCRIPT_INFO_H    <freetype/internal/services/svpsinfo.h>
+#define FT_SERVICE_POSTSCRIPT_NAME_H    <freetype/internal/services/svpostnm.h>
+#define FT_SERVICE_PROPERTIES_H         <freetype/internal/services/svprop.h>
+#define FT_SERVICE_SFNT_H               <freetype/internal/services/svsfnt.h>
+#define FT_SERVICE_TRUETYPE_ENGINE_H    <freetype/internal/services/svtteng.h>
+#define FT_SERVICE_TT_CMAP_H            <freetype/internal/services/svttcmap.h>
+#define FT_SERVICE_WINFNT_H             <freetype/internal/services/svwinfnt.h>
+#define FT_SERVICE_FONT_FORMAT_H        <freetype/internal/services/svfntfmt.h>
+#define FT_SERVICE_TRUETYPE_GLYF_H      <freetype/internal/services/svttglyf.h>
 
  /* */
 
diff --git a/include/internal/ftstream.h b/include/freetype/internal/ftstream.h
similarity index 100%
rename from include/internal/ftstream.h
rename to include/freetype/internal/ftstream.h
diff --git a/include/internal/fttrace.h b/include/freetype/internal/fttrace.h
similarity index 99%
rename from include/internal/fttrace.h
rename to include/freetype/internal/fttrace.h
index 9d28d21..2b0bf9d 100644
--- a/include/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -148,7 +148,7 @@
 FT_TRACE_DEF( aflatin )
 FT_TRACE_DEF( aflatin2 )
 FT_TRACE_DEF( afwarp )
-FT_TRACE_DEF( afharfbuzz )
+FT_TRACE_DEF( afshaper )
 FT_TRACE_DEF( afglobal )
 
 /* END */
diff --git a/include/internal/ftvalid.h b/include/freetype/internal/ftvalid.h
similarity index 100%
rename from include/internal/ftvalid.h
rename to include/freetype/internal/ftvalid.h
diff --git a/include/internal/internal.h b/include/freetype/internal/internal.h
similarity index 62%
rename from include/internal/internal.h
rename to include/freetype/internal/internal.h
index 1c1fd0e..809ce59 100644
--- a/include/internal/internal.h
+++ b/include/freetype/internal/internal.h
@@ -24,28 +24,28 @@
   /*************************************************************************/
 
 
-#define FT_INTERNAL_OBJECTS_H             <internal/ftobjs.h>
-#define FT_INTERNAL_PIC_H                 <internal/ftpic.h>
-#define FT_INTERNAL_STREAM_H              <internal/ftstream.h>
-#define FT_INTERNAL_MEMORY_H              <internal/ftmemory.h>
-#define FT_INTERNAL_DEBUG_H               <internal/ftdebug.h>
-#define FT_INTERNAL_CALC_H                <internal/ftcalc.h>
-#define FT_INTERNAL_DRIVER_H              <internal/ftdriver.h>
-#define FT_INTERNAL_TRACE_H               <internal/fttrace.h>
-#define FT_INTERNAL_GLYPH_LOADER_H        <internal/ftgloadr.h>
-#define FT_INTERNAL_SFNT_H                <internal/sfnt.h>
-#define FT_INTERNAL_SERVICE_H             <internal/ftserv.h>
-#define FT_INTERNAL_RFORK_H               <internal/ftrfork.h>
-#define FT_INTERNAL_VALIDATE_H            <internal/ftvalid.h>
+#define FT_INTERNAL_OBJECTS_H             <freetype/internal/ftobjs.h>
+#define FT_INTERNAL_PIC_H                 <freetype/internal/ftpic.h>
+#define FT_INTERNAL_STREAM_H              <freetype/internal/ftstream.h>
+#define FT_INTERNAL_MEMORY_H              <freetype/internal/ftmemory.h>
+#define FT_INTERNAL_DEBUG_H               <freetype/internal/ftdebug.h>
+#define FT_INTERNAL_CALC_H                <freetype/internal/ftcalc.h>
+#define FT_INTERNAL_DRIVER_H              <freetype/internal/ftdriver.h>
+#define FT_INTERNAL_TRACE_H               <freetype/internal/fttrace.h>
+#define FT_INTERNAL_GLYPH_LOADER_H        <freetype/internal/ftgloadr.h>
+#define FT_INTERNAL_SFNT_H                <freetype/internal/sfnt.h>
+#define FT_INTERNAL_SERVICE_H             <freetype/internal/ftserv.h>
+#define FT_INTERNAL_RFORK_H               <freetype/internal/ftrfork.h>
+#define FT_INTERNAL_VALIDATE_H            <freetype/internal/ftvalid.h>
 
-#define FT_INTERNAL_TRUETYPE_TYPES_H      <internal/tttypes.h>
-#define FT_INTERNAL_TYPE1_TYPES_H         <internal/t1types.h>
+#define FT_INTERNAL_TRUETYPE_TYPES_H      <freetype/internal/tttypes.h>
+#define FT_INTERNAL_TYPE1_TYPES_H         <freetype/internal/t1types.h>
 
-#define FT_INTERNAL_POSTSCRIPT_AUX_H      <internal/psaux.h>
-#define FT_INTERNAL_POSTSCRIPT_HINTS_H    <internal/pshints.h>
-#define FT_INTERNAL_POSTSCRIPT_GLOBALS_H  <internal/psglobal.h>
+#define FT_INTERNAL_POSTSCRIPT_AUX_H      <freetype/internal/psaux.h>
+#define FT_INTERNAL_POSTSCRIPT_HINTS_H    <freetype/internal/pshints.h>
+#define FT_INTERNAL_POSTSCRIPT_GLOBALS_H  <freetype/internal/psglobal.h>
 
-#define FT_INTERNAL_AUTOHINT_H            <internal/autohint.h>
+#define FT_INTERNAL_AUTOHINT_H            <freetype/internal/autohint.h>
 
 
 #if defined( _MSC_VER )      /* Visual C++ (and Intel C++) */
diff --git a/include/internal/psaux.h b/include/freetype/internal/psaux.h
similarity index 100%
rename from include/internal/psaux.h
rename to include/freetype/internal/psaux.h
diff --git a/include/internal/pshints.h b/include/freetype/internal/pshints.h
similarity index 100%
rename from include/internal/pshints.h
rename to include/freetype/internal/pshints.h
diff --git a/include/internal/services/svbdf.h b/include/freetype/internal/services/svbdf.h
similarity index 100%
rename from include/internal/services/svbdf.h
rename to include/freetype/internal/services/svbdf.h
diff --git a/include/internal/services/svcid.h b/include/freetype/internal/services/svcid.h
similarity index 100%
rename from include/internal/services/svcid.h
rename to include/freetype/internal/services/svcid.h
diff --git a/include/internal/services/svfntfmt.h b/include/freetype/internal/services/svfntfmt.h
similarity index 100%
rename from include/internal/services/svfntfmt.h
rename to include/freetype/internal/services/svfntfmt.h
diff --git a/include/internal/services/svgldict.h b/include/freetype/internal/services/svgldict.h
similarity index 100%
rename from include/internal/services/svgldict.h
rename to include/freetype/internal/services/svgldict.h
diff --git a/include/internal/services/svgxval.h b/include/freetype/internal/services/svgxval.h
similarity index 100%
rename from include/internal/services/svgxval.h
rename to include/freetype/internal/services/svgxval.h
diff --git a/include/internal/services/svkern.h b/include/freetype/internal/services/svkern.h
similarity index 100%
rename from include/internal/services/svkern.h
rename to include/freetype/internal/services/svkern.h
diff --git a/include/internal/services/svmm.h b/include/freetype/internal/services/svmm.h
similarity index 100%
rename from include/internal/services/svmm.h
rename to include/freetype/internal/services/svmm.h
diff --git a/include/internal/services/svotval.h b/include/freetype/internal/services/svotval.h
similarity index 100%
rename from include/internal/services/svotval.h
rename to include/freetype/internal/services/svotval.h
diff --git a/include/internal/services/svpfr.h b/include/freetype/internal/services/svpfr.h
similarity index 100%
rename from include/internal/services/svpfr.h
rename to include/freetype/internal/services/svpfr.h
diff --git a/include/internal/services/svpostnm.h b/include/freetype/internal/services/svpostnm.h
similarity index 100%
rename from include/internal/services/svpostnm.h
rename to include/freetype/internal/services/svpostnm.h
diff --git a/include/internal/services/svprop.h b/include/freetype/internal/services/svprop.h
similarity index 100%
rename from include/internal/services/svprop.h
rename to include/freetype/internal/services/svprop.h
diff --git a/include/internal/services/svpscmap.h b/include/freetype/internal/services/svpscmap.h
similarity index 100%
rename from include/internal/services/svpscmap.h
rename to include/freetype/internal/services/svpscmap.h
diff --git a/include/internal/services/svpsinfo.h b/include/freetype/internal/services/svpsinfo.h
similarity index 100%
rename from include/internal/services/svpsinfo.h
rename to include/freetype/internal/services/svpsinfo.h
diff --git a/include/internal/services/svsfnt.h b/include/freetype/internal/services/svsfnt.h
similarity index 100%
rename from include/internal/services/svsfnt.h
rename to include/freetype/internal/services/svsfnt.h
diff --git a/include/internal/services/svttcmap.h b/include/freetype/internal/services/svttcmap.h
similarity index 95%
rename from include/internal/services/svttcmap.h
rename to include/freetype/internal/services/svttcmap.h
index 4351a9a..cd95b9a 100644
--- a/include/internal/services/svttcmap.h
+++ b/include/freetype/internal/services/svttcmap.h
@@ -48,11 +48,12 @@
   /*      `ttnameid.h'.                                                    */
   /*                                                                       */
   /*    format ::                                                          */
-  /*      The cmap format.  OpenType 1.5 defines the formats 0 (byte       */
+  /*      The cmap format.  OpenType 1.6 defines the formats 0 (byte       */
   /*      encoding table), 2~(high-byte mapping through table), 4~(segment */
   /*      mapping to delta values), 6~(trimmed table mapping), 8~(mixed    */
   /*      16-bit and 32-bit coverage), 10~(trimmed array), 12~(segmented   */
-  /*      coverage), and 14 (Unicode Variation Sequences).                 */
+  /*      coverage), 13~(last resort font), and 14 (Unicode Variation      */
+  /*      Sequences).                                                      */
   /*                                                                       */
   typedef struct  TT_CMapInfo_
   {
diff --git a/include/internal/services/svtteng.h b/include/freetype/internal/services/svtteng.h
similarity index 100%
rename from include/internal/services/svtteng.h
rename to include/freetype/internal/services/svtteng.h
diff --git a/include/internal/services/svttglyf.h b/include/freetype/internal/services/svttglyf.h
similarity index 100%
rename from include/internal/services/svttglyf.h
rename to include/freetype/internal/services/svttglyf.h
diff --git a/include/internal/services/svwinfnt.h b/include/freetype/internal/services/svwinfnt.h
similarity index 100%
rename from include/internal/services/svwinfnt.h
rename to include/freetype/internal/services/svwinfnt.h
diff --git a/include/internal/sfnt.h b/include/freetype/internal/sfnt.h
similarity index 93%
rename from include/internal/sfnt.h
rename to include/freetype/internal/sfnt.h
index 97ce390..30f53bf 100644
--- a/include/internal/sfnt.h
+++ b/include/freetype/internal/sfnt.h
@@ -44,7 +44,9 @@
   /*    face       :: A handle to the target face object.                  */
   /*                                                                       */
   /*    face_index :: The index of the TrueType font, if we are opening a  */
-  /*                  collection.                                          */
+  /*                  collection, in bits 0-15.  The numbered instance     */
+  /*                  index~+~1 of a GX (sub)font, if applicable, in bits  */
+  /*                  16-30.                                               */
   /*                                                                       */
   /*    num_params :: The number of additional parameters.                 */
   /*                                                                       */
@@ -87,7 +89,9 @@
   /*    face       :: A handle to the target face object.                  */
   /*                                                                       */
   /*    face_index :: The index of the TrueType font, if we are opening a  */
-  /*                  collection.                                          */
+  /*                  collection, in bits 0-15.  The numbered instance     */
+  /*                  index~+~1 of a GX (sub)font, if applicable, in bits  */
+  /*                  16-30.                                               */
   /*                                                                       */
   /*    num_params :: The number of additional parameters.                 */
   /*                                                                       */
@@ -427,6 +431,33 @@
   /*************************************************************************/
   /*                                                                       */
   /* <FuncType>                                                            */
+  /*    TT_Get_Name_Func                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    From the `name' table, return a given ENGLISH name record in       */
+  /*    ASCII.                                                             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the source face object.                    */
+  /*                                                                       */
+  /*    nameid   :: The name id of the name record to return.              */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    name     :: The address of an allocated string pointer.  NULL if   */
+  /*                no name is present.                                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  typedef FT_Error
+  (*TT_Get_Name_Func)( TT_Face      face,
+                       FT_UShort    nameid,
+                       FT_String**  name );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <FuncType>                                                            */
   /*    TT_Load_Table_Func                                                 */
   /*                                                                       */
   /* <Description>                                                         */
@@ -556,6 +587,8 @@
 
     TT_Get_Metrics_Func          get_metrics;
 
+    TT_Get_Name_Func             get_name;
+
   } SFNT_Interface;
 
 
@@ -594,7 +627,8 @@
           free_eblc_,                    \
           set_sbit_strike_,              \
           load_strike_metrics_,          \
-          get_metrics_ )                 \
+          get_metrics_,                  \
+          get_name_ )                    \
   static const SFNT_Interface  class_ =  \
   {                                      \
     goto_table_,                         \
@@ -626,6 +660,7 @@
     set_sbit_strike_,                    \
     load_strike_metrics_,                \
     get_metrics_,                        \
+    get_name_,                           \
   };
 
 #else /* FT_CONFIG_OPTION_PIC */
@@ -663,7 +698,8 @@
           free_eblc_,                                   \
           set_sbit_strike_,                             \
           load_strike_metrics_,                         \
-          get_metrics_ )                                \
+          get_metrics_,                                 \
+          get_name_ )                                   \
   void                                                  \
   FT_Init_Class_ ## class_( FT_Library       library,   \
                             SFNT_Interface*  clazz )    \
@@ -699,6 +735,7 @@
     clazz->set_sbit_strike     = set_sbit_strike_;      \
     clazz->load_strike_metrics = load_strike_metrics_;  \
     clazz->get_metrics         = get_metrics_;          \
+    clazz->get_name            = get_name_;             \
   }
 
 #endif /* FT_CONFIG_OPTION_PIC */
diff --git a/include/internal/t1types.h b/include/freetype/internal/t1types.h
similarity index 100%
rename from include/internal/t1types.h
rename to include/freetype/internal/t1types.h
diff --git a/include/internal/tttypes.h b/include/freetype/internal/tttypes.h
similarity index 98%
rename from include/internal/tttypes.h
rename to include/freetype/internal/tttypes.h
index 31dd0aa..000c5a8 100644
--- a/include/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1457,11 +1457,23 @@
   /* handle to execution context */
   typedef struct TT_ExecContextRec_*  TT_ExecContext;
 
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    TT_Size                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a TrueType size object.                                */
+  /*                                                                       */
+  typedef struct TT_SizeRec_*  TT_Size;
+
+
   /* glyph loader structure */
   typedef struct  TT_LoaderRec_
   {
-    FT_Face          face;
-    FT_Size          size;
+    TT_Face          face;
+    TT_Size          size;
     FT_GlyphSlot     glyph;
     FT_GlyphLoader   gloader;
 
@@ -1503,6 +1515,9 @@
     FT_Byte*         cursor;
     FT_Byte*         limit;
 
+    /* since version 2.6.2 */
+    FT_ListRec       composites;
+
   } TT_LoaderRec;
 
 
diff --git a/include/t1tables.h b/include/freetype/t1tables.h
similarity index 100%
rename from include/t1tables.h
rename to include/freetype/t1tables.h
diff --git a/include/ttnameid.h b/include/freetype/ttnameid.h
similarity index 100%
rename from include/ttnameid.h
rename to include/freetype/ttnameid.h
diff --git a/include/tttables.h b/include/freetype/tttables.h
similarity index 100%
rename from include/tttables.h
rename to include/freetype/tttables.h
diff --git a/include/tttags.h b/include/freetype/tttags.h
similarity index 100%
rename from include/tttags.h
rename to include/freetype/tttags.h
diff --git a/include/ttunpat.h b/include/freetype/ttunpat.h
similarity index 100%
rename from include/ttunpat.h
rename to include/freetype/ttunpat.h
diff --git a/include/ft2build.h b/include/ft2build.h
index 09c19d4..419b80a 100644
--- a/include/ft2build.h
+++ b/include/ft2build.h
@@ -34,7 +34,7 @@
 #ifndef __FT2BUILD_H__
 #define __FT2BUILD_H__
 
-#include <config/ftheader.h>
+#include <freetype/config/ftheader.h>
 
 #endif /* __FT2BUILD_H__ */
 
diff --git a/module_option.diff b/module_option.diff
new file mode 100644
index 0000000..75079ce
--- /dev/null
+++ b/module_option.diff
@@ -0,0 +1,57 @@
+diff --git a/include/freetype/config/ftmodule.h b/include/freetype/config/ftmodule.h
+index 76d271a..e145790 100644
+--- a/include/freetype/config/ftmodule.h
++++ b/include/freetype/config/ftmodule.h
+@@ -12,14 +12,7 @@
+ 
+ FT_USE_MODULE( FT_Module_Class, autofit_module_class )
+ FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class )
+-FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class )
+ FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class )
+-FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class )
+-FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class )
+-FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class )
+-FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class )
+-FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class )
+-FT_USE_MODULE( FT_Module_Class, psaux_module_class )
+ FT_USE_MODULE( FT_Module_Class, psnames_module_class )
+ FT_USE_MODULE( FT_Module_Class, pshinter_module_class )
+ FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class )
+@@ -27,6 +20,5 @@ FT_USE_MODULE( FT_Module_Class, sfnt_module_class )
+ FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class )
+ FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcd_renderer_class )
+ FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcdv_renderer_class )
+-FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class )
+ 
+ /* EOF */
+diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h
+index b481f8f..3819586 100644
+--- a/include/freetype/config/ftoption.h
++++ b/include/freetype/config/ftoption.h
+@@ -225,7 +225,7 @@ FT_BEGIN_HEADER
+   /*                                                                       */
+   /*   Define this macro if you want to enable this `feature'.             */
+   /*                                                                       */
+-/* #define FT_CONFIG_OPTION_USE_PNG */
++#define FT_CONFIG_OPTION_USE_PNG
+ 
+ 
+   /*************************************************************************/
+@@ -370,7 +370,7 @@ FT_BEGIN_HEADER
+   /* supply font data incrementally as the document is parsed, such        */
+   /* as the Ghostscript interpreter for the PostScript language.           */
+   /*                                                                       */
+-#define FT_CONFIG_OPTION_INCREMENTAL
++/* #define FT_CONFIG_OPTION_INCREMENTAL */
+ 
+ 
+   /*************************************************************************/
+@@ -843,7 +843,7 @@ FT_BEGIN_HEADER
+   /* `warping' property of the auto-hinter (see file `ftautoh.h' for more  */
+   /* information; by default it is switched off).                          */
+   /*                                                                       */
+-#define AF_CONFIG_OPTION_USE_WARPER
++/* #define AF_CONFIG_OPTION_USE_WARPER */
+ 
+   /* */
+ 
diff --git a/src/autofit/afblue.c b/src/autofit/afblue.c
index e2b2451..104ee17 100644
--- a/src/autofit/afblue.c
+++ b/src/autofit/afblue.c
@@ -26,107 +26,161 @@
   af_blue_strings[] =
   {
     /* */
-    '\xD8', '\xA7', '\xD8', '\xA5', '\xD9', '\x84', '\xD9', '\x83', '\xD8', '\xB7', '\xD8', '\xB8',  /* ا إ ل ك ط ظ */
+    '\xD8', '\xA7', ' ', '\xD8', '\xA5', ' ', '\xD9', '\x84', ' ', '\xD9', '\x83', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8',  /* ا إ ل ك ط ظ */
     '\0',
-    '\xD8', '\xAA', '\xD8', '\xAB', '\xD8', '\xB7', '\xD8', '\xB8', '\xD9', '\x83',  /* ت ث ط ظ ك */
+    '\xD8', '\xAA', ' ', '\xD8', '\xAB', ' ', '\xD8', '\xB7', ' ', '\xD8', '\xB8', ' ', '\xD9', '\x83',  /* ت ث ط ظ ك */
     '\0',
-    '\xD0', '\x91', '\xD0', '\x92', '\xD0', '\x95', '\xD0', '\x9F', '\xD0', '\x97', '\xD0', '\x9E', '\xD0', '\xA1', '\xD0', '\xAD',  /* БВЕПЗОСЭ */
+    '\xD9', '\x80',  /* ـ */
     '\0',
-    '\xD0', '\x91', '\xD0', '\x92', '\xD0', '\x95', '\xD0', '\xA8', '\xD0', '\x97', '\xD0', '\x9E', '\xD0', '\xA1', '\xD0', '\xAD',  /* БВЕШЗОСЭ */
+    '\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\x9F', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD',  /* Б В Е П З О С Э */
     '\0',
-    '\xD1', '\x85', '\xD0', '\xBF', '\xD0', '\xBD', '\xD1', '\x88', '\xD0', '\xB5', '\xD0', '\xB7', '\xD0', '\xBE', '\xD1', '\x81',  /* хпншезос */
+    '\xD0', '\x91', ' ', '\xD0', '\x92', ' ', '\xD0', '\x95', ' ', '\xD0', '\xA8', ' ', '\xD0', '\x97', ' ', '\xD0', '\x9E', ' ', '\xD0', '\xA1', ' ', '\xD0', '\xAD',  /* Б В Е Ш З О С Э */
     '\0',
-    '\xD1', '\x80', '\xD1', '\x83', '\xD1', '\x84',  /* руф */
+    '\xD1', '\x85', ' ', '\xD0', '\xBF', ' ', '\xD0', '\xBD', ' ', '\xD1', '\x88', ' ', '\xD0', '\xB5', ' ', '\xD0', '\xB7', ' ', '\xD0', '\xBE', ' ', '\xD1', '\x81',  /* х п н ш е з о с */
     '\0',
-    '\xE0', '\xA4', '\x95', '\xE0', '\xA4', '\xAE', '\xE0', '\xA4', '\x85', '\xE0', '\xA4', '\x86', '\xE0', '\xA4', '\xA5', '\xE0', '\xA4', '\xA7', '\xE0', '\xA4', '\xAD', '\xE0', '\xA4', '\xB6',  /* क म अ आ थ ध भ श */
+    '\xD1', '\x80', ' ', '\xD1', '\x83', ' ', '\xD1', '\x84',  /* р у ф */
     '\0',
-    '\xE0', '\xA4', '\x88', '\xE0', '\xA4', '\x90', '\xE0', '\xA4', '\x93', '\xE0', '\xA4', '\x94', '\xE0', '\xA4', '\xBF', '\xE0', '\xA5', '\x80', '\xE0', '\xA5', '\x8B', '\xE0', '\xA5', '\x8C',  /* ई ऐ ओ औ ि ी ो ौ */
+    '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x85', ' ', '\xE0', '\xA4', '\x86', ' ', '\xE0', '\xA4', '\xA5', ' ', '\xE0', '\xA4', '\xA7', ' ', '\xE0', '\xA4', '\xAD', ' ', '\xE0', '\xA4', '\xB6',  /* क म अ आ थ ध भ श */
     '\0',
-    '\xE0', '\xA4', '\x95', '\xE0', '\xA4', '\xAE', '\xE0', '\xA4', '\x85', '\xE0', '\xA4', '\x86', '\xE0', '\xA4', '\xA5', '\xE0', '\xA4', '\xA7', '\xE0', '\xA4', '\xAD', '\xE0', '\xA4', '\xB6',  /* क म अ आ थ ध भ श */
+    '\xE0', '\xA4', '\x88', ' ', '\xE0', '\xA4', '\x90', ' ', '\xE0', '\xA4', '\x93', ' ', '\xE0', '\xA4', '\x94', ' ', '\xE0', '\xA4', '\xBF', ' ', '\xE0', '\xA5', '\x80', ' ', '\xE0', '\xA5', '\x8B', ' ', '\xE0', '\xA5', '\x8C',  /* ई ऐ ओ औ ि ी ो ौ */
     '\0',
-    '\xE0', '\xA5', '\x81', '\xE0', '\xA5', '\x83',  /* ु ृ */
+    '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x85', ' ', '\xE0', '\xA4', '\x86', ' ', '\xE0', '\xA4', '\xA5', ' ', '\xE0', '\xA4', '\xA7', ' ', '\xE0', '\xA4', '\xAD', ' ', '\xE0', '\xA4', '\xB6',  /* क म अ आ थ ध भ श */
     '\0',
-    '\xCE', '\x93', '\xCE', '\x92', '\xCE', '\x95', '\xCE', '\x96', '\xCE', '\x98', '\xCE', '\x9F', '\xCE', '\xA9',  /* ΓΒΕΖΘΟΩ */
+    '\xE0', '\xA5', '\x81', ' ', '\xE0', '\xA5', '\x83',  /* ु ृ */
     '\0',
-    '\xCE', '\x92', '\xCE', '\x94', '\xCE', '\x96', '\xCE', '\x9E', '\xCE', '\x98', '\xCE', '\x9F',  /* ΒΔΖΞΘΟ */
+    '\xCE', '\x93', ' ', '\xCE', '\x92', ' ', '\xCE', '\x95', ' ', '\xCE', '\x96', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F', ' ', '\xCE', '\xA9',  /* Γ Β Ε Ζ Θ Ο Ω */
     '\0',
-    '\xCE', '\xB2', '\xCE', '\xB8', '\xCE', '\xB4', '\xCE', '\xB6', '\xCE', '\xBB', '\xCE', '\xBE',  /* βθδζλξ */
+    '\xCE', '\x92', ' ', '\xCE', '\x94', ' ', '\xCE', '\x96', ' ', '\xCE', '\x9E', ' ', '\xCE', '\x98', ' ', '\xCE', '\x9F',  /* Β Δ Ζ Ξ Θ Ο */
     '\0',
-    '\xCE', '\xB1', '\xCE', '\xB5', '\xCE', '\xB9', '\xCE', '\xBF', '\xCF', '\x80', '\xCF', '\x83', '\xCF', '\x84', '\xCF', '\x89',  /* αειοπστω */
+    '\xCE', '\xB2', ' ', '\xCE', '\xB8', ' ', '\xCE', '\xB4', ' ', '\xCE', '\xB6', ' ', '\xCE', '\xBB', ' ', '\xCE', '\xBE',  /* β θ δ ζ λ ξ */
     '\0',
-    '\xCE', '\xB2', '\xCE', '\xB3', '\xCE', '\xB7', '\xCE', '\xBC', '\xCF', '\x81', '\xCF', '\x86', '\xCF', '\x87', '\xCF', '\x88',  /* βγημρφχψ */
+    '\xCE', '\xB1', ' ', '\xCE', '\xB5', ' ', '\xCE', '\xB9', ' ', '\xCE', '\xBF', ' ', '\xCF', '\x80', ' ', '\xCF', '\x83', ' ', '\xCF', '\x84', ' ', '\xCF', '\x89',  /* α ε ι ο π σ τ ω */
     '\0',
-    '\xD7', '\x91', '\xD7', '\x93', '\xD7', '\x94', '\xD7', '\x97', '\xD7', '\x9A', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1',  /* בדהחךכםס */
+    '\xCE', '\xB2', ' ', '\xCE', '\xB3', ' ', '\xCE', '\xB7', ' ', '\xCE', '\xBC', ' ', '\xCF', '\x81', ' ', '\xCF', '\x86', ' ', '\xCF', '\x87', ' ', '\xCF', '\x88',  /* β γ η μ ρ φ χ ψ */
     '\0',
-    '\xD7', '\x91', '\xD7', '\x98', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1', '\xD7', '\xA6',  /* בטכםסצ */
+    '\xD7', '\x91', ' ', '\xD7', '\x93', ' ', '\xD7', '\x94', ' ', '\xD7', '\x97', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1',  /* ב ד ה ח ך כ ם ס */
     '\0',
-    '\xD7', '\xA7', '\xD7', '\x9A', '\xD7', '\x9F', '\xD7', '\xA3', '\xD7', '\xA5',  /* קךןףץ */
+    '\xD7', '\x91', ' ', '\xD7', '\x98', ' ', '\xD7', '\x9B', ' ', '\xD7', '\x9D', ' ', '\xD7', '\xA1', ' ', '\xD7', '\xA6',  /* ב ט כ ם ס צ */
     '\0',
-    'T', 'H', 'E', 'Z', 'O', 'C', 'Q', 'S',  /* THEZOCQS */
+    '\xD7', '\xA7', ' ', '\xD7', '\x9A', ' ', '\xD7', '\x9F', ' ', '\xD7', '\xA3', ' ', '\xD7', '\xA5',  /* ק ך ן ף ץ */
     '\0',
-    'H', 'E', 'Z', 'L', 'O', 'C', 'U', 'S',  /* HEZLOCUS */
+    '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x91', ' ', '\xE1', '\x9E', '\x93', ' ', '\xE1', '\x9E', '\xA7', ' ', '\xE1', '\x9E', '\xA9', ' ', '\xE1', '\x9E', '\xB6',  /* ខ ទ ន ឧ ឩ ា */
     '\0',
-    'f', 'i', 'j', 'k', 'd', 'b', 'h',  /* fijkdbh */
+    '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x80', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x82', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x90',  /* ក្ក ក្ខ ក្គ ក្ថ */
     '\0',
-    'x', 'z', 'r', 'o', 'e', 's', 'c',  /* xzroesc */
+    '\xE1', '\x9E', '\x81', ' ', '\xE1', '\x9E', '\x83', ' ', '\xE1', '\x9E', '\x85', ' ', '\xE1', '\x9E', '\x8B', ' ', '\xE1', '\x9E', '\x94', ' ', '\xE1', '\x9E', '\x98', ' ', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xB2',  /* ខ ឃ ច ឋ ប ម យ ឲ */
     '\0',
-    'p', 'q', 'g', 'j', 'y',  /* pqgjy */
+    '\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', ' ', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\xB2', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\xA2', '\xE1', '\x9E', '\xBF',  /* ត្រ រៀ ឲ្យ អឿ */
     '\0',
-    '\xE0', '\xB0', '\x87', '\xE0', '\xB0', '\x8C', '\xE0', '\xB0', '\x99', '\xE0', '\xB0', '\x9E', '\xE0', '\xB0', '\xA3', '\xE0', '\xB0', '\xB1', '\xE0', '\xB1', '\xAF',  /* ఇ ఌ ఙ ఞ ణ ఱ ౯ */
+    '\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x83', ' ', '\xE1', '\x9E', '\x84', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x81', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x99', ' ', '\xE1', '\x9E', '\x80', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x85', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x9A', '\xE1', '\x9F', '\x80', ' ', '\xE1', '\x9E', '\x93', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x8F', '\xE1', '\x9E', '\xBF', ' ', '\xE1', '\x9E', '\x9B', '\xE1', '\x9F', '\x92', '\xE1', '\x9E', '\x94', '\xE1', '\x9E', '\xBF',  /* ន្ត្រៃ ង្ខ្យ ក្បៀ ច្រៀ ន្តឿ ល្បឿ */
     '\0',
-    '\xE0', '\xB0', '\x85', '\xE0', '\xB0', '\x95', '\xE0', '\xB0', '\x9A', '\xE0', '\xB0', '\xB0', '\xE0', '\xB0', '\xBD', '\xE0', '\xB1', '\xA8', '\xE0', '\xB1', '\xAC',  /* అ క చ ర ఽ ౨ ౬ */
+    '\xE1', '\xA7', '\xA0', ' ', '\xE1', '\xA7', '\xA1',  /* ᧠ ᧡ */
     '\0',
-    '\xE0', '\xB8', '\x9A', '\xE0', '\xB9', '\x80', '\xE0', '\xB9', '\x81', '\xE0', '\xB8', '\xAD', '\xE0', '\xB8', '\x81', '\xE0', '\xB8', '\xB2',  /* บ เ แ อ ก า */
+    '\xE1', '\xA7', '\xB6', ' ', '\xE1', '\xA7', '\xB9',  /* ᧶ ᧹ */
     '\0',
-    '\xE0', '\xB8', '\x9A', '\xE0', '\xB8', '\x9B', '\xE0', '\xB8', '\xA9', '\xE0', '\xB8', '\xAF', '\xE0', '\xB8', '\xAD', '\xE0', '\xB8', '\xA2', '\xE0', '\xB8', '\xAE',  /* บ ป ษ ฯ อ ย ฮ */
+    '\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\x94', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\xA1', ' ', '\xE0', '\xBA', '\xA5', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\x87',  /* າ ດ ອ ມ ລ ວ ຣ ງ */
     '\0',
-    '\xE0', '\xB8', '\x9B', '\xE0', '\xB8', '\x9D', '\xE0', '\xB8', '\x9F',  /* ป ฝ ฟ */
+    '\xE0', '\xBA', '\xB2', ' ', '\xE0', '\xBA', '\xAD', ' ', '\xE0', '\xBA', '\x9A', ' ', '\xE0', '\xBA', '\x8D', ' ', '\xE0', '\xBA', '\xA3', ' ', '\xE0', '\xBA', '\xAE', ' ', '\xE0', '\xBA', '\xA7', ' ', '\xE0', '\xBA', '\xA2',  /* າ ອ ບ ຍ ຣ ຮ ວ ຢ */
     '\0',
-    '\xE0', '\xB9', '\x82', '\xE0', '\xB9', '\x83', '\xE0', '\xB9', '\x84',  /* โ ใ ไ */
+    '\xE0', '\xBA', '\x9B', ' ', '\xE0', '\xBA', '\xA2', ' ', '\xE0', '\xBA', '\x9F', ' ', '\xE0', '\xBA', '\x9D',  /* ປ ຢ ຟ ຝ */
     '\0',
-    '\xE0', '\xB8', '\x8E', '\xE0', '\xB8', '\x8F', '\xE0', '\xB8', '\xA4', '\xE0', '\xB8', '\xA6',  /* ฎ ฏ ฤ ฦ */
+    '\xE0', '\xBB', '\x82', ' ', '\xE0', '\xBB', '\x84', ' ', '\xE0', '\xBB', '\x83',  /* ໂ ໄ ໃ */
     '\0',
-    '\xE0', '\xB8', '\x8D', '\xE0', '\xB8', '\x90',  /* ญ ฐ */
+    '\xE0', '\xBA', '\x87', ' ', '\xE0', '\xBA', '\x8A', ' ', '\xE0', '\xBA', '\x96', ' ', '\xE0', '\xBA', '\xBD', ' ', '\xE0', '\xBB', '\x86', ' ', '\xE0', '\xBA', '\xAF',  /* ງ ຊ ຖ ຽ ໆ ຯ */
     '\0',
-    '\xE0', '\xB9', '\x90', '\xE0', '\xB9', '\x91', '\xE0', '\xB9', '\x93',  /* ๐ ๑ ๓ */
+    'T', ' ', 'H', ' ', 'E', ' ', 'Z', ' ', 'O', ' ', 'C', ' ', 'Q', ' ', 'S',  /* T H E Z O C Q S */
+    '\0',
+    'H', ' ', 'E', ' ', 'Z', ' ', 'L', ' ', 'O', ' ', 'C', ' ', 'U', ' ', 'S',  /* H E Z L O C U S */
+    '\0',
+    'f', ' ', 'i', ' ', 'j', ' ', 'k', ' ', 'd', ' ', 'b', ' ', 'h',  /* f i j k d b h */
+    '\0',
+    'x', ' ', 'z', ' ', 'r', ' ', 'o', ' ', 'e', ' ', 's', ' ', 'c',  /* x z r o e s c */
+    '\0',
+    'p', ' ', 'q', ' ', 'g', ' ', 'j', ' ', 'y',  /* p q g j y */
+    '\0',
+    '\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x85', ' ', '\xE2', '\x82', '\x87', ' ', '\xE2', '\x82', '\x88',  /* ₀ ₃ ₅ ₇ ₈ */
+    '\0',
+    '\xE2', '\x82', '\x80', ' ', '\xE2', '\x82', '\x81', ' ', '\xE2', '\x82', '\x82', ' ', '\xE2', '\x82', '\x83', ' ', '\xE2', '\x82', '\x88',  /* ₀ ₁ ₂ ₃ ₈ */
+    '\0',
+    '\xE1', '\xB5', '\xA2', ' ', '\xE2', '\xB1', '\xBC', ' ', '\xE2', '\x82', '\x95', ' ', '\xE2', '\x82', '\x96', ' ', '\xE2', '\x82', '\x97',  /* ᵢ ⱼ ₕ ₖ ₗ */
+    '\0',
+    '\xE2', '\x82', '\x90', ' ', '\xE2', '\x82', '\x91', ' ', '\xE2', '\x82', '\x92', ' ', '\xE2', '\x82', '\x93', ' ', '\xE2', '\x82', '\x99', ' ', '\xE2', '\x82', '\x9B', ' ', '\xE1', '\xB5', '\xA5', ' ', '\xE1', '\xB5', '\xA4', ' ', '\xE1', '\xB5', '\xA3',  /* ₐ ₑ ₒ ₓ ₙ ₛ ᵥ ᵤ ᵣ */
+    '\0',
+    '\xE1', '\xB5', '\xA6', ' ', '\xE1', '\xB5', '\xA7', ' ', '\xE1', '\xB5', '\xA8', ' ', '\xE1', '\xB5', '\xA9', ' ', '\xE2', '\x82', '\x9A',  /* ᵦ ᵧ ᵨ ᵩ ₚ */
+    '\0',
+    '\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB3', ' ', '\xE2', '\x81', '\xB5', ' ', '\xE2', '\x81', '\xB7', ' ', '\xE1', '\xB5', '\x80', ' ', '\xE1', '\xB4', '\xB4', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xBC',  /* ⁰ ³ ⁵ ⁷ ᵀ ᴴ ᴱ ᴼ */
+    '\0',
+    '\xE2', '\x81', '\xB0', ' ', '\xC2', '\xB9', ' ', '\xC2', '\xB2', ' ', '\xC2', '\xB3', ' ', '\xE1', '\xB4', '\xB1', ' ', '\xE1', '\xB4', '\xB8', ' ', '\xE1', '\xB4', '\xBC', ' ', '\xE1', '\xB5', '\x81',  /* ⁰ ¹ ² ³ ᴱ ᴸ ᴼ ᵁ */
+    '\0',
+    '\xE1', '\xB5', '\x87', ' ', '\xE1', '\xB5', '\x88', ' ', '\xE1', '\xB5', '\x8F', ' ', '\xCA', '\xB0', ' ', '\xCA', '\xB2', ' ', '\xE1', '\xB6', '\xA0', ' ', '\xE2', '\x81', '\xB1',  /* ᵇ ᵈ ᵏ ʰ ʲ ᶠ ⁱ */
+    '\0',
+    '\xE1', '\xB5', '\x89', ' ', '\xE1', '\xB5', '\x92', ' ', '\xCA', '\xB3', ' ', '\xCB', '\xA2', ' ', '\xCB', '\xA3', ' ', '\xE1', '\xB6', '\x9C', ' ', '\xE1', '\xB6', '\xBB',  /* ᵉ ᵒ ʳ ˢ ˣ ᶜ ᶻ */
+    '\0',
+    '\xE1', '\xB5', '\x96', ' ', '\xCA', '\xB8', ' ', '\xE1', '\xB5', '\x8D',  /* ᵖ ʸ ᵍ */
+    '\0',
+    '\xE1', '\x80', '\x81', ' ', '\xE1', '\x80', '\x82', ' ', '\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\xA5', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B',  /* ခ ဂ င ဒ ဝ ၥ ၊ ။ */
+    '\0',
+    '\xE1', '\x80', '\x84', ' ', '\xE1', '\x80', '\x8E', ' ', '\xE1', '\x80', '\x92', ' ', '\xE1', '\x80', '\x95', ' ', '\xE1', '\x80', '\x97', ' ', '\xE1', '\x80', '\x9D', ' ', '\xE1', '\x81', '\x8A', ' ', '\xE1', '\x81', '\x8B',  /* င ဎ ဒ ပ ဗ ဝ ၊ ။ */
+    '\0',
+    '\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xBC', ' ', '\xE1', '\x81', '\x8D', ' ', '\xE1', '\x81', '\x8F', ' ', '\xE1', '\x81', '\x86', ' ', '\xE1', '\x80', '\xAB', ' ', '\xE1', '\x80', '\xAD',  /* ဩ ြ ၍ ၏ ၆ ါ ိ */
+    '\0',
+    '\xE1', '\x80', '\x89', ' ', '\xE1', '\x80', '\x8A', ' ', '\xE1', '\x80', '\xA5', ' ', '\xE1', '\x80', '\xA9', ' ', '\xE1', '\x80', '\xA8', ' ', '\xE1', '\x81', '\x82', ' ', '\xE1', '\x81', '\x85', ' ', '\xE1', '\x81', '\x89',  /* ဉ ည ဥ ဩ ဨ ၂ ၅ ၉ */
+    '\0',
+    '\xE0', '\xB0', '\x87', ' ', '\xE0', '\xB0', '\x8C', ' ', '\xE0', '\xB0', '\x99', ' ', '\xE0', '\xB0', '\x9E', ' ', '\xE0', '\xB0', '\xA3', ' ', '\xE0', '\xB0', '\xB1', ' ', '\xE0', '\xB1', '\xAF',  /* ఇ ఌ ఙ ఞ ణ ఱ ౯ */
+    '\0',
+    '\xE0', '\xB0', '\x85', ' ', '\xE0', '\xB0', '\x95', ' ', '\xE0', '\xB0', '\x9A', ' ', '\xE0', '\xB0', '\xB0', ' ', '\xE0', '\xB0', '\xBD', ' ', '\xE0', '\xB1', '\xA8', ' ', '\xE0', '\xB1', '\xAC',  /* అ క చ ర ఽ ౨ ౬ */
+    '\0',
+    '\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB9', '\x80', ' ', '\xE0', '\xB9', '\x81', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\x81', ' ', '\xE0', '\xB8', '\xB2',  /* บ เ แ อ ก า */
+    '\0',
+    '\xE0', '\xB8', '\x9A', ' ', '\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\xA9', ' ', '\xE0', '\xB8', '\xAF', ' ', '\xE0', '\xB8', '\xAD', ' ', '\xE0', '\xB8', '\xA2', ' ', '\xE0', '\xB8', '\xAE',  /* บ ป ษ ฯ อ ย ฮ */
+    '\0',
+    '\xE0', '\xB8', '\x9B', ' ', '\xE0', '\xB8', '\x9D', ' ', '\xE0', '\xB8', '\x9F',  /* ป ฝ ฟ */
+    '\0',
+    '\xE0', '\xB9', '\x82', ' ', '\xE0', '\xB9', '\x83', ' ', '\xE0', '\xB9', '\x84',  /* โ ใ ไ */
+    '\0',
+    '\xE0', '\xB8', '\x8E', ' ', '\xE0', '\xB8', '\x8F', ' ', '\xE0', '\xB8', '\xA4', ' ', '\xE0', '\xB8', '\xA6',  /* ฎ ฏ ฤ ฦ */
+    '\0',
+    '\xE0', '\xB8', '\x8D', ' ', '\xE0', '\xB8', '\x90',  /* ญ ฐ */
+    '\0',
+    '\xE0', '\xB9', '\x90', ' ', '\xE0', '\xB9', '\x91', ' ', '\xE0', '\xB9', '\x93',  /* ๐ ๑ ๓ */
 #ifdef AF_CONFIG_OPTION_CJK
     '\0',
-    '\xE4', '\xBB', '\x96', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\x9C', '\xB0',  /* 他们你來們到和地 */
-    '\xE5', '\xAF', '\xB9', '\xE5', '\xB0', '\x8D', '\xE5', '\xB0', '\xB1', '\xE5', '\xB8', '\xAD', '\xE6', '\x88', '\x91', '\xE6', '\x97', '\xB6', '\xE6', '\x99', '\x82', '\xE6', '\x9C', '\x83',  /* 对對就席我时時會 */
-    '\xE6', '\x9D', '\xA5', '\xE7', '\x82', '\xBA', '\xE8', '\x83', '\xBD', '\xE8', '\x88', '\xB0', '\xE8', '\xAA', '\xAA', '\xE8', '\xAF', '\xB4', '\xE8', '\xBF', '\x99', '\xE9', '\x80', '\x99',  /* 来為能舰說说这這 */
-    '\xE9', '\xBD', '\x8A', '|',  /* 齊 | */
-    '\xE5', '\x86', '\x9B', '\xE5', '\x90', '\x8C', '\xE5', '\xB7', '\xB2', '\xE6', '\x84', '\xBF', '\xE6', '\x97', '\xA2', '\xE6', '\x98', '\x9F', '\xE6', '\x98', '\xAF', '\xE6', '\x99', '\xAF',  /* 军同已愿既星是景 */
-    '\xE6', '\xB0', '\x91', '\xE7', '\x85', '\xA7', '\xE7', '\x8E', '\xB0', '\xE7', '\x8F', '\xBE', '\xE7', '\x90', '\x86', '\xE7', '\x94', '\xA8', '\xE7', '\xBD', '\xAE', '\xE8', '\xA6', '\x81',  /* 民照现現理用置要 */
-    '\xE8', '\xBB', '\x8D', '\xE9', '\x82', '\xA3', '\xE9', '\x85', '\x8D', '\xE9', '\x87', '\x8C', '\xE9', '\x96', '\x8B', '\xE9', '\x9B', '\xB7', '\xE9', '\x9C', '\xB2', '\xE9', '\x9D', '\xA2',  /* 軍那配里開雷露面 */
-    '\xE9', '\xA1', '\xBE',  /* 顾 */
+    '\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0',  /* 他 们 你 來 們 到 和 地 */
+    ' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB8', '\xAD', ' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x83',  /*  对 對 就 席 我 时 時 會 */
+    ' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\x88', '\xB0', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99',  /*  来 為 能 舰 說 说 这 這 */
+    ' ', '\xE9', '\xBD', '\x8A', ' ', '|',  /*  齊 | */
+    ' ', '\xE5', '\x86', '\x9B', ' ', '\xE5', '\x90', '\x8C', ' ', '\xE5', '\xB7', '\xB2', ' ', '\xE6', '\x84', '\xBF', ' ', '\xE6', '\x97', '\xA2', ' ', '\xE6', '\x98', '\x9F', ' ', '\xE6', '\x98', '\xAF', ' ', '\xE6', '\x99', '\xAF',  /*  军 同 已 愿 既 星 是 景 */
+    ' ', '\xE6', '\xB0', '\x91', ' ', '\xE7', '\x85', '\xA7', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\xA8', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\xA6', '\x81',  /*  民 照 现 現 理 用 置 要 */
+    ' ', '\xE8', '\xBB', '\x8D', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x85', '\x8D', ' ', '\xE9', '\x87', '\x8C', ' ', '\xE9', '\x96', '\x8B', ' ', '\xE9', '\x9B', '\xB7', ' ', '\xE9', '\x9C', '\xB2', ' ', '\xE9', '\x9D', '\xA2',  /*  軍 那 配 里 開 雷 露 面 */
+    ' ', '\xE9', '\xA1', '\xBE',  /*  顾 */
     '\0',
-    '\xE4', '\xB8', '\xAA', '\xE4', '\xB8', '\xBA', '\xE4', '\xBA', '\xBA', '\xE4', '\xBB', '\x96', '\xE4', '\xBB', '\xA5', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86',  /* 个为人他以们你來 */
-    '\xE5', '\x80', '\x8B', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\xA4', '\xA7', '\xE5', '\xAF', '\xB9', '\xE5', '\xB0', '\x8D', '\xE5', '\xB0', '\xB1',  /* 個們到和大对對就 */
-    '\xE6', '\x88', '\x91', '\xE6', '\x97', '\xB6', '\xE6', '\x99', '\x82', '\xE6', '\x9C', '\x89', '\xE6', '\x9D', '\xA5', '\xE7', '\x82', '\xBA', '\xE8', '\xA6', '\x81', '\xE8', '\xAA', '\xAA',  /* 我时時有来為要說 */
-    '\xE8', '\xAF', '\xB4', '|',  /* 说 | */
-    '\xE4', '\xB8', '\xBB', '\xE4', '\xBA', '\x9B', '\xE5', '\x9B', '\xA0', '\xE5', '\xAE', '\x83', '\xE6', '\x83', '\xB3', '\xE6', '\x84', '\x8F', '\xE7', '\x90', '\x86', '\xE7', '\x94', '\x9F',  /* 主些因它想意理生 */
-    '\xE7', '\x95', '\xB6', '\xE7', '\x9C', '\x8B', '\xE7', '\x9D', '\x80', '\xE7', '\xBD', '\xAE', '\xE8', '\x80', '\x85', '\xE8', '\x87', '\xAA', '\xE8', '\x91', '\x97', '\xE8', '\xA3', '\xA1',  /* 當看着置者自著裡 */
-    '\xE8', '\xBF', '\x87', '\xE8', '\xBF', '\x98', '\xE8', '\xBF', '\x9B', '\xE9', '\x80', '\xB2', '\xE9', '\x81', '\x8E', '\xE9', '\x81', '\x93', '\xE9', '\x82', '\x84', '\xE9', '\x87', '\x8C',  /* 过还进進過道還里 */
-    '\xE9', '\x9D', '\xA2',  /* 面 */
+    '\xE4', '\xB8', '\xAA', ' ', '\xE4', '\xB8', '\xBA', ' ', '\xE4', '\xBA', '\xBA', ' ', '\xE4', '\xBB', '\x96', ' ', '\xE4', '\xBB', '\xA5', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86',  /* 个 为 人 他 以 们 你 來 */
+    ' ', '\xE5', '\x80', '\x8B', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\xA4', '\xA7', ' ', '\xE5', '\xAF', '\xB9', ' ', '\xE5', '\xB0', '\x8D', ' ', '\xE5', '\xB0', '\xB1',  /*  個 們 到 和 大 对 對 就 */
+    ' ', '\xE6', '\x88', '\x91', ' ', '\xE6', '\x97', '\xB6', ' ', '\xE6', '\x99', '\x82', ' ', '\xE6', '\x9C', '\x89', ' ', '\xE6', '\x9D', '\xA5', ' ', '\xE7', '\x82', '\xBA', ' ', '\xE8', '\xA6', '\x81', ' ', '\xE8', '\xAA', '\xAA',  /*  我 时 時 有 来 為 要 說 */
+    ' ', '\xE8', '\xAF', '\xB4', ' ', '|',  /*  说 | */
+    ' ', '\xE4', '\xB8', '\xBB', ' ', '\xE4', '\xBA', '\x9B', ' ', '\xE5', '\x9B', '\xA0', ' ', '\xE5', '\xAE', '\x83', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x84', '\x8F', ' ', '\xE7', '\x90', '\x86', ' ', '\xE7', '\x94', '\x9F',  /*  主 些 因 它 想 意 理 生 */
+    ' ', '\xE7', '\x95', '\xB6', ' ', '\xE7', '\x9C', '\x8B', ' ', '\xE7', '\x9D', '\x80', ' ', '\xE7', '\xBD', '\xAE', ' ', '\xE8', '\x80', '\x85', ' ', '\xE8', '\x87', '\xAA', ' ', '\xE8', '\x91', '\x97', ' ', '\xE8', '\xA3', '\xA1',  /*  當 看 着 置 者 自 著 裡 */
+    ' ', '\xE8', '\xBF', '\x87', ' ', '\xE8', '\xBF', '\x98', ' ', '\xE8', '\xBF', '\x9B', ' ', '\xE9', '\x80', '\xB2', ' ', '\xE9', '\x81', '\x8E', ' ', '\xE9', '\x81', '\x93', ' ', '\xE9', '\x82', '\x84', ' ', '\xE9', '\x87', '\x8C',  /*  过 还 进 進 過 道 還 里 */
+    ' ', '\xE9', '\x9D', '\xA2',  /*  面 */
 #ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
     '\0',
-    '\xE4', '\xBA', '\x9B', '\xE4', '\xBB', '\xAC', '\xE4', '\xBD', '\xA0', '\xE4', '\xBE', '\x86', '\xE5', '\x80', '\x91', '\xE5', '\x88', '\xB0', '\xE5', '\x92', '\x8C', '\xE5', '\x9C', '\xB0',  /* 些们你來們到和地 */
-    '\xE5', '\xA5', '\xB9', '\xE5', '\xB0', '\x86', '\xE5', '\xB0', '\x87', '\xE5', '\xB0', '\xB1', '\xE5', '\xB9', '\xB4', '\xE5', '\xBE', '\x97', '\xE6', '\x83', '\x85', '\xE6', '\x9C', '\x80',  /* 她将將就年得情最 */
-    '\xE6', '\xA0', '\xB7', '\xE6', '\xA8', '\xA3', '\xE7', '\x90', '\x86', '\xE8', '\x83', '\xBD', '\xE8', '\xAA', '\xAA', '\xE8', '\xAF', '\xB4', '\xE8', '\xBF', '\x99', '\xE9', '\x80', '\x99',  /* 样樣理能說说这這 */
-    '\xE9', '\x80', '\x9A', '|',  /* 通 | */
-    '\xE5', '\x8D', '\xB3', '\xE5', '\x90', '\x97', '\xE5', '\x90', '\xA7', '\xE5', '\x90', '\xAC', '\xE5', '\x91', '\xA2', '\xE5', '\x93', '\x81', '\xE5', '\x93', '\x8D', '\xE5', '\x97', '\x8E',  /* 即吗吧听呢品响嗎 */
-    '\xE5', '\xB8', '\x88', '\xE5', '\xB8', '\xAB', '\xE6', '\x94', '\xB6', '\xE6', '\x96', '\xAD', '\xE6', '\x96', '\xB7', '\xE6', '\x98', '\x8E', '\xE7', '\x9C', '\xBC', '\xE9', '\x96', '\x93',  /* 师師收断斷明眼間 */
-    '\xE9', '\x97', '\xB4', '\xE9', '\x99', '\x85', '\xE9', '\x99', '\x88', '\xE9', '\x99', '\x90', '\xE9', '\x99', '\xA4', '\xE9', '\x99', '\xB3', '\xE9', '\x9A', '\x8F', '\xE9', '\x9A', '\x9B',  /* 间际陈限除陳随際 */
-    '\xE9', '\x9A', '\xA8',  /* 隨 */
+    ' ', '\xE4', '\xBA', '\x9B', ' ', '\xE4', '\xBB', '\xAC', ' ', '\xE4', '\xBD', '\xA0', ' ', '\xE4', '\xBE', '\x86', ' ', '\xE5', '\x80', '\x91', ' ', '\xE5', '\x88', '\xB0', ' ', '\xE5', '\x92', '\x8C', ' ', '\xE5', '\x9C', '\xB0',  /*  些 们 你 來 們 到 和 地 */
+    ' ', '\xE5', '\xA5', '\xB9', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE5', '\xB0', '\xB1', ' ', '\xE5', '\xB9', '\xB4', ' ', '\xE5', '\xBE', '\x97', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x9C', '\x80',  /*  她 将 將 就 年 得 情 最 */
+    ' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE7', '\x90', '\x86', ' ', '\xE8', '\x83', '\xBD', ' ', '\xE8', '\xAA', '\xAA', ' ', '\xE8', '\xAF', '\xB4', ' ', '\xE8', '\xBF', '\x99', ' ', '\xE9', '\x80', '\x99',  /*  样 樣 理 能 說 说 这 這 */
+    ' ', '\xE9', '\x80', '\x9A', ' ', '|',  /*  通 | */
+    ' ', '\xE5', '\x8D', '\xB3', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x90', '\xA7', ' ', '\xE5', '\x90', '\xAC', ' ', '\xE5', '\x91', '\xA2', ' ', '\xE5', '\x93', '\x81', ' ', '\xE5', '\x93', '\x8D', ' ', '\xE5', '\x97', '\x8E',  /*  即 吗 吧 听 呢 品 响 嗎 */
+    ' ', '\xE5', '\xB8', '\x88', ' ', '\xE5', '\xB8', '\xAB', ' ', '\xE6', '\x94', '\xB6', ' ', '\xE6', '\x96', '\xAD', ' ', '\xE6', '\x96', '\xB7', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE7', '\x9C', '\xBC', ' ', '\xE9', '\x96', '\x93',  /*  师 師 收 断 斷 明 眼 間 */
+    ' ', '\xE9', '\x97', '\xB4', ' ', '\xE9', '\x99', '\x85', ' ', '\xE9', '\x99', '\x88', ' ', '\xE9', '\x99', '\x90', ' ', '\xE9', '\x99', '\xA4', ' ', '\xE9', '\x99', '\xB3', ' ', '\xE9', '\x9A', '\x8F', ' ', '\xE9', '\x9A', '\x9B',  /*  间 际 陈 限 除 陳 随 際 */
+    ' ', '\xE9', '\x9A', '\xA8',  /*  隨 */
     '\0',
-    '\xE4', '\xBA', '\x8B', '\xE5', '\x89', '\x8D', '\xE5', '\xAD', '\xB8', '\xE5', '\xB0', '\x86', '\xE5', '\xB0', '\x87', '\xE6', '\x83', '\x85', '\xE6', '\x83', '\xB3', '\xE6', '\x88', '\x96',  /* 事前學将將情想或 */
-    '\xE6', '\x94', '\xBF', '\xE6', '\x96', '\xAF', '\xE6', '\x96', '\xB0', '\xE6', '\xA0', '\xB7', '\xE6', '\xA8', '\xA3', '\xE6', '\xB0', '\x91', '\xE6', '\xB2', '\x92', '\xE6', '\xB2', '\xA1',  /* 政斯新样樣民沒没 */
-    '\xE7', '\x84', '\xB6', '\xE7', '\x89', '\xB9', '\xE7', '\x8E', '\xB0', '\xE7', '\x8F', '\xBE', '\xE7', '\x90', '\x83', '\xE7', '\xAC', '\xAC', '\xE7', '\xB6', '\x93', '\xE8', '\xB0', '\x81',  /* 然特现現球第經谁 */
-    '\xE8', '\xB5', '\xB7', '|',  /* 起 | */
-    '\xE4', '\xBE', '\x8B', '\xE5', '\x88', '\xA5', '\xE5', '\x88', '\xAB', '\xE5', '\x88', '\xB6', '\xE5', '\x8A', '\xA8', '\xE5', '\x8B', '\x95', '\xE5', '\x90', '\x97', '\xE5', '\x97', '\x8E',  /* 例別别制动動吗嗎 */
-    '\xE5', '\xA2', '\x9E', '\xE6', '\x8C', '\x87', '\xE6', '\x98', '\x8E', '\xE6', '\x9C', '\x9D', '\xE6', '\x9C', '\x9F', '\xE6', '\x9E', '\x84', '\xE7', '\x89', '\xA9', '\xE7', '\xA1', '\xAE',  /* 增指明朝期构物确 */
-    '\xE7', '\xA7', '\x8D', '\xE8', '\xAA', '\xBF', '\xE8', '\xB0', '\x83', '\xE8', '\xB2', '\xBB', '\xE8', '\xB4', '\xB9', '\xE9', '\x82', '\xA3', '\xE9', '\x83', '\xBD', '\xE9', '\x96', '\x93',  /* 种調调費费那都間 */
-    '\xE9', '\x97', '\xB4',  /* 间 */
+    '\xE4', '\xBA', '\x8B', ' ', '\xE5', '\x89', '\x8D', ' ', '\xE5', '\xAD', '\xB8', ' ', '\xE5', '\xB0', '\x86', ' ', '\xE5', '\xB0', '\x87', ' ', '\xE6', '\x83', '\x85', ' ', '\xE6', '\x83', '\xB3', ' ', '\xE6', '\x88', '\x96',  /* 事 前 學 将 將 情 想 或 */
+    ' ', '\xE6', '\x94', '\xBF', ' ', '\xE6', '\x96', '\xAF', ' ', '\xE6', '\x96', '\xB0', ' ', '\xE6', '\xA0', '\xB7', ' ', '\xE6', '\xA8', '\xA3', ' ', '\xE6', '\xB0', '\x91', ' ', '\xE6', '\xB2', '\x92', ' ', '\xE6', '\xB2', '\xA1',  /*  政 斯 新 样 樣 民 沒 没 */
+    ' ', '\xE7', '\x84', '\xB6', ' ', '\xE7', '\x89', '\xB9', ' ', '\xE7', '\x8E', '\xB0', ' ', '\xE7', '\x8F', '\xBE', ' ', '\xE7', '\x90', '\x83', ' ', '\xE7', '\xAC', '\xAC', ' ', '\xE7', '\xB6', '\x93', ' ', '\xE8', '\xB0', '\x81',  /*  然 特 现 現 球 第 經 谁 */
+    ' ', '\xE8', '\xB5', '\xB7', ' ', '|',  /*  起 | */
+    ' ', '\xE4', '\xBE', '\x8B', ' ', '\xE5', '\x88', '\xA5', ' ', '\xE5', '\x88', '\xAB', ' ', '\xE5', '\x88', '\xB6', ' ', '\xE5', '\x8A', '\xA8', ' ', '\xE5', '\x8B', '\x95', ' ', '\xE5', '\x90', '\x97', ' ', '\xE5', '\x97', '\x8E',  /*  例 別 别 制 动 動 吗 嗎 */
+    ' ', '\xE5', '\xA2', '\x9E', ' ', '\xE6', '\x8C', '\x87', ' ', '\xE6', '\x98', '\x8E', ' ', '\xE6', '\x9C', '\x9D', ' ', '\xE6', '\x9C', '\x9F', ' ', '\xE6', '\x9E', '\x84', ' ', '\xE7', '\x89', '\xA9', ' ', '\xE7', '\xA1', '\xAE',  /*  增 指 明 朝 期 构 物 确 */
+    ' ', '\xE7', '\xA7', '\x8D', ' ', '\xE8', '\xAA', '\xBF', ' ', '\xE8', '\xB0', '\x83', ' ', '\xE8', '\xB2', '\xBB', ' ', '\xE8', '\xB4', '\xB9', ' ', '\xE9', '\x82', '\xA3', ' ', '\xE9', '\x83', '\xBD', ' ', '\xE9', '\x96', '\x93',  /*  种 調 调 費 费 那 都 間 */
+    ' ', '\xE9', '\x97', '\xB4',  /*  间 */
 #endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
 #endif /* AF_CONFIG_OPTION_CJK                */
     '\0',
@@ -139,9 +193,10 @@
   af_blue_stringsets[] =
   {
     /* */
-    { AF_BLUE_STRING_ARABIC_TOP,   AF_BLUE_PROPERTY_LATIN_TOP },
-    { AF_BLUE_STRING_ARABIC_JOIN,  0                          },
-    { AF_BLUE_STRING_MAX,          0                          },
+    { AF_BLUE_STRING_ARABIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP     },
+    { AF_BLUE_STRING_ARABIC_BOTTOM, 0                              },
+    { AF_BLUE_STRING_ARABIC_JOIN,   AF_BLUE_PROPERTY_LATIN_NEUTRAL },
+    { AF_BLUE_STRING_MAX,           0                              },
     { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
     { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM,  0                                 },
     { AF_BLUE_STRING_CYRILLIC_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
@@ -170,6 +225,24 @@
     { AF_BLUE_STRING_HEBREW_BOTTOM,    0                             },
     { AF_BLUE_STRING_HEBREW_DESCENDER, 0                             },
     { AF_BLUE_STRING_MAX,              0                             },
+    { AF_BLUE_STRING_KHMER_TOP,             AF_BLUE_PROPERTY_LATIN_TOP      |
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
+    { AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP,   AF_BLUE_PROPERTY_LATIN_SUB_TOP    },
+    { AF_BLUE_STRING_KHMER_BOTTOM,          0                                 },
+    { AF_BLUE_STRING_KHMER_DESCENDER,       0                                 },
+    { AF_BLUE_STRING_KHMER_LARGE_DESCENDER, 0                                 },
+    { AF_BLUE_STRING_MAX,                   0                                 },
+    { AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
+                                                  AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
+    { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0                                 },
+    { AF_BLUE_STRING_MAX,                         0                                 },
+    { AF_BLUE_STRING_LAO_TOP,             AF_BLUE_PROPERTY_LATIN_TOP      |
+                                          AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
+    { AF_BLUE_STRING_LAO_BOTTOM,          0                                 },
+    { AF_BLUE_STRING_LAO_ASCENDER,        AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_LAO_LARGE_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_LAO_DESCENDER,       0                                 },
+    { AF_BLUE_STRING_MAX,                 0                                 },
     { AF_BLUE_STRING_LATIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
     { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM,  0                                 },
     { AF_BLUE_STRING_LATIN_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
@@ -178,6 +251,28 @@
     { AF_BLUE_STRING_LATIN_SMALL,           0                                 },
     { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0                                 },
     { AF_BLUE_STRING_MAX,                   0                                 },
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM,  0                                 },
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           0                                 },
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0                                 },
+    { AF_BLUE_STRING_MAX,                        0                                 },
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM,  0                                 },
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           0                                 },
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0                                 },
+    { AF_BLUE_STRING_MAX,                        0                                 },
+    { AF_BLUE_STRING_MYANMAR_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
+                                        AF_BLUE_PROPERTY_LATIN_X_HEIGHT   },
+    { AF_BLUE_STRING_MYANMAR_BOTTOM,    0                                 },
+    { AF_BLUE_STRING_MYANMAR_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        },
+    { AF_BLUE_STRING_MYANMAR_DESCENDER, 0                                 },
+    { AF_BLUE_STRING_MAX,               0                                 },
     { AF_BLUE_STRING_TELUGU_TOP,    AF_BLUE_PROPERTY_LATIN_TOP },
     { AF_BLUE_STRING_TELUGU_BOTTOM, 0                          },
     { AF_BLUE_STRING_MAX,           0                          },
diff --git a/src/autofit/afblue.dat b/src/autofit/afblue.dat
index fd5684e..5ffb852 100644
--- a/src/autofit/afblue.dat
+++ b/src/autofit/afblue.dat
@@ -20,9 +20,8 @@
 // labels separated by whitespace and followed by a colon (everything in a
 // single line); the first label gives the name of the enumeration template,
 // the second the name of the array template, and the third the name of the
-// `maximum' template, holding the size of the largest array element.  The
-// script then fills the corresponding templates (indicated by `@'
-// characters around the name).
+// `maximum' template.  The script then fills the corresponding templates
+// (indicated by `@' characters around the name).
 //
 // A section contains one or more data records.  Each data record consists
 // of two or more lines.  The first line holds the enumeration name, and the
@@ -30,15 +29,20 @@
 //
 // There are two possible representations for array data.
 //
-// - A string of characters in UTF-8 encoding enclosed in double quotes,
-//   using C syntax.  There can be only one string per line, thus the
-//   starting and ending double quote must be the first and last character
-//   in the line, respectively, ignoring whitespace before and after the
-//   string.  Space characters within the string are ignored too.  If there
-//   are multiple strings (in multiple lines), they are concatenated to a
-//   single string.  In the output, a string gets represented as a series of
-//   singles bytes, followed by a zero byte.  The enumeration values simply
-//   hold byte offsets to the start of the corresponding strings.
+// - A string of characters or character clusters (for example, representing
+//   Aksharas, Devanagari syllables) in UTF-8 encoding enclosed in double
+//   quotes, using C syntax, where the elements are separated by spaces.
+//   There can be only one string per line, thus the starting and ending
+//   double quote must be the first and last character in the line,
+//   respectively, ignoring whitespace before and after the string.  If
+//   there are multiple strings (in multiple lines), they are concatenated
+//   to a single string.  In the output, a string gets represented as a
+//   series of singles bytes, followed by a zero byte.  The enumeration
+//   values simply hold byte offsets to the start of the corresponding
+//   strings.
+//
+//   For strings, the `maximum' template holds the maximum number of
+//   non-space characters in all strings.
 //
 // - Data blocks enclosed in balanced braces, which get copied verbatim and
 //   which can span multiple lines.  The opening brace of a block must be
@@ -47,6 +51,9 @@
 //   character after each block and counts the number of blocks to set the
 //   enumeration values.
 //
+//   For data blocks, the `maximum' template holds the maximum number of
+//   array elements.
+//
 // A section can contain either strings only or data blocks only.
 //
 // A comment line starts with `//'; it gets removed.  A preprocessor
@@ -69,20 +76,25 @@
 
   AF_BLUE_STRING_ARABIC_TOP
     "ا إ ل ك ط ظ"
-  AF_BLUE_STRING_ARABIC_JOIN
+  AF_BLUE_STRING_ARABIC_BOTTOM
     "ت ث ط ظ ك"
+  // We don't necessarily have access to medial forms via Unicode in case
+  // Arabic presentational forms are missing.  The only character that is
+  // guaranteed to have the same vertical position with joining (this is,
+  // non-isolated) forms is U+0640, ARABIC TATWEEL, which must join both
+  // round and flat curves.
+  AF_BLUE_STRING_ARABIC_JOIN
+    "ـ"
 
   AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP
-    "БВЕПЗОСЭ"
+    "Б В Е П З О С Э"
   AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM
-    "БВЕШЗОСЭ"
+    "Б В Е Ш З О С Э"
   AF_BLUE_STRING_CYRILLIC_SMALL
-    "хпншезос"
+    "х п н ш е з о с"
   AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER
-    "руф"
+    "р у ф"
 
-  // we separate the letters with spaces to avoid ligatures;
-  // this is just for convenience to simplify reading
   AF_BLUE_STRING_DEVANAGARI_BASE
     "क म अ आ थ ध भ श"
   AF_BLUE_STRING_DEVANAGARI_TOP
@@ -96,36 +108,95 @@
     "ु ृ"
 
   AF_BLUE_STRING_GREEK_CAPITAL_TOP
-    "ΓΒΕΖΘΟΩ"
+    "Γ Β Ε Ζ Θ Ο Ω"
   AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM
-    "ΒΔΖΞΘΟ"
+    "Β Δ Ζ Ξ Θ Ο"
   AF_BLUE_STRING_GREEK_SMALL_BETA_TOP
-    "βθδζλξ"
+    "β θ δ ζ λ ξ"
   AF_BLUE_STRING_GREEK_SMALL
-    "αειοπστω"
+    "α ε ι ο π σ τ ω"
   AF_BLUE_STRING_GREEK_SMALL_DESCENDER
-    "βγημρφχψ"
+    "β γ η μ ρ φ χ ψ"
 
   AF_BLUE_STRING_HEBREW_TOP
-    "בדהחךכםס"
+    "ב ד ה ח ך כ ם ס"
   AF_BLUE_STRING_HEBREW_BOTTOM
-    "בטכםסצ"
+    "ב ט כ ם ס צ"
   AF_BLUE_STRING_HEBREW_DESCENDER
-    "קךןףץ"
+    "ק ך ן ף ץ"
+
+  AF_BLUE_STRING_KHMER_TOP
+    "ខ ទ ន ឧ ឩ ា"
+  AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP
+    "ក្ក ក្ខ ក្គ ក្ថ"
+  AF_BLUE_STRING_KHMER_BOTTOM
+    "ខ ឃ ច ឋ ប ម យ ឲ"
+  AF_BLUE_STRING_KHMER_DESCENDER
+    "ត្រ រៀ ឲ្យ អឿ"
+  AF_BLUE_STRING_KHMER_LARGE_DESCENDER
+    "ន្ត្រៃ ង្ខ្យ ក្បៀ ច្រៀ ន្តឿ ល្បឿ"
+
+  AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP
+    "᧠ ᧡"
+  AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM
+    "᧶ ᧹"
+
+  AF_BLUE_STRING_LAO_TOP
+    "າ ດ ອ ມ ລ ວ ຣ ງ"
+  AF_BLUE_STRING_LAO_BOTTOM
+    "າ ອ ບ ຍ ຣ ຮ ວ ຢ"
+  AF_BLUE_STRING_LAO_ASCENDER
+    "ປ ຢ ຟ ຝ"
+  AF_BLUE_STRING_LAO_LARGE_ASCENDER
+    "ໂ ໄ ໃ"
+  AF_BLUE_STRING_LAO_DESCENDER
+    "ງ ຊ ຖ ຽ ໆ ຯ"
 
   AF_BLUE_STRING_LATIN_CAPITAL_TOP
-    "THEZOCQS"
+    "T H E Z O C Q S"
   AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM
-    "HEZLOCUS"
+    "H E Z L O C U S"
   AF_BLUE_STRING_LATIN_SMALL_F_TOP
-    "fijkdbh"
+    "f i j k d b h"
   AF_BLUE_STRING_LATIN_SMALL
-    "xzroesc"
+    "x z r o e s c"
   AF_BLUE_STRING_LATIN_SMALL_DESCENDER
-    "pqgjy"
+    "p q g j y"
 
-  // we separate the letters with spaces to avoid ligatures;
-  // this is just for convenience to simplify reading
+  // we assume that both the subscript and superscript ranges
+  // don't contain oldstyle digits (actually, most fonts probably
+  // have digits only in those ranges)
+  AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP
+    "₀ ₃ ₅ ₇ ₈"
+  AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM
+    "₀ ₁ ₂ ₃ ₈"
+  AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP
+    "ᵢ ⱼ ₕ ₖ ₗ"
+  AF_BLUE_STRING_LATIN_SUBS_SMALL
+    "ₐ ₑ ₒ ₓ ₙ ₛ ᵥ ᵤ ᵣ"
+  AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER
+    "ᵦ ᵧ ᵨ ᵩ ₚ"
+
+  AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP
+    "⁰ ³ ⁵ ⁷ ᵀ ᴴ ᴱ ᴼ"
+  AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM
+    "⁰ ¹ ² ³ ᴱ ᴸ ᴼ ᵁ"
+  AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP
+    "ᵇ ᵈ ᵏ ʰ ʲ ᶠ ⁱ"
+  AF_BLUE_STRING_LATIN_SUPS_SMALL
+    "ᵉ ᵒ ʳ ˢ ˣ ᶜ ᶻ"
+  AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER
+    "ᵖ ʸ ᵍ"
+
+  AF_BLUE_STRING_MYANMAR_TOP
+    "ခ ဂ င ဒ ဝ ၥ ၊ ။"
+  AF_BLUE_STRING_MYANMAR_BOTTOM
+    "င ဎ ဒ ပ ဗ ဝ ၊ ။"
+  AF_BLUE_STRING_MYANMAR_ASCENDER
+    "ဩ ြ ၍ ၏ ၆ ါ ိ"
+  AF_BLUE_STRING_MYANMAR_DESCENDER
+    "ဉ ည ဥ ဩ ဨ ၂ ၅ ၉"
+
   AF_BLUE_STRING_TELUGU_TOP
     "ఇ ఌ ఙ ఞ ణ ఱ ౯"
   AF_BLUE_STRING_TELUGU_BOTTOM
@@ -150,44 +221,44 @@
 #ifdef AF_CONFIG_OPTION_CJK
 
   AF_BLUE_STRING_CJK_TOP
-    "他们你來們到和地"
-    "对對就席我时時會"
-    "来為能舰說说这這"
-    "齊 |"
-    "军同已愿既星是景"
-    "民照现現理用置要"
-    "軍那配里開雷露面"
-    "顾"
+    "他 们 你 來 們 到 和 地"
+    " 对 對 就 席 我 时 時 會"
+    " 来 為 能 舰 說 说 这 這"
+    " 齊 |"
+    " 军 同 已 愿 既 星 是 景"
+    " 民 照 现 現 理 用 置 要"
+    " 軍 那 配 里 開 雷 露 面"
+    " 顾"
   AF_BLUE_STRING_CJK_BOTTOM
-    "个为人他以们你來"
-    "個們到和大对對就"
-    "我时時有来為要說"
-    "说 |"
-    "主些因它想意理生"
-    "當看着置者自著裡"
-    "过还进進過道還里"
-    "面"
+    "个 为 人 他 以 们 你 來"
+    " 個 們 到 和 大 对 對 就"
+    " 我 时 時 有 来 為 要 說"
+    " 说 |"
+    " 主 些 因 它 想 意 理 生"
+    " 當 看 着 置 者 自 著 裡"
+    " 过 还 进 進 過 道 還 里"
+    " 面"
 
 #ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
 
   AF_BLUE_STRING_CJK_LEFT
-    "些们你來們到和地"
-    "她将將就年得情最"
-    "样樣理能說说这這"
-    "通 |"
-    "即吗吧听呢品响嗎"
-    "师師收断斷明眼間"
-    "间际陈限除陳随際"
-    "隨"
+    " 些 们 你 來 們 到 和 地"
+    " 她 将 將 就 年 得 情 最"
+    " 样 樣 理 能 說 说 这 這"
+    " 通 |"
+    " 即 吗 吧 听 呢 品 响 嗎"
+    " 师 師 收 断 斷 明 眼 間"
+    " 间 际 陈 限 除 陳 随 際"
+    " 隨"
   AF_BLUE_STRING_CJK_RIGHT
-    "事前學将將情想或"
-    "政斯新样樣民沒没"
-    "然特现現球第經谁"
-    "起 |"
-    "例別别制动動吗嗎"
-    "增指明朝期构物确"
-    "种調调費费那都間"
-    "间"
+    "事 前 學 将 將 情 想 或"
+    " 政 斯 新 样 樣 民 沒 没"
+    " 然 特 现 現 球 第 經 谁"
+    " 起 |"
+    " 例 別 别 制 动 動 吗 嗎"
+    " 增 指 明 朝 期 构 物 确"
+    " 种 調 调 費 费 那 都 間"
+    " 间"
 
 #endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
 
@@ -219,6 +290,14 @@
 // respectively.  Only horizontal blue zones (i.e., adjusting vertical
 // coordinate values) are supported.
 //
+// Some scripts like Khmer need character composition to get all necessary
+// blue zones, since Unicode only provides an abstract data model that
+// doesn't represent all possible glyph shapes.  For such character
+// clusters, the HarfBuzz library is used to convert them into the
+// corresponding glyphs.  The largest glyph element (where `largest' can be
+// either `largest ascender' or `largest descender') then defines the
+// corresponding flat or round extremum.
+//
 // For the latin auto-hinter, the overshoot should be larger than the
 // reference for top zones, and vice versa for bottom zones.
 //
@@ -229,6 +308,21 @@
 //
 //     If not set, take the minimum values.
 //
+//     Mutually exclusive with `LATIN_SUB_TOP'.
+//
+//   LATIN_SUB_TOP
+//     For all glyphs of a character cluster, compute the maximum flat
+//     and round coordinate values of each component, then take the
+//     smallest of the maximum values.  The idea is to get the top of
+//     subscript glyphs, as used in Khmer, for example.  Note that
+//     this mechanism doesn't work for ordinary ligatures.
+//
+//     This flags indicates a secondary blue zone: It gets removed if
+//     there is a non-LATIN_SUB_TOP blue zone at the same coordinate
+//     value (after scaling).
+//
+//     Mutually exclusive with `LATIN_TOP'.
+//
 //   LATIN_NEUTRAL
 //     Ignore round extrema and define the blue zone with flat values only.
 //     Both top and bottom of contours can match.  This is useful for
@@ -264,11 +358,11 @@
 //
 // Characters in a blue string are *not* automatically classified.  Instead,
 // first come the characters used for the overshoot value, then the
-// character `|', then the characters used for the reference value.  The
-// blue zone is then set up by the mean values of all reference values and
-// all overshoot values, respectively.  Both horizontal and vertical blue
-// zones (i.e., adjusting vertical and horizontal coordinate values,
-// respectively) are supported.
+// character `|', then the characters used for the reference value
+// (everything separated by space characters).  The blue zone is then set up
+// by the mean values of all reference values and all overshoot values,
+// respectively.  Both horizontal and vertical blue zones (i.e., adjusting
+// vertical and horizontal coordinate values, respectively) are supported.
 //
 // For the cjk auto-hinter, the overshoot should be smaller than the
 // reference for top zones, and vice versa for bottom zones.
@@ -289,9 +383,10 @@
 AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
 
   AF_BLUE_STRINGSET_ARAB
-    { AF_BLUE_STRING_ARABIC_TOP,   AF_BLUE_PROPERTY_LATIN_TOP }
-    { AF_BLUE_STRING_ARABIC_JOIN,  0                          }
-    { AF_BLUE_STRING_MAX,          0                          }
+    { AF_BLUE_STRING_ARABIC_TOP,    AF_BLUE_PROPERTY_LATIN_TOP     }
+    { AF_BLUE_STRING_ARABIC_BOTTOM, 0                              }
+    { AF_BLUE_STRING_ARABIC_JOIN,   AF_BLUE_PROPERTY_LATIN_NEUTRAL }
+    { AF_BLUE_STRING_MAX,           0                              }
 
   AF_BLUE_STRINGSET_CYRL
     { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
@@ -329,6 +424,30 @@
     { AF_BLUE_STRING_HEBREW_DESCENDER, 0                             }
     { AF_BLUE_STRING_MAX,              0                             }
 
+  AF_BLUE_STRINGSET_KHMR
+    { AF_BLUE_STRING_KHMER_TOP,             AF_BLUE_PROPERTY_LATIN_TOP      |
+                                            AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
+    { AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP,   AF_BLUE_PROPERTY_LATIN_SUB_TOP    }
+    { AF_BLUE_STRING_KHMER_BOTTOM,          0                                 }
+    { AF_BLUE_STRING_KHMER_DESCENDER,       0                                 }
+    { AF_BLUE_STRING_KHMER_LARGE_DESCENDER, 0                                 }
+    { AF_BLUE_STRING_MAX,                   0                                 }
+
+  AF_BLUE_STRINGSET_KHMS
+    { AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP,    AF_BLUE_PROPERTY_LATIN_TOP      |
+                                                  AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
+    { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0                                 }
+    { AF_BLUE_STRING_MAX,                         0                                 }
+
+  AF_BLUE_STRINGSET_LAO
+    { AF_BLUE_STRING_LAO_TOP,             AF_BLUE_PROPERTY_LATIN_TOP      |
+                                          AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
+    { AF_BLUE_STRING_LAO_BOTTOM,          0                                 }
+    { AF_BLUE_STRING_LAO_ASCENDER,        AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LAO_LARGE_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LAO_DESCENDER,       0                                 }
+    { AF_BLUE_STRING_MAX,                 0                                 }
+
   AF_BLUE_STRINGSET_LATN
     { AF_BLUE_STRING_LATIN_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
     { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM,  0                                 }
@@ -339,6 +458,34 @@
     { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0                                 }
     { AF_BLUE_STRING_MAX,                   0                                 }
 
+  AF_BLUE_STRINGSET_LATB
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM,  0                                 }
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL,           0                                 }
+    { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0                                 }
+    { AF_BLUE_STRING_MAX,                        0                                 }
+
+  AF_BLUE_STRINGSET_LATP
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM,  0                                 }
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP,     AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           AF_BLUE_PROPERTY_LATIN_TOP      |
+                                                 AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL,           0                                 }
+    { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0                                 }
+    { AF_BLUE_STRING_MAX,                        0                                 }
+
+  AF_BLUE_STRINGSET_MYMR
+    { AF_BLUE_STRING_MYANMAR_TOP,       AF_BLUE_PROPERTY_LATIN_TOP      |
+                                        AF_BLUE_PROPERTY_LATIN_X_HEIGHT   }
+    { AF_BLUE_STRING_MYANMAR_BOTTOM,    0                                 }
+    { AF_BLUE_STRING_MYANMAR_ASCENDER,  AF_BLUE_PROPERTY_LATIN_TOP        }
+    { AF_BLUE_STRING_MYANMAR_DESCENDER, 0                                 }
+    { AF_BLUE_STRING_MAX,               0                                 }
+
   AF_BLUE_STRINGSET_TELU
     { AF_BLUE_STRING_TELUGU_TOP,    AF_BLUE_PROPERTY_LATIN_TOP }
     { AF_BLUE_STRING_TELUGU_BOTTOM, 0                          }
diff --git a/src/autofit/afblue.h b/src/autofit/afblue.h
index 94e33a9..34f90e9 100644
--- a/src/autofit/afblue.h
+++ b/src/autofit/afblue.h
@@ -28,32 +28,35 @@
 
   /* an auxiliary macro to decode a UTF-8 character -- since we only use */
   /* hard-coded, self-converted data, no error checking is performed     */
-#define GET_UTF8_CHAR( ch, p )                    \
-          ch = (unsigned char)*p++;               \
-          if ( ch >= 0x80 )                       \
-          {                                       \
-            FT_UInt  len;                         \
-                                                  \
-                                                  \
-            if ( ch < 0xE0 )                      \
-            {                                     \
-              len = 1;                            \
-              ch &= 0x1F;                         \
-            }                                     \
-            else if ( ch < 0xF0 )                 \
-            {                                     \
-              len = 2;                            \
-              ch &= 0x0F;                         \
-            }                                     \
-            else                                  \
-            {                                     \
-              len = 3;                            \
-              ch &= 0x07;                         \
-            }                                     \
-                                                  \
-            for ( ; len > 0; len-- )              \
-              ch = ( ch << 6 ) | ( *p++ & 0x3F ); \
-          }
+#define GET_UTF8_CHAR( ch, p )                      \
+          do                                        \
+          {                                         \
+            ch = (unsigned char)*p++;               \
+            if ( ch >= 0x80 )                       \
+            {                                       \
+              FT_UInt  len_;                        \
+                                                    \
+                                                    \
+              if ( ch < 0xE0 )                      \
+              {                                     \
+                len_ = 1;                           \
+                ch  &= 0x1F;                        \
+              }                                     \
+              else if ( ch < 0xF0 )                 \
+              {                                     \
+                len_ = 2;                           \
+                ch  &= 0x0F;                        \
+              }                                     \
+              else                                  \
+              {                                     \
+                len_ = 3;                           \
+                ch  &= 0x07;                        \
+              }                                     \
+                                                    \
+              for ( ; len_ > 0; len_-- )            \
+                ch = ( ch << 6 ) | ( *p++ & 0x3F ); \
+            }                                       \
+          } while ( 0 )
 
 
   /*************************************************************************/
@@ -75,46 +78,73 @@
   typedef enum  AF_Blue_String_
   {
     AF_BLUE_STRING_ARABIC_TOP = 0,
-    AF_BLUE_STRING_ARABIC_JOIN = 13,
-    AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP = 24,
-    AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM = 41,
-    AF_BLUE_STRING_CYRILLIC_SMALL = 58,
-    AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER = 75,
-    AF_BLUE_STRING_DEVANAGARI_BASE = 82,
-    AF_BLUE_STRING_DEVANAGARI_TOP = 107,
-    AF_BLUE_STRING_DEVANAGARI_HEAD = 132,
-    AF_BLUE_STRING_DEVANAGARI_BOTTOM = 157,
-    AF_BLUE_STRING_GREEK_CAPITAL_TOP = 164,
-    AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM = 179,
-    AF_BLUE_STRING_GREEK_SMALL_BETA_TOP = 192,
-    AF_BLUE_STRING_GREEK_SMALL = 205,
-    AF_BLUE_STRING_GREEK_SMALL_DESCENDER = 222,
-    AF_BLUE_STRING_HEBREW_TOP = 239,
-    AF_BLUE_STRING_HEBREW_BOTTOM = 256,
-    AF_BLUE_STRING_HEBREW_DESCENDER = 269,
-    AF_BLUE_STRING_LATIN_CAPITAL_TOP = 280,
-    AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM = 289,
-    AF_BLUE_STRING_LATIN_SMALL_F_TOP = 298,
-    AF_BLUE_STRING_LATIN_SMALL = 306,
-    AF_BLUE_STRING_LATIN_SMALL_DESCENDER = 314,
-    AF_BLUE_STRING_TELUGU_TOP = 320,
-    AF_BLUE_STRING_TELUGU_BOTTOM = 342,
-    AF_BLUE_STRING_THAI_TOP = 364,
-    AF_BLUE_STRING_THAI_BOTTOM = 383,
-    AF_BLUE_STRING_THAI_ASCENDER = 405,
-    AF_BLUE_STRING_THAI_LARGE_ASCENDER = 415,
-    AF_BLUE_STRING_THAI_DESCENDER = 425,
-    AF_BLUE_STRING_THAI_LARGE_DESCENDER = 438,
-    AF_BLUE_STRING_THAI_DIGIT_TOP = 445,
-    af_blue_1_1 = 454,
+    AF_BLUE_STRING_ARABIC_BOTTOM = 18,
+    AF_BLUE_STRING_ARABIC_JOIN = 33,
+    AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP = 36,
+    AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM = 60,
+    AF_BLUE_STRING_CYRILLIC_SMALL = 84,
+    AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER = 108,
+    AF_BLUE_STRING_DEVANAGARI_BASE = 117,
+    AF_BLUE_STRING_DEVANAGARI_TOP = 149,
+    AF_BLUE_STRING_DEVANAGARI_HEAD = 181,
+    AF_BLUE_STRING_DEVANAGARI_BOTTOM = 213,
+    AF_BLUE_STRING_GREEK_CAPITAL_TOP = 221,
+    AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM = 242,
+    AF_BLUE_STRING_GREEK_SMALL_BETA_TOP = 260,
+    AF_BLUE_STRING_GREEK_SMALL = 278,
+    AF_BLUE_STRING_GREEK_SMALL_DESCENDER = 302,
+    AF_BLUE_STRING_HEBREW_TOP = 326,
+    AF_BLUE_STRING_HEBREW_BOTTOM = 350,
+    AF_BLUE_STRING_HEBREW_DESCENDER = 368,
+    AF_BLUE_STRING_KHMER_TOP = 383,
+    AF_BLUE_STRING_KHMER_SUBSCRIPT_TOP = 407,
+    AF_BLUE_STRING_KHMER_BOTTOM = 447,
+    AF_BLUE_STRING_KHMER_DESCENDER = 479,
+    AF_BLUE_STRING_KHMER_LARGE_DESCENDER = 513,
+    AF_BLUE_STRING_KHMER_SYMBOLS_WAXING_TOP = 600,
+    AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM = 608,
+    AF_BLUE_STRING_LAO_TOP = 616,
+    AF_BLUE_STRING_LAO_BOTTOM = 648,
+    AF_BLUE_STRING_LAO_ASCENDER = 680,
+    AF_BLUE_STRING_LAO_LARGE_ASCENDER = 696,
+    AF_BLUE_STRING_LAO_DESCENDER = 708,
+    AF_BLUE_STRING_LATIN_CAPITAL_TOP = 732,
+    AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM = 748,
+    AF_BLUE_STRING_LATIN_SMALL_F_TOP = 764,
+    AF_BLUE_STRING_LATIN_SMALL = 778,
+    AF_BLUE_STRING_LATIN_SMALL_DESCENDER = 792,
+    AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP = 802,
+    AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM = 822,
+    AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP = 842,
+    AF_BLUE_STRING_LATIN_SUBS_SMALL = 862,
+    AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER = 898,
+    AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP = 918,
+    AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM = 949,
+    AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP = 978,
+    AF_BLUE_STRING_LATIN_SUPS_SMALL = 1004,
+    AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER = 1029,
+    AF_BLUE_STRING_MYANMAR_TOP = 1040,
+    AF_BLUE_STRING_MYANMAR_BOTTOM = 1072,
+    AF_BLUE_STRING_MYANMAR_ASCENDER = 1104,
+    AF_BLUE_STRING_MYANMAR_DESCENDER = 1132,
+    AF_BLUE_STRING_TELUGU_TOP = 1164,
+    AF_BLUE_STRING_TELUGU_BOTTOM = 1192,
+    AF_BLUE_STRING_THAI_TOP = 1220,
+    AF_BLUE_STRING_THAI_BOTTOM = 1244,
+    AF_BLUE_STRING_THAI_ASCENDER = 1272,
+    AF_BLUE_STRING_THAI_LARGE_ASCENDER = 1284,
+    AF_BLUE_STRING_THAI_DESCENDER = 1296,
+    AF_BLUE_STRING_THAI_LARGE_DESCENDER = 1312,
+    AF_BLUE_STRING_THAI_DIGIT_TOP = 1320,
+    af_blue_1_1 = 1331,
 #ifdef AF_CONFIG_OPTION_CJK
     AF_BLUE_STRING_CJK_TOP = af_blue_1_1 + 1,
-    AF_BLUE_STRING_CJK_BOTTOM = af_blue_1_1 + 153,
-    af_blue_1_1_1 = af_blue_1_1 + 304,
+    AF_BLUE_STRING_CJK_BOTTOM = af_blue_1_1 + 203,
+    af_blue_1_1_1 = af_blue_1_1 + 404,
 #ifdef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
     AF_BLUE_STRING_CJK_LEFT = af_blue_1_1_1 + 1,
-    AF_BLUE_STRING_CJK_RIGHT = af_blue_1_1_1 + 153,
-    af_blue_1_1_2 = af_blue_1_1_1 + 304,
+    AF_BLUE_STRING_CJK_RIGHT = af_blue_1_1_1 + 204,
+    af_blue_1_1_2 = af_blue_1_1_1 + 405,
 #else
     af_blue_1_1_2 = af_blue_1_1_1 + 0,
 #endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
@@ -148,9 +178,10 @@
   /* blue string can't be used in more than a single writing system, which */
   /* is a safe bet.                                                        */
 #define AF_BLUE_PROPERTY_LATIN_TOP       ( 1U << 0 )  /* must have value 1 */
-#define AF_BLUE_PROPERTY_LATIN_NEUTRAL   ( 1U << 1 )
-#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT  ( 1U << 2 )
-#define AF_BLUE_PROPERTY_LATIN_LONG      ( 1U << 3 )
+#define AF_BLUE_PROPERTY_LATIN_SUB_TOP   ( 1U << 1 )
+#define AF_BLUE_PROPERTY_LATIN_NEUTRAL   ( 1U << 2 )
+#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT  ( 1U << 3 )
+#define AF_BLUE_PROPERTY_LATIN_LONG      ( 1U << 4 )
 
 #define AF_BLUE_PROPERTY_CJK_TOP    ( 1U << 0 )       /* must have value 1 */
 #define AF_BLUE_PROPERTY_CJK_HORIZ  ( 1U << 1 )       /* must have value 2 */
@@ -165,14 +196,20 @@
   typedef enum  AF_Blue_Stringset_
   {
     AF_BLUE_STRINGSET_ARAB = 0,
-    AF_BLUE_STRINGSET_CYRL = 3,
-    AF_BLUE_STRINGSET_DEVA = 9,
-    AF_BLUE_STRINGSET_GREK = 15,
-    AF_BLUE_STRINGSET_HEBR = 22,
-    AF_BLUE_STRINGSET_LATN = 26,
-    AF_BLUE_STRINGSET_TELU = 33,
-    AF_BLUE_STRINGSET_THAI = 36,
-    af_blue_2_1 = 44,
+    AF_BLUE_STRINGSET_CYRL = 4,
+    AF_BLUE_STRINGSET_DEVA = 10,
+    AF_BLUE_STRINGSET_GREK = 16,
+    AF_BLUE_STRINGSET_HEBR = 23,
+    AF_BLUE_STRINGSET_KHMR = 27,
+    AF_BLUE_STRINGSET_KHMS = 33,
+    AF_BLUE_STRINGSET_LAO = 36,
+    AF_BLUE_STRINGSET_LATN = 42,
+    AF_BLUE_STRINGSET_LATB = 49,
+    AF_BLUE_STRINGSET_LATP = 56,
+    AF_BLUE_STRINGSET_MYMR = 63,
+    AF_BLUE_STRINGSET_TELU = 68,
+    AF_BLUE_STRINGSET_THAI = 71,
+    af_blue_2_1 = 79,
 #ifdef AF_CONFIG_OPTION_CJK
     AF_BLUE_STRINGSET_HANI = af_blue_2_1 + 0,
     af_blue_2_1_1 = af_blue_2_1 + 2,
diff --git a/src/autofit/afblue.hin b/src/autofit/afblue.hin
index ad43fe6..1eb9172 100644
--- a/src/autofit/afblue.hin
+++ b/src/autofit/afblue.hin
@@ -25,32 +25,35 @@
 
   /* an auxiliary macro to decode a UTF-8 character -- since we only use */
   /* hard-coded, self-converted data, no error checking is performed     */
-#define GET_UTF8_CHAR( ch, p )                    \
-          ch = (unsigned char)*p++;               \
-          if ( ch >= 0x80 )                       \
-          {                                       \
-            FT_UInt  len;                         \
-                                                  \
-                                                  \
-            if ( ch < 0xE0 )                      \
-            {                                     \
-              len = 1;                            \
-              ch &= 0x1F;                         \
-            }                                     \
-            else if ( ch < 0xF0 )                 \
-            {                                     \
-              len = 2;                            \
-              ch &= 0x0F;                         \
-            }                                     \
-            else                                  \
-            {                                     \
-              len = 3;                            \
-              ch &= 0x07;                         \
-            }                                     \
-                                                  \
-            for ( ; len > 0; len-- )              \
-              ch = ( ch << 6 ) | ( *p++ & 0x3F ); \
-          }
+#define GET_UTF8_CHAR( ch, p )                      \
+          do                                        \
+          {                                         \
+            ch = (unsigned char)*p++;               \
+            if ( ch >= 0x80 )                       \
+            {                                       \
+              FT_UInt  len_;                        \
+                                                    \
+                                                    \
+              if ( ch < 0xE0 )                      \
+              {                                     \
+                len_ = 1;                           \
+                ch  &= 0x1F;                        \
+              }                                     \
+              else if ( ch < 0xF0 )                 \
+              {                                     \
+                len_ = 2;                           \
+                ch  &= 0x0F;                        \
+              }                                     \
+              else                                  \
+              {                                     \
+                len_ = 3;                           \
+                ch  &= 0x07;                        \
+              }                                     \
+                                                    \
+              for ( ; len_ > 0; len_-- )            \
+                ch = ( ch << 6 ) | ( *p++ & 0x3F ); \
+            }                                       \
+          } while ( 0 )
 
 
   /*************************************************************************/
@@ -97,9 +100,10 @@
   /* blue string can't be used in more than a single writing system, which */
   /* is a safe bet.                                                        */
 #define AF_BLUE_PROPERTY_LATIN_TOP       ( 1U << 0 )  /* must have value 1 */
-#define AF_BLUE_PROPERTY_LATIN_NEUTRAL   ( 1U << 1 )
-#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT  ( 1U << 2 )
-#define AF_BLUE_PROPERTY_LATIN_LONG      ( 1U << 3 )
+#define AF_BLUE_PROPERTY_LATIN_SUB_TOP   ( 1U << 1 )
+#define AF_BLUE_PROPERTY_LATIN_NEUTRAL   ( 1U << 2 )
+#define AF_BLUE_PROPERTY_LATIN_X_HEIGHT  ( 1U << 3 )
+#define AF_BLUE_PROPERTY_LATIN_LONG      ( 1U << 4 )
 
 #define AF_BLUE_PROPERTY_CJK_TOP    ( 1U << 0 )       /* must have value 1 */
 #define AF_BLUE_PROPERTY_CJK_HORIZ  ( 1U << 1 )       /* must have value 2 */
diff --git a/src/autofit/afcjk.c b/src/autofit/afcjk.c
index 905408b..73d75ae 100644
--- a/src/autofit/afcjk.c
+++ b/src/autofit/afcjk.c
@@ -88,7 +88,6 @@
     {
       FT_Error          error;
       FT_ULong          glyph_index;
-      FT_Long           y_offset;
       int               dim;
       AF_CJKMetricsRec  dummy[1];
       AF_Scaler         scaler = &dummy->root.scaler;
@@ -101,45 +100,61 @@
       AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
                                        [style_class->script];
 
-      FT_UInt32  standard_char;
+      void*        shaper_buf;
+      const char*  p;
 
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_ULong  ch;
+#endif
 
-      standard_char = script_class->standard_char1;
-      af_get_char_index( &metrics->root,
-                         standard_char,
-                         &glyph_index,
-                         &y_offset );
-      if ( !glyph_index )
+      p          = script_class->standard_charstring;
+      shaper_buf = af_shaper_buf_create( face );
+
+      /* We check a list of standard characters.  The first match wins. */
+
+      glyph_index = 0;
+      while ( *p )
       {
-        if ( script_class->standard_char2 )
-        {
-          standard_char = script_class->standard_char2;
-          af_get_char_index( &metrics->root,
-                             standard_char,
-                             &glyph_index,
-                             &y_offset );
-          if ( !glyph_index )
-          {
-            if ( script_class->standard_char3 )
-            {
-              standard_char = script_class->standard_char3;
-              af_get_char_index( &metrics->root,
-                                 standard_char,
-                                 &glyph_index,
-                                 &y_offset );
-              if ( !glyph_index )
-                goto Exit;
-            }
-            else
-              goto Exit;
-          }
-        }
-        else
-          goto Exit;
+        unsigned int  num_idx;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        const char*  p_old;
+#endif
+
+
+        while ( *p == ' ' )
+          p++;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        p_old = p;
+        GET_UTF8_CHAR( ch, p_old );
+#endif
+
+        /* reject input that maps to more than a single glyph */
+        p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
+        if ( num_idx > 1 )
+          continue;
+
+        /* otherwise exit loop if we have a result */
+        glyph_index = af_shaper_get_elem( &metrics->root,
+                                          shaper_buf,
+                                          0,
+                                          NULL,
+                                          NULL );
+        if ( glyph_index )
+          break;
       }
 
+      af_shaper_buf_destroy( face, shaper_buf );
+
+      if ( !glyph_index )
+        goto Exit;
+
+      if ( !glyph_index )
+        goto Exit;
+
       FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
-                  standard_char, glyph_index ));
+                  ch, glyph_index ));
 
       error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
       if ( error || face->glyph->outline.n_points <= 0 )
@@ -177,6 +192,12 @@
         if ( error )
           goto Exit;
 
+        /*
+         *  We assume that the glyphs selected for the stem width
+         *  computation are `featureless' enough so that the linking
+         *  algorithm works fine without adjustments of its scoring
+         *  function.
+         */
         af_latin_hints_link_segments( hints,
                                       0,
                                       NULL,
@@ -275,6 +296,8 @@
     AF_Blue_Stringset         bss = sc->blue_stringset;
     const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
 
+    void*  shaper_buf;
+
 
     /* we walk over the blue character strings as specified in the   */
     /* style's entry in the `af_blue_stringset' array, computing its */
@@ -284,6 +307,8 @@
                 "==========================\n"
                 "\n" ));
 
+    shaper_buf = af_shaper_buf_create( face );
+
     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
     {
       const char*  p = &af_blue_strings[bs->string];
@@ -322,26 +347,47 @@
 
       while ( *p )
       {
-        FT_ULong    ch;
         FT_ULong    glyph_index;
-        FT_Long     y_offset;
         FT_Pos      best_pos;       /* same as points.y or points.x, resp. */
         FT_Int      best_point;
         FT_Vector*  points;
 
+        unsigned int  num_idx;
 
-        GET_UTF8_CHAR( ch, p );
+#ifdef FT_DEBUG_LEVEL_TRACE
+        const char*  p_old;
+        FT_ULong     ch;
+#endif
+
+
+        while ( *p == ' ' )
+          p++;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        p_old = p;
+        GET_UTF8_CHAR( ch, p_old );
+#endif
 
         /* switch to characters that define flat values */
-        if ( ch == '|' )
+        if ( *p == '|' )
         {
           fill = 0;
           FT_TRACE5(( "  [reference values]\n" ));
+          p++;
           continue;
         }
 
+        /* reject input that maps to more than a single glyph */
+        p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
+        if ( num_idx > 1 )
+          continue;
+
         /* load the character in the face -- skip unknown or empty ones */
-        af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset );
+        glyph_index = af_shaper_get_elem( &metrics->root,
+                                          shaper_buf,
+                                          0,
+                                          NULL,
+                                          NULL );
         if ( glyph_index == 0 )
         {
           FT_TRACE5(( "  U+%04lX unavailable\n", ch ));
@@ -350,9 +396,9 @@
 
         error   = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
         outline = face->glyph->outline;
-        if ( error || outline.n_points <= 0 )
+        if ( error || outline.n_points <= 2 )
         {
-          FT_TRACE5(( "  U+%04lX contains no outlines\n", ch ));
+          FT_TRACE5(( "  U+%04lX contains no (usable) outlines\n", ch ));
           continue;
         }
 
@@ -431,7 +477,8 @@
           fills[num_fills++] = best_pos;
         else
           flats[num_flats++] = best_pos;
-      }
+
+      } /* end while loop */
 
       if ( num_flats == 0 && num_fills == 0 )
       {
@@ -498,7 +545,10 @@
       FT_TRACE5(( "    -> reference = %ld\n"
                   "       overshoot = %ld\n",
                   *blue_ref, *blue_shoot ));
-    }
+
+    } /* end for loop */
+
+    af_shaper_buf_destroy( face, shaper_buf );
 
     FT_TRACE5(( "\n" ));
 
@@ -512,27 +562,36 @@
   af_cjk_metrics_check_digits( AF_CJKMetrics  metrics,
                                FT_Face        face )
   {
-    FT_UInt   i;
     FT_Bool   started = 0, same_width = 1;
     FT_Fixed  advance, old_advance = 0;
 
+    void*  shaper_buf;
 
-    /* digit `0' is 0x30 in all supported charmaps */
-    for ( i = 0x30; i <= 0x39; i++ )
+    /* in all supported charmaps, digits have character codes 0x30-0x39 */
+    const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
+    const char*  p;
+
+
+    p          = digits;
+    shaper_buf = af_shaper_buf_create( face );
+
+    while ( *p )
     {
-      FT_ULong  glyph_index;
-      FT_Long   y_offset;
+      FT_ULong      glyph_index;
+      unsigned int  num_idx;
 
 
-      af_get_char_index( &metrics->root, i, &glyph_index, &y_offset );
-      if ( glyph_index == 0 )
+      /* reject input that maps to more than a single glyph */
+      p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
+      if ( num_idx > 1 )
         continue;
 
-      if ( FT_Get_Advance( face, glyph_index,
-                           FT_LOAD_NO_SCALE         |
-                           FT_LOAD_NO_HINTING       |
-                           FT_LOAD_IGNORE_TRANSFORM,
-                           &advance ) )
+      glyph_index = af_shaper_get_elem( &metrics->root,
+                                        shaper_buf,
+                                        0,
+                                        &advance,
+                                        NULL );
+      if ( !glyph_index )
         continue;
 
       if ( started )
@@ -550,6 +609,8 @@
       }
     }
 
+    af_shaper_buf_destroy( face, shaper_buf );
+
     metrics->root.digits_have_same_width = same_width;
   }
 
@@ -688,6 +749,22 @@
   }
 
 
+  /* Extract standard_width from writing system/script specific */
+  /* metrics class.                                             */
+
+  FT_LOCAL_DEF( void )
+  af_cjk_get_standard_widths( AF_CJKMetrics  metrics,
+                              FT_Pos*        stdHW,
+                              FT_Pos*        stdVW )
+  {
+    if ( stdHW )
+      *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
+
+    if ( stdVW )
+      *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
+  }
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -2181,7 +2258,8 @@
   /* Apply the complete hinting algorithm to a CJK glyph. */
 
   FT_LOCAL_DEF( FT_Error )
-  af_cjk_hints_apply( AF_GlyphHints  hints,
+  af_cjk_hints_apply( FT_UInt        glyph_index,
+                      AF_GlyphHints  hints,
                       FT_Outline*    outline,
                       AF_CJKMetrics  metrics )
   {
@@ -2189,6 +2267,7 @@
     int       dim;
 
     FT_UNUSED( metrics );
+    FT_UNUSED( glyph_index );
 
 
     error = af_glyph_hints_reload( hints, outline );
@@ -2278,6 +2357,7 @@
     (AF_WritingSystem_InitMetricsFunc) af_cjk_metrics_init,
     (AF_WritingSystem_ScaleMetricsFunc)af_cjk_metrics_scale,
     (AF_WritingSystem_DoneMetricsFunc) NULL,
+    (AF_WritingSystem_GetStdWidthsFunc)af_cjk_get_standard_widths,
 
     (AF_WritingSystem_InitHintsFunc)   af_cjk_hints_init,
     (AF_WritingSystem_ApplyHintsFunc)  af_cjk_hints_apply
@@ -2297,6 +2377,7 @@
     (AF_WritingSystem_InitMetricsFunc) NULL,
     (AF_WritingSystem_ScaleMetricsFunc)NULL,
     (AF_WritingSystem_DoneMetricsFunc) NULL,
+    (AF_WritingSystem_GetStdWidthsFunc)NULL,
 
     (AF_WritingSystem_InitHintsFunc)   NULL,
     (AF_WritingSystem_ApplyHintsFunc)  NULL
diff --git a/src/autofit/afcjk.h b/src/autofit/afcjk.h
index bfd11f2..e395e74 100644
--- a/src/autofit/afcjk.h
+++ b/src/autofit/afcjk.h
@@ -115,7 +115,8 @@
                      AF_CJKMetrics  metrics );
 
   FT_LOCAL( FT_Error )
-  af_cjk_hints_apply( AF_GlyphHints  hints,
+  af_cjk_hints_apply( FT_UInt        glyph_index,
+                      AF_GlyphHints  hints,
                       FT_Outline*    outline,
                       AF_CJKMetrics  metrics );
 
diff --git a/src/autofit/afdummy.c b/src/autofit/afdummy.c
index 03ca25f..9142c78 100644
--- a/src/autofit/afdummy.c
+++ b/src/autofit/afdummy.c
@@ -38,11 +38,14 @@
 
 
   static FT_Error
-  af_dummy_hints_apply( AF_GlyphHints  hints,
+  af_dummy_hints_apply( FT_UInt        glyph_index,
+                        AF_GlyphHints  hints,
                         FT_Outline*    outline )
   {
     FT_Error  error;
 
+    FT_UNUSED( glyph_index );
+
 
     error = af_glyph_hints_reload( hints, outline );
     if ( !error )
@@ -62,6 +65,7 @@
     (AF_WritingSystem_InitMetricsFunc) NULL,
     (AF_WritingSystem_ScaleMetricsFunc)NULL,
     (AF_WritingSystem_DoneMetricsFunc) NULL,
+    (AF_WritingSystem_GetStdWidthsFunc)NULL,
 
     (AF_WritingSystem_InitHintsFunc)   af_dummy_hints_init,
     (AF_WritingSystem_ApplyHintsFunc)  af_dummy_hints_apply
diff --git a/src/autofit/afglobal.c b/src/autofit/afglobal.c
index 64b9293..3223358 100644
--- a/src/autofit/afglobal.c
+++ b/src/autofit/afglobal.c
@@ -18,7 +18,7 @@
 
 #include "afglobal.h"
 #include "afranges.h"
-#include "hbshim.h"
+#include "afshaper.h"
 #include FT_INTERNAL_DEBUG_H
 
 
@@ -42,12 +42,13 @@
 
 
 #undef  SCRIPT
-#define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) \
+#define SCRIPT( s, S, d, h, ss ) \
           AF_DEFINE_SCRIPT_CLASS(           \
             af_ ## s ## _script_class,      \
             AF_SCRIPT_ ## S,                \
             af_ ## s ## _uniranges,         \
-            sc1, sc2, sc3 )
+            af_ ## s ## _nonbase_uniranges, \
+            ss )
 
 #include "afscript.h"
 
@@ -82,7 +83,7 @@
 
 
 #undef  SCRIPT
-#define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) \
+#define SCRIPT( s, S, d, h, ss ) \
           &af_ ## s ## _script_class,
 
   FT_LOCAL_ARRAY_DEF( AF_ScriptClass )
@@ -135,16 +136,15 @@
     FT_Error    error;
     FT_Face     face        = globals->face;
     FT_CharMap  old_charmap = face->charmap;
-    FT_Byte*    gstyles     = globals->glyph_styles;
+    FT_UShort*  gstyles     = globals->glyph_styles;
     FT_UInt     ss;
     FT_UInt     i;
     FT_UInt     dflt        = ~0U; /* a non-valid value */
 
 
     /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */
-    FT_MEM_SET( globals->glyph_styles,
-                AF_STYLE_UNASSIGNED,
-                globals->glyph_count );
+    for ( i = 0; i < (FT_UInt)globals->glyph_count; i++ )
+      gstyles[i] = AF_STYLE_UNASSIGNED;
 
     error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
     if ( error )
@@ -190,10 +190,10 @@
 
           gindex = FT_Get_Char_Index( face, charcode );
 
-          if ( gindex != 0                             &&
-               gindex < (FT_ULong)globals->glyph_count &&
-               gstyles[gindex] == AF_STYLE_UNASSIGNED  )
-            gstyles[gindex] = (FT_Byte)ss;
+          if ( gindex != 0                                                &&
+               gindex < (FT_ULong)globals->glyph_count                    &&
+               ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
+            gstyles[gindex] = (FT_UShort)ss;
 
           for (;;)
           {
@@ -202,21 +202,50 @@
             if ( gindex == 0 || charcode > range->last )
               break;
 
-            if ( gindex < (FT_ULong)globals->glyph_count &&
-                 gstyles[gindex] == AF_STYLE_UNASSIGNED  )
-              gstyles[gindex] = (FT_Byte)ss;
+            if ( gindex < (FT_ULong)globals->glyph_count                    &&
+                 ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
+              gstyles[gindex] = (FT_UShort)ss;
+          }
+        }
+
+        /* do the same for the script's non-base characters */
+        for ( range = script_class->script_uni_nonbase_ranges;
+              range->first != 0;
+              range++ )
+        {
+          FT_ULong  charcode = range->first;
+          FT_UInt   gindex;
+
+
+          gindex = FT_Get_Char_Index( face, charcode );
+
+          if ( gindex != 0                                          &&
+               gindex < (FT_ULong)globals->glyph_count              &&
+               ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss )
+            gstyles[gindex] |= AF_NONBASE;
+
+          for (;;)
+          {
+            charcode = FT_Get_Next_Char( face, charcode, &gindex );
+
+            if ( gindex == 0 || charcode > range->last )
+              break;
+
+            if ( gindex < (FT_ULong)globals->glyph_count              &&
+                 ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss )
+              gstyles[gindex] |= AF_NONBASE;
           }
         }
       }
       else
       {
         /* get glyphs not directly addressable by cmap */
-        af_get_coverage( globals, style_class, gstyles );
+        af_shaper_get_coverage( globals, style_class, gstyles );
       }
     }
 
     /* handle the default OpenType features of the default script ... */
-    af_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles );
+    af_shaper_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles );
 
     /* ... and the remaining default OpenType features */
     for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ )
@@ -225,7 +254,7 @@
 
 
       if ( ss != dflt && style_class->coverage == AF_COVERAGE_DEFAULT )
-        af_get_coverage( globals, style_class, gstyles );
+        af_shaper_get_coverage( globals, style_class, gstyles );
     }
 
     /* mark ASCII digits */
@@ -250,9 +279,9 @@
 
       for ( nn = 0; nn < globals->glyph_count; nn++ )
       {
-        if ( ( gstyles[nn] & ~AF_DIGIT ) == AF_STYLE_UNASSIGNED )
+        if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
         {
-          gstyles[nn] &= ~AF_STYLE_UNASSIGNED;
+          gstyles[nn] &= ~AF_STYLE_MASK;
           gstyles[nn] |= globals->module->fallback_style;
         }
       }
@@ -276,7 +305,7 @@
 
       for ( idx = 0; idx < globals->glyph_count; idx++ )
       {
-        if ( ( gstyles[idx] & ~AF_DIGIT ) == style_class->style )
+        if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style )
         {
           if ( !( count % 10 ) )
             FT_TRACE4(( " " ));
@@ -314,18 +343,28 @@
 
     memory = face->memory;
 
+    /* we allocate an AF_FaceGlobals structure together */
+    /* with the glyph_styles array                      */
     if ( FT_ALLOC( globals,
                    sizeof ( *globals ) +
-                     (FT_ULong)face->num_glyphs * sizeof ( FT_Byte ) ) )
+                     (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) )
       goto Exit;
 
-    globals->face         = face;
-    globals->glyph_count  = face->num_glyphs;
-    globals->glyph_styles = (FT_Byte*)( globals + 1 );
-    globals->module       = module;
+    globals->face                      = face;
+    globals->glyph_count               = face->num_glyphs;
+    /* right after the globals structure come the glyph styles */
+    globals->glyph_styles              = (FT_UShort*)( globals + 1 );
+    globals->module                    = module;
+    globals->stem_darkening_for_ppem   = 0;
+    globals->darken_x                  = 0;
+    globals->darken_y                  = 0;
+    globals->standard_vertical_width   = 0;
+    globals->standard_horizontal_width = 0;
+    globals->scale_down_factor         = 0;
 
 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
     globals->hb_font = hb_ft_font_create( face, NULL );
+    globals->hb_buf  = hb_buffer_create();
 #endif
 
     error = af_face_globals_compute_style_coverage( globals );
@@ -372,11 +411,21 @@
 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
       hb_font_destroy( globals->hb_font );
       globals->hb_font = NULL;
+
+      hb_buffer_destroy( globals->hb_buf );
+      globals->hb_buf = NULL;
 #endif
 
-      globals->glyph_count  = 0;
-      globals->glyph_styles = NULL;  /* no need to free this one! */
-      globals->face         = NULL;
+      globals->glyph_count               = 0;
+      globals->stem_darkening_for_ppem   = 0;
+      globals->darken_x                  = 0;
+      globals->darken_y                  = 0;
+      globals->standard_vertical_width   = 0;
+      globals->standard_horizontal_width = 0;
+      globals->scale_down_factor         = 0;
+      /* no need to free this one! */
+      globals->glyph_styles              = NULL;
+      globals->face                      = NULL;
 
       FT_FREE( globals );
     }
diff --git a/src/autofit/afglobal.h b/src/autofit/afglobal.h
index 9bbb687..5b4e439 100644
--- a/src/autofit/afglobal.h
+++ b/src/autofit/afglobal.h
@@ -23,7 +23,7 @@
 
 #include "aftypes.h"
 #include "afmodule.h"
-#include "hbshim.h"
+#include "afshaper.h"
 
 
 FT_BEGIN_HEADER
@@ -34,7 +34,7 @@
 
 
 #undef  SCRIPT
-#define SCRIPT( s, S, d, h, sc1, sc2, sc3 )                    \
+#define SCRIPT( s, S, d, h, ss )                               \
           AF_DECLARE_SCRIPT_CLASS( af_ ## s ## _script_class )
 
 #include "afscript.h"
@@ -72,10 +72,16 @@
 #endif
   /* default script for OpenType; ignored if HarfBuzz isn't used */
 #define AF_SCRIPT_DEFAULT    AF_SCRIPT_LATN
-  /* a bit mask indicating an uncovered glyph        */
-#define AF_STYLE_UNASSIGNED  0x7F
-  /* if this flag is set, we have an ASCII digit     */
-#define AF_DIGIT             0x80
+
+  /* a bit mask for AF_DIGIT and AF_NONBASE */
+#define AF_STYLE_MASK        0x3FFF
+  /* an uncovered glyph      */
+#define AF_STYLE_UNASSIGNED  AF_STYLE_MASK
+
+  /* if this flag is set, we have an ASCII digit   */
+#define AF_DIGIT             0x8000U
+  /* if this flag is set, we have a non-base character */
+#define AF_NONBASE           0x4000U
 
   /* `increase-x-height' property */
 #define AF_PROP_INCREASE_X_HEIGHT_MIN  6
@@ -100,10 +106,11 @@
   {
     FT_Face          face;
     FT_Long          glyph_count;    /* same as face->num_glyphs */
-    FT_Byte*         glyph_styles;
+    FT_UShort*       glyph_styles;
 
 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
     hb_font_t*       hb_font;
+    hb_buffer_t*     hb_buf;           /* for feature comparison */
 #endif
 
     /* per-face auto-hinter properties */
@@ -111,6 +118,22 @@
 
     AF_StyleMetrics  metrics[AF_STYLE_MAX];
 
+    /* Compute darkening amount once per size.  Use this to check whether */
+    /* darken_{x,y} needs to be recomputed.                               */
+    FT_UShort        stem_darkening_for_ppem;
+    /* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_HORZ] */
+    /* to compute the darkening amount.                       */
+    FT_Pos           standard_vertical_width;
+    /* Copy from e.g. AF_LatinMetrics.axis[AF_DIMENSION_VERT] */
+    /* to compute the darkening amount.                       */
+    FT_Pos           standard_horizontal_width;
+    /* The actual amount to darken a glyph along the X axis. */
+    FT_Pos           darken_x;
+    /* The actual amount to darken a glyph along the Y axis. */
+    FT_Pos           darken_y;
+    /* Amount to scale down by to keep emboldened points */
+    /* on the Y-axis in pre-computed blue zones.         */
+    FT_Fixed         scale_down_factor;
     AF_Module        module;         /* to access global properties */
 
   } AF_FaceGlobalsRec;
diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c
index 37482eb..56c8220 100644
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -219,6 +219,82 @@
 #define AF_INDEX_NUM( ptr, base )  (int)( (ptr) ? ( (ptr) - (base) ) : -1 )
 
 
+  static char*
+  af_print_idx( char* p,
+                int   idx )
+  {
+    if ( idx == -1 )
+    {
+      p[0] = '-';
+      p[1] = '-';
+      p[2] = '\0';
+    }
+    else
+      ft_sprintf( p, "%d", idx );
+
+    return p;
+  }
+
+
+  static int
+  af_get_segment_index( AF_GlyphHints  hints,
+                        int            point_idx,
+                        int            dimension )
+  {
+    AF_AxisHints  axis     = &hints->axis[dimension];
+    AF_Point      point    = hints->points + point_idx;
+    AF_Segment    segments = axis->segments;
+    AF_Segment    limit    = segments + axis->num_segments;
+    AF_Segment    segment;
+
+
+    for ( segment = segments; segment < limit; segment++ )
+    {
+      if ( segment->first <= segment->last )
+      {
+        if ( point >= segment->first && point <= segment->last )
+          break;
+      }
+      else
+      {
+        AF_Point  p = segment->first;
+
+
+        for (;;)
+        {
+          if ( point == p )
+            goto Exit;
+
+          if ( p == segment->last )
+            break;
+
+          p = p->next;
+        }
+      }
+    }
+
+  Exit:
+    if ( segment == limit )
+      return -1;
+
+    return (int)( segment - segments );
+  }
+
+
+  static int
+  af_get_edge_index( AF_GlyphHints  hints,
+                     int            segment_idx,
+                     int            dimension )
+  {
+    AF_AxisHints  axis    = &hints->axis[dimension];
+    AF_Edge       edges   = axis->edges;
+    AF_Segment    segment = axis->segments + segment_idx;
+
+
+    return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
+  }
+
+
 #ifdef __cplusplus
   extern "C" {
 #endif
@@ -234,22 +310,39 @@
     AF_DUMP(( "Table of points:\n" ));
 
     if ( hints->num_points )
-      AF_DUMP(( "  [ index |  xorg |  yorg | xscale | yscale"
-                " |  xfit |  yfit |  flags ]\n" ));
+      AF_DUMP(( "  index  hedge  hseg  vedge  vseg  flags"
+                "  xorg  yorg  xscale  yscale   xfit    yfit\n" ));
     else
       AF_DUMP(( "  (none)\n" ));
 
     for ( point = points; point < limit; point++ )
-      AF_DUMP(( "  [ %5d | %5d | %5d | %6.2f | %6.2f"
-                " | %5.2f | %5.2f | %c ]\n",
-                AF_INDEX_NUM( point, points ),
+    {
+      int  point_idx     = AF_INDEX_NUM( point, points );
+      int  segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
+      int  segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );
+
+      char  buf1[16], buf2[16], buf3[16], buf4[16];
+
+
+      AF_DUMP(( "  %5d  %5s %5s  %5s %5s  %s "
+                " %5d %5d %7.2f %7.2f %7.2f %7.2f\n",
+                point_idx,
+                af_print_idx( buf1,
+                              af_get_edge_index( hints, segment_idx_1, 1 ) ),
+                af_print_idx( buf2, segment_idx_1 ),
+                af_print_idx( buf3,
+                              af_get_edge_index( hints, segment_idx_0, 0 ) ),
+                af_print_idx( buf4, segment_idx_0 ),
+                ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? "weak"
+                                                              : " -- ",
+
                 point->fx,
                 point->fy,
                 point->ox / 64.0,
                 point->oy / 64.0,
                 point->x / 64.0,
-                point->y / 64.0,
-                ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' '));
+                point->y / 64.0 ));
+    }
     AF_DUMP(( "\n" ));
   }
 #ifdef __cplusplus
@@ -306,21 +399,23 @@
       AF_Segment    limit    = segments + axis->num_segments;
       AF_Segment    seg;
 
+      char  buf1[16], buf2[16], buf3[16];
+
 
       AF_DUMP(( "Table of %s segments:\n",
                 dimension == AF_DIMENSION_HORZ ? "vertical"
                                                : "horizontal" ));
       if ( axis->num_segments )
-        AF_DUMP(( "  [ index |  pos  |  dir  | from"
-                  " |  to  | link | serif | edge"
-                  " | height | extra |    flags    ]\n" ));
+        AF_DUMP(( "  index   pos    dir   from   to"
+                  "   link  serif  edge"
+                  "  height  extra     flags\n" ));
       else
         AF_DUMP(( "  (none)\n" ));
 
       for ( seg = segments; seg < limit; seg++ )
-        AF_DUMP(( "  [ %5d | %5.2g | %5s | %4d"
-                  " | %4d | %4d | %5d | %4d"
-                  " | %6d | %5d | %11s ]\n",
+        AF_DUMP(( "  %5d  %5.2g  %5s  %4d  %4d"
+                  "  %4s  %5s  %4s"
+                  "  %6d  %5d  %11s\n",
                   AF_INDEX_NUM( seg, segments ),
                   dimension == AF_DIMENSION_HORZ
                                ? (int)seg->first->ox / 64.0
@@ -328,9 +423,11 @@
                   af_dir_str( (AF_Direction)seg->dir ),
                   AF_INDEX_NUM( seg->first, points ),
                   AF_INDEX_NUM( seg->last, points ),
-                  AF_INDEX_NUM( seg->link, segments ),
-                  AF_INDEX_NUM( seg->serif, segments ),
-                  AF_INDEX_NUM( seg->edge, edges ),
+
+                  af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
+                  af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
+                  af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
+
                   seg->height,
                   seg->height - ( seg->max_coord - seg->min_coord ),
                   af_edge_flags_to_string( seg->flags ) ));
@@ -435,6 +532,8 @@
       AF_Edge       limit = edges + axis->num_edges;
       AF_Edge       edge;
 
+      char  buf1[16], buf2[16];
+
 
       /*
        *  note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
@@ -444,19 +543,20 @@
                 dimension == AF_DIMENSION_HORZ ? "vertical"
                                                : "horizontal" ));
       if ( axis->num_edges )
-        AF_DUMP(( "  [ index |  pos  |  dir  | link"
-                  " | serif | blue | opos  |  pos  |    flags    ]\n" ));
+        AF_DUMP(( "  index   pos    dir   link  serif"
+                  "  blue  opos    pos      flags\n" ));
       else
         AF_DUMP(( "  (none)\n" ));
 
       for ( edge = edges; edge < limit; edge++ )
-        AF_DUMP(( "  [ %5d | %5.2g | %5s | %4d"
-                  " | %5d |   %c  | %5.2f | %5.2f | %11s ]\n",
+        AF_DUMP(( "  %5d  %5.2g  %5s  %4s  %5s"
+                  "    %c   %5.2f  %5.2f  %11s\n",
                   AF_INDEX_NUM( edge, edges ),
                   (int)edge->opos / 64.0,
                   af_dir_str( (AF_Direction)edge->dir ),
-                  AF_INDEX_NUM( edge->link, edges ),
-                  AF_INDEX_NUM( edge->serif, edges ),
+                  af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
+                  af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
+
                   edge->blue_edge ? 'y' : 'n',
                   edge->opos / 64.0,
                   edge->pos / 64.0,
diff --git a/src/autofit/afindic.c b/src/autofit/afindic.c
index 7412cd1..59b14d7 100644
--- a/src/autofit/afindic.c
+++ b/src/autofit/afindic.c
@@ -79,12 +79,29 @@
 
 
   static FT_Error
-  af_indic_hints_apply( AF_GlyphHints  hints,
+  af_indic_hints_apply( FT_UInt        glyph_index,
+                        AF_GlyphHints  hints,
                         FT_Outline*    outline,
                         AF_CJKMetrics  metrics )
   {
     /* use CJK routines */
-    return af_cjk_hints_apply( hints, outline, metrics );
+    return af_cjk_hints_apply( glyph_index, hints, outline, metrics );
+  }
+
+
+  /* Extract standard_width from writing system/script specific */
+  /* metrics class.                                             */
+
+  static void
+  af_indic_get_standard_widths( AF_CJKMetrics  metrics,
+                                FT_Pos*        stdHW,
+                                FT_Pos*        stdVW )
+  {
+    if ( stdHW )
+      *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
+
+    if ( stdVW )
+      *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
   }
 
 
@@ -107,6 +124,7 @@
     (AF_WritingSystem_InitMetricsFunc) af_indic_metrics_init,
     (AF_WritingSystem_ScaleMetricsFunc)af_indic_metrics_scale,
     (AF_WritingSystem_DoneMetricsFunc) NULL,
+    (AF_WritingSystem_GetStdWidthsFunc)af_indic_get_standard_widths,
 
     (AF_WritingSystem_InitHintsFunc)   af_indic_hints_init,
     (AF_WritingSystem_ApplyHintsFunc)  af_indic_hints_apply
@@ -126,6 +144,7 @@
     (AF_WritingSystem_InitMetricsFunc) NULL,
     (AF_WritingSystem_ScaleMetricsFunc)NULL,
     (AF_WritingSystem_DoneMetricsFunc) NULL,
+    (AF_WritingSystem_GetStdWidthsFunc)NULL,
 
     (AF_WritingSystem_InitHintsFunc)   NULL,
     (AF_WritingSystem_ApplyHintsFunc)  NULL
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 893e986..9c9f370 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -41,6 +41,10 @@
 #define FT_COMPONENT  trace_aflatin
 
 
+  /* needed for computation of round vs. flat segments */
+#define FLAT_THRESHOLD( x )  ( x / 14 )
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -75,7 +79,6 @@
     {
       FT_Error            error;
       FT_ULong            glyph_index;
-      FT_Long             y_offset;
       int                 dim;
       AF_LatinMetricsRec  dummy[1];
       AF_Scaler           scaler = &dummy->root.scaler;
@@ -88,52 +91,63 @@
       AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
                                        [style_class->script];
 
-      FT_UInt32  standard_char;
+      void*        shaper_buf;
+      const char*  p;
 
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_ULong  ch;
+#endif
+
+      p          = script_class->standard_charstring;
+      shaper_buf = af_shaper_buf_create( face );
 
       /*
-       * We check more than a single standard character to catch features
-       * like `c2sc' (small caps from caps) that don't contain lowercase
-       * letters by definition, or other features that mainly operate on
-       * numerals.
+       * We check a list of standard characters to catch features like
+       * `c2sc' (small caps from caps) that don't contain lowercase letters
+       * by definition, or other features that mainly operate on numerals.
+       * The first match wins.
        */
 
-      standard_char = script_class->standard_char1;
-      af_get_char_index( &metrics->root,
-                         standard_char,
-                         &glyph_index,
-                         &y_offset );
-      if ( !glyph_index )
+      glyph_index = 0;
+      while ( *p )
       {
-        if ( script_class->standard_char2 )
-        {
-          standard_char = script_class->standard_char2;
-          af_get_char_index( &metrics->root,
-                             standard_char,
-                             &glyph_index,
-                             &y_offset );
-          if ( !glyph_index )
-          {
-            if ( script_class->standard_char3 )
-            {
-              standard_char = script_class->standard_char3;
-              af_get_char_index( &metrics->root,
-                                 standard_char,
-                                 &glyph_index,
-                                 &y_offset );
-              if ( !glyph_index )
-                goto Exit;
-            }
-            else
-              goto Exit;
-          }
-        }
-        else
-          goto Exit;
+        unsigned int  num_idx;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        const char*  p_old;
+#endif
+
+
+        while ( *p == ' ' )
+          p++;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        p_old = p;
+        GET_UTF8_CHAR( ch, p_old );
+#endif
+
+        /* reject input that maps to more than a single glyph */
+        p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
+        if ( num_idx > 1 )
+          continue;
+
+        /* otherwise exit loop if we have a result */
+        glyph_index = af_shaper_get_elem( &metrics->root,
+                                          shaper_buf,
+                                          0,
+                                          NULL,
+                                          NULL );
+        if ( glyph_index )
+          break;
       }
 
+      af_shaper_buf_destroy( face, shaper_buf );
+
+      if ( !glyph_index )
+        goto Exit;
+
       FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
-                  standard_char, glyph_index ));
+                  ch, glyph_index ));
 
       error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
       if ( error || face->glyph->outline.n_points <= 0 )
@@ -274,6 +288,10 @@
     AF_Blue_Stringset         bss = sc->blue_stringset;
     const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
 
+    FT_Pos  flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
+
+    void*  shaper_buf;
+
 
     /* we walk over the blue character strings as specified in the */
     /* style's entry in the `af_blue_stringset' array              */
@@ -282,11 +300,15 @@
                 "============================\n"
                 "\n" ));
 
+    shaper_buf = af_shaper_buf_create( face );
+
     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
     {
       const char*  p = &af_blue_strings[bs->string];
       FT_Pos*      blue_ref;
       FT_Pos*      blue_shoot;
+      FT_Pos       ascender;
+      FT_Pos       descender;
 
 
 #ifdef FT_DEBUG_LEVEL_TRACE
@@ -305,6 +327,11 @@
             FT_TRACE5(( "top" ));
             have_flag = 1;
           }
+          else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
+          {
+            FT_TRACE5(( "sub top" ));
+            have_flag = 1;
+          }
 
           if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
           {
@@ -338,394 +365,482 @@
 
       num_flats  = 0;
       num_rounds = 0;
+      ascender   = 0;
+      descender  = 0;
 
       while ( *p )
       {
-        FT_ULong    ch;
         FT_ULong    glyph_index;
         FT_Long     y_offset;
-        FT_Pos      best_y;                            /* same as points.y */
         FT_Int      best_point, best_contour_first, best_contour_last;
         FT_Vector*  points;
-        FT_Bool     round = 0;
+
+        FT_Pos   best_y_extremum;                      /* same as points.y */
+        FT_Bool  best_round = 0;
+
+        unsigned int  i, num_idx;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        const char*  p_old;
+        FT_ULong     ch;
+#endif
 
 
-        GET_UTF8_CHAR( ch, p );
+        while ( *p == ' ' )
+          p++;
 
-        /* load the character in the face -- skip unknown or empty ones */
-        af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset );
-        if ( glyph_index == 0 )
+#ifdef FT_DEBUG_LEVEL_TRACE
+        p_old = p;
+        GET_UTF8_CHAR( ch, p_old );
+#endif
+
+        p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
+
+        if ( !num_idx )
         {
           FT_TRACE5(( "  U+%04lX unavailable\n", ch ));
           continue;
         }
 
-        error   = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
-        outline = face->glyph->outline;
-        /* reject glyphs that don't produce any rendering */
-        if ( error || outline.n_points <= 2 )
+        if ( AF_LATIN_IS_TOP_BLUE( bs ) )
+          best_y_extremum = FT_INT_MIN;
+        else
+          best_y_extremum = FT_INT_MAX;
+
+        /* iterate over all glyph elements of the character cluster */
+        /* and get the data of the `biggest' one                    */
+        for ( i = 0; i < num_idx; i++ )
         {
-          FT_TRACE5(( "  U+%04lX contains no (usable) outlines\n", ch ));
-          continue;
-        }
-
-        /* now compute min or max point indices and coordinates */
-        points             = outline.points;
-        best_point         = -1;
-        best_y             = 0;  /* make compiler happy */
-        best_contour_first = 0;  /* ditto */
-        best_contour_last  = 0;  /* ditto */
-
-        {
-          FT_Int  nn;
-          FT_Int  first = 0;
-          FT_Int  last  = -1;
+          FT_Pos   best_y;
+          FT_Bool  round = 0;
 
 
-          for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
+          /* load the character in the face -- skip unknown or empty ones */
+          glyph_index = af_shaper_get_elem( &metrics->root,
+                                            shaper_buf,
+                                            i,
+                                            NULL,
+                                            &y_offset );
+          if ( glyph_index == 0 )
           {
-            FT_Int  old_best_point = best_point;
-            FT_Int  pp;
-
-
-            last = outline.contours[nn];
-
-            /* Avoid single-point contours since they are never rasterized. */
-            /* In some fonts, they correspond to mark attachment points     */
-            /* that are way outside of the glyph's real outline.            */
-            if ( last <= first )
-              continue;
-
-            if ( AF_LATIN_IS_TOP_BLUE( bs ) )
-            {
-              for ( pp = first; pp <= last; pp++ )
-                if ( best_point < 0 || points[pp].y > best_y )
-                {
-                  best_point = pp;
-                  best_y     = points[pp].y;
-                }
-            }
-            else
-            {
-              for ( pp = first; pp <= last; pp++ )
-                if ( best_point < 0 || points[pp].y < best_y )
-                {
-                  best_point = pp;
-                  best_y     = points[pp].y;
-                }
-            }
-
-            if ( best_point != old_best_point )
-            {
-              best_contour_first = first;
-              best_contour_last  = last;
-            }
-          }
-        }
-
-        /* now check whether the point belongs to a straight or round   */
-        /* segment; we first need to find in which contour the extremum */
-        /* lies, then inspect its previous and next points              */
-        if ( best_point >= 0 )
-        {
-          FT_Pos  best_x = points[best_point].x;
-          FT_Int  prev, next;
-          FT_Int  best_segment_first, best_segment_last;
-          FT_Int  best_on_point_first, best_on_point_last;
-          FT_Pos  dist;
-
-
-          best_segment_first = best_point;
-          best_segment_last  = best_point;
-
-          if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
-          {
-            best_on_point_first = best_point;
-            best_on_point_last  = best_point;
-          }
-          else
-          {
-            best_on_point_first = -1;
-            best_on_point_last  = -1;
+            FT_TRACE5(( "  U+%04lX unavailable\n", ch ));
+            continue;
           }
 
-          /* look for the previous and next points on the contour  */
-          /* that are not on the same Y coordinate, then threshold */
-          /* the `closeness'...                                    */
-          prev = best_point;
-          next = prev;
-
-          do
+          error   = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+          outline = face->glyph->outline;
+          /* reject glyphs that don't produce any rendering */
+          if ( error || outline.n_points <= 2 )
           {
-            if ( prev > best_contour_first )
-              prev--;
+#ifdef FT_DEBUG_LEVEL_TRACE
+            if ( num_idx == 1 )
+              FT_TRACE5(( "  U+%04lX contains no (usable) outlines\n", ch ));
             else
-              prev = best_contour_last;
+              FT_TRACE5(( "  component %d of cluster starting with U+%04lX"
+                          " contains no (usable) outlines\n", i, ch ));
+#endif
+            continue;
+          }
 
-            dist = FT_ABS( points[prev].y - best_y );
-            /* accept a small distance or a small angle (both values are */
-            /* heuristic; value 20 corresponds to approx. 2.9 degrees)   */
-            if ( dist > 5 )
-              if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
-                break;
+          /* now compute min or max point indices and coordinates */
+          points             = outline.points;
+          best_point         = -1;
+          best_y             = 0;  /* make compiler happy */
+          best_contour_first = 0;  /* ditto */
+          best_contour_last  = 0;  /* ditto */
 
-            best_segment_first = prev;
-
-            if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
-            {
-              best_on_point_first = prev;
-              if ( best_on_point_last < 0 )
-                best_on_point_last = prev;
-            }
-
-          } while ( prev != best_point );
-
-          do
           {
-            if ( next < best_contour_last )
-              next++;
-            else
-              next = best_contour_first;
+            FT_Int  nn;
+            FT_Int  first = 0;
+            FT_Int  last  = -1;
 
-            dist = FT_ABS( points[next].y - best_y );
-            if ( dist > 5 )
-              if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
-                break;
 
-            best_segment_last = next;
-
-            if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
+            for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
             {
-              best_on_point_last = next;
-              if ( best_on_point_first < 0 )
-                best_on_point_first = next;
-            }
-
-          } while ( next != best_point );
-
-          if ( AF_LATIN_IS_LONG_BLUE( bs ) )
-          {
-            /* If this flag is set, we have an additional constraint to  */
-            /* get the blue zone distance: Find a segment of the topmost */
-            /* (or bottommost) contour that is longer than a heuristic   */
-            /* threshold.  This ensures that small bumps in the outline  */
-            /* are ignored (for example, the `vertical serifs' found in  */
-            /* many Hebrew glyph designs).                               */
-
-            /* If this segment is long enough, we are done.  Otherwise,  */
-            /* search the segment next to the extremum that is long      */
-            /* enough, has the same direction, and a not too large       */
-            /* vertical distance from the extremum.  Note that the       */
-            /* algorithm doesn't check whether the found segment is      */
-            /* actually the one (vertically) nearest to the extremum.    */
-
-            /* heuristic threshold value */
-            FT_Pos  length_threshold = metrics->units_per_em / 25;
+              FT_Int  old_best_point = best_point;
+              FT_Int  pp;
 
 
-            dist = FT_ABS( points[best_segment_last].x -
-                             points[best_segment_first].x );
+              last = outline.contours[nn];
 
-            if ( dist < length_threshold                       &&
-                 best_segment_last - best_segment_first + 2 <=
-                   best_contour_last - best_contour_first      )
-            {
-              /* heuristic threshold value */
-              FT_Pos  height_threshold = metrics->units_per_em / 4;
-
-              FT_Int   first;
-              FT_Int   last;
-              FT_Bool  hit;
-
-              /* we intentionally declare these two variables        */
-              /* outside of the loop since various compilers emit    */
-              /* incorrect warning messages otherwise, talking about */
-              /* `possibly uninitialized variables'                  */
-              FT_Int  p_first = 0;            /* make compiler happy */
-              FT_Int  p_last  = 0;
-
-              FT_Bool  left2right;
-
-
-              /* compute direction */
-              prev = best_point;
-
-              do
-              {
-                if ( prev > best_contour_first )
-                  prev--;
-                else
-                  prev = best_contour_last;
-
-                if ( points[prev].x != best_x )
-                  break;
-
-              } while ( prev != best_point );
-
-              /* skip glyph for the degenerate case */
-              if ( prev == best_point )
+              /* Avoid single-point contours since they are never      */
+              /* rasterized.  In some fonts, they correspond to mark   */
+              /* attachment points that are way outside of the glyph's */
+              /* real outline.                                         */
+              if ( last <= first )
                 continue;
 
-              left2right = FT_BOOL( points[prev].x < points[best_point].x );
-
-              first = best_segment_last;
-              last  = first;
-              hit   = 0;
-
-              do
+              if ( AF_LATIN_IS_TOP_BLUE( bs )     ||
+                   AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
               {
-                FT_Bool  l2r;
-                FT_Pos   d;
-
-
-                if ( !hit )
+                for ( pp = first; pp <= last; pp++ )
                 {
-                  /* no hit; adjust first point */
-                  first = last;
-
-                  /* also adjust first and last on point */
-                  if ( FT_CURVE_TAG( outline.tags[first] ) ==
-                         FT_CURVE_TAG_ON )
+                  if ( best_point < 0 || points[pp].y > best_y )
                   {
-                    p_first = first;
-                    p_last  = first;
+                    best_point = pp;
+                    best_y     = points[pp].y;
+                    ascender   = FT_MAX( ascender, best_y + y_offset );
                   }
                   else
+                    descender = FT_MIN( descender, points[pp].y + y_offset );
+                }
+              }
+              else
+              {
+                for ( pp = first; pp <= last; pp++ )
+                {
+                  if ( best_point < 0 || points[pp].y < best_y )
                   {
-                    p_first = -1;
-                    p_last  = -1;
+                    best_point = pp;
+                    best_y     = points[pp].y;
+                    descender  = FT_MIN( descender, best_y + y_offset );
+                  }
+                  else
+                    ascender = FT_MAX( ascender, points[pp].y + y_offset );
+                }
+              }
+
+              if ( best_point != old_best_point )
+              {
+                best_contour_first = first;
+                best_contour_last  = last;
+              }
+            }
+          }
+
+          /* now check whether the point belongs to a straight or round   */
+          /* segment; we first need to find in which contour the extremum */
+          /* lies, then inspect its previous and next points              */
+          if ( best_point >= 0 )
+          {
+            FT_Pos  best_x = points[best_point].x;
+            FT_Int  prev, next;
+            FT_Int  best_segment_first, best_segment_last;
+            FT_Int  best_on_point_first, best_on_point_last;
+            FT_Pos  dist;
+
+
+            best_segment_first = best_point;
+            best_segment_last  = best_point;
+
+            if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
+            {
+              best_on_point_first = best_point;
+              best_on_point_last  = best_point;
+            }
+            else
+            {
+              best_on_point_first = -1;
+              best_on_point_last  = -1;
+            }
+
+            /* look for the previous and next points on the contour  */
+            /* that are not on the same Y coordinate, then threshold */
+            /* the `closeness'...                                    */
+            prev = best_point;
+            next = prev;
+
+            do
+            {
+              if ( prev > best_contour_first )
+                prev--;
+              else
+                prev = best_contour_last;
+
+              dist = FT_ABS( points[prev].y - best_y );
+              /* accept a small distance or a small angle (both values are */
+              /* heuristic; value 20 corresponds to approx. 2.9 degrees)   */
+              if ( dist > 5 )
+                if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
+                  break;
+
+              best_segment_first = prev;
+
+              if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
+              {
+                best_on_point_first = prev;
+                if ( best_on_point_last < 0 )
+                  best_on_point_last = prev;
+              }
+
+            } while ( prev != best_point );
+
+            do
+            {
+              if ( next < best_contour_last )
+                next++;
+              else
+                next = best_contour_first;
+
+              dist = FT_ABS( points[next].y - best_y );
+              if ( dist > 5 )
+                if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
+                  break;
+
+              best_segment_last = next;
+
+              if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
+              {
+                best_on_point_last = next;
+                if ( best_on_point_first < 0 )
+                  best_on_point_first = next;
+              }
+
+            } while ( next != best_point );
+
+            if ( AF_LATIN_IS_LONG_BLUE( bs ) )
+            {
+              /* If this flag is set, we have an additional constraint to  */
+              /* get the blue zone distance: Find a segment of the topmost */
+              /* (or bottommost) contour that is longer than a heuristic   */
+              /* threshold.  This ensures that small bumps in the outline  */
+              /* are ignored (for example, the `vertical serifs' found in  */
+              /* many Hebrew glyph designs).                               */
+
+              /* If this segment is long enough, we are done.  Otherwise,  */
+              /* search the segment next to the extremum that is long      */
+              /* enough, has the same direction, and a not too large       */
+              /* vertical distance from the extremum.  Note that the       */
+              /* algorithm doesn't check whether the found segment is      */
+              /* actually the one (vertically) nearest to the extremum.    */
+
+              /* heuristic threshold value */
+              FT_Pos  length_threshold = metrics->units_per_em / 25;
+
+
+              dist = FT_ABS( points[best_segment_last].x -
+                               points[best_segment_first].x );
+
+              if ( dist < length_threshold                       &&
+                   best_segment_last - best_segment_first + 2 <=
+                     best_contour_last - best_contour_first      )
+              {
+                /* heuristic threshold value */
+                FT_Pos  height_threshold = metrics->units_per_em / 4;
+
+                FT_Int   first;
+                FT_Int   last;
+                FT_Bool  hit;
+
+                /* we intentionally declare these two variables        */
+                /* outside of the loop since various compilers emit    */
+                /* incorrect warning messages otherwise, talking about */
+                /* `possibly uninitialized variables'                  */
+                FT_Int  p_first = 0;            /* make compiler happy */
+                FT_Int  p_last  = 0;
+
+                FT_Bool  left2right;
+
+
+                /* compute direction */
+                prev = best_point;
+
+                do
+                {
+                  if ( prev > best_contour_first )
+                    prev--;
+                  else
+                    prev = best_contour_last;
+
+                  if ( points[prev].x != best_x )
+                    break;
+
+                } while ( prev != best_point );
+
+                /* skip glyph for the degenerate case */
+                if ( prev == best_point )
+                  continue;
+
+                left2right = FT_BOOL( points[prev].x < points[best_point].x );
+
+                first = best_segment_last;
+                last  = first;
+                hit   = 0;
+
+                do
+                {
+                  FT_Bool  l2r;
+                  FT_Pos   d;
+
+
+                  if ( !hit )
+                  {
+                    /* no hit; adjust first point */
+                    first = last;
+
+                    /* also adjust first and last on point */
+                    if ( FT_CURVE_TAG( outline.tags[first] ) ==
+                           FT_CURVE_TAG_ON )
+                    {
+                      p_first = first;
+                      p_last  = first;
+                    }
+                    else
+                    {
+                      p_first = -1;
+                      p_last  = -1;
+                    }
+
+                    hit = 1;
                   }
 
-                  hit = 1;
-                }
+                  if ( last < best_contour_last )
+                    last++;
+                  else
+                    last = best_contour_first;
 
-                if ( last < best_contour_last )
-                  last++;
-                else
-                  last = best_contour_first;
-
-                if ( FT_ABS( best_y - points[first].y ) > height_threshold )
-                {
-                  /* vertical distance too large */
-                  hit = 0;
-                  continue;
-                }
-
-                /* same test as above */
-                dist = FT_ABS( points[last].y - points[first].y );
-                if ( dist > 5 )
-                  if ( FT_ABS( points[last].x - points[first].x ) <=
-                         20 * dist )
+                  if ( FT_ABS( best_y - points[first].y ) > height_threshold )
                   {
+                    /* vertical distance too large */
                     hit = 0;
                     continue;
                   }
 
-                if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
-                {
-                  p_last = last;
-                  if ( p_first < 0 )
-                    p_first = last;
-                }
-
-                l2r = FT_BOOL( points[first].x < points[last].x );
-                d   = FT_ABS( points[last].x - points[first].x );
-
-                if ( l2r == left2right     &&
-                     d >= length_threshold )
-                {
-                  /* all constraints are met; update segment after finding */
-                  /* its end                                               */
-                  do
-                  {
-                    if ( last < best_contour_last )
-                      last++;
-                    else
-                      last = best_contour_first;
-
-                    d = FT_ABS( points[last].y - points[first].y );
-                    if ( d > 5 )
-                      if ( FT_ABS( points[next].x - points[first].x ) <=
-                             20 * dist )
-                      {
-                        if ( last > best_contour_first )
-                          last--;
-                        else
-                          last = best_contour_last;
-                        break;
-                      }
-
-                    p_last = last;
-
-                    if ( FT_CURVE_TAG( outline.tags[last] ) ==
-                           FT_CURVE_TAG_ON )
+                  /* same test as above */
+                  dist = FT_ABS( points[last].y - points[first].y );
+                  if ( dist > 5 )
+                    if ( FT_ABS( points[last].x - points[first].x ) <=
+                           20 * dist )
                     {
-                      p_last = last;
-                      if ( p_first < 0 )
-                        p_first = last;
+                      hit = 0;
+                      continue;
                     }
 
-                  } while ( last != best_segment_first );
+                  if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
+                  {
+                    p_last = last;
+                    if ( p_first < 0 )
+                      p_first = last;
+                  }
 
-                  best_y = points[first].y;
+                  l2r = FT_BOOL( points[first].x < points[last].x );
+                  d   = FT_ABS( points[last].x - points[first].x );
 
-                  best_segment_first = first;
-                  best_segment_last  = last;
+                  if ( l2r == left2right     &&
+                       d >= length_threshold )
+                  {
+                    /* all constraints are met; update segment after */
+                    /* finding its end                               */
+                    do
+                    {
+                      if ( last < best_contour_last )
+                        last++;
+                      else
+                        last = best_contour_first;
 
-                  best_on_point_first = p_first;
-                  best_on_point_last  = p_last;
+                      d = FT_ABS( points[last].y - points[first].y );
+                      if ( d > 5 )
+                        if ( FT_ABS( points[next].x - points[first].x ) <=
+                               20 * dist )
+                        {
+                          if ( last > best_contour_first )
+                            last--;
+                          else
+                            last = best_contour_last;
+                          break;
+                        }
 
-                  break;
-                }
+                      p_last = last;
 
-              } while ( last != best_segment_first );
+                      if ( FT_CURVE_TAG( outline.tags[last] ) ==
+                             FT_CURVE_TAG_ON )
+                      {
+                        p_last = last;
+                        if ( p_first < 0 )
+                          p_first = last;
+                      }
+
+                    } while ( last != best_segment_first );
+
+                    best_y = points[first].y;
+
+                    best_segment_first = first;
+                    best_segment_last  = last;
+
+                    best_on_point_first = p_first;
+                    best_on_point_last  = p_last;
+
+                    break;
+                  }
+
+                } while ( last != best_segment_first );
+              }
+            }
+
+            /* for computing blue zones, we add the y offset as returned */
+            /* by the currently used OpenType feature -- for example,    */
+            /* superscript glyphs might be identical to subscript glyphs */
+            /* with a vertical shift                                     */
+            best_y += y_offset;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+            if ( num_idx == 1 )
+              FT_TRACE5(( "  U+%04lX: best_y = %5ld", ch, best_y ));
+            else
+              FT_TRACE5(( "  component %d of cluster starting with U+%04lX:"
+                          " best_y = %5ld", i, ch, best_y ));
+#endif
+
+            /* now set the `round' flag depending on the segment's kind: */
+            /*                                                           */
+            /* - if the horizontal distance between the first and last   */
+            /*   `on' point is larger than a heuristic threshold         */
+            /*   we have a flat segment                                  */
+            /* - if either the first or the last point of the segment is */
+            /*   an `off' point, the segment is round, otherwise it is   */
+            /*   flat                                                    */
+            if ( best_on_point_first >= 0                               &&
+                 best_on_point_last >= 0                                &&
+                 ( FT_ABS( points[best_on_point_last].x -
+                           points[best_on_point_first].x ) ) >
+                   flat_threshold                                       )
+              round = 0;
+            else
+              round = FT_BOOL(
+                        FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
+                          FT_CURVE_TAG_ON                                   ||
+                        FT_CURVE_TAG( outline.tags[best_segment_last]  ) !=
+                          FT_CURVE_TAG_ON                                   );
+
+            if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
+            {
+              /* only use flat segments for a neutral blue zone */
+              FT_TRACE5(( " (round, skipped)\n" ));
+              continue;
+            }
+
+            FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
+          }
+
+          if ( AF_LATIN_IS_TOP_BLUE( bs ) )
+          {
+            if ( best_y > best_y_extremum )
+            {
+              best_y_extremum = best_y;
+              best_round      = round;
+            }
+          }
+          else
+          {
+            if ( best_y < best_y_extremum )
+            {
+              best_y_extremum = best_y;
+              best_round      = round;
             }
           }
 
-          /* for computing blue zones, we add the y offset as returned */
-          /* by the currently used OpenType feature -- for example,    */
-          /* superscript glyphs might be identical to subscript glyphs */
-          /* with a vertical shift                                     */
-          best_y += y_offset;
+        } /* end for loop */
 
-          FT_TRACE5(( "  U+%04lX: best_y = %5ld", ch, best_y ));
-
-          /* now set the `round' flag depending on the segment's kind: */
-          /*                                                           */
-          /* - if the horizontal distance between the first and last   */
-          /*   `on' point is larger than upem/8 (value 8 is heuristic) */
-          /*   we have a flat segment                                  */
-          /* - if either the first or the last point of the segment is */
-          /*   an `off' point, the segment is round, otherwise it is   */
-          /*   flat                                                    */
-          if ( best_on_point_first >= 0                               &&
-               best_on_point_last >= 0                                &&
-               (FT_UInt)( FT_ABS( points[best_on_point_last].x -
-                                  points[best_on_point_first].x ) ) >
-                 metrics->units_per_em / 8                            )
-            round = 0;
+        if ( !( best_y_extremum == FT_INT_MIN ||
+                best_y_extremum == FT_INT_MAX ) )
+        {
+          if ( best_round )
+            rounds[num_rounds++] = best_y_extremum;
           else
-            round = FT_BOOL(
-                      FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
-                        FT_CURVE_TAG_ON                                   ||
-                      FT_CURVE_TAG( outline.tags[best_segment_last]  ) !=
-                        FT_CURVE_TAG_ON                                   );
-
-          if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
-          {
-            /* only use flat segments for a neutral blue zone */
-            FT_TRACE5(( " (round, skipped)\n" ));
-            continue;
-          }
-
-          FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
+            flats[num_flats++]   = best_y_extremum;
         }
 
-        if ( round )
-          rounds[num_rounds++] = best_y;
-        else
-          flats[num_flats++]   = best_y;
-      }
+      } /* end while loop */
 
       if ( num_flats == 0 && num_rounds == 0 )
       {
@@ -775,7 +890,8 @@
         FT_Bool  over_ref = FT_BOOL( shoot > ref );
 
 
-        if ( AF_LATIN_IS_TOP_BLUE( bs ) ^ over_ref )
+        if ( ( AF_LATIN_IS_TOP_BLUE( bs )    ||
+               AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref )
         {
           *blue_ref   =
           *blue_shoot = ( shoot + ref ) / 2;
@@ -785,9 +901,14 @@
         }
       }
 
+      blue->ascender  = ascender;
+      blue->descender = descender;
+
       blue->flags = 0;
       if ( AF_LATIN_IS_TOP_BLUE( bs ) )
         blue->flags |= AF_LATIN_BLUE_TOP;
+      if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
+        blue->flags |= AF_LATIN_BLUE_SUB_TOP;
       if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
         blue->flags |= AF_LATIN_BLUE_NEUTRAL;
 
@@ -802,7 +923,10 @@
       FT_TRACE5(( "    -> reference = %ld\n"
                   "       overshoot = %ld\n",
                   *blue_ref, *blue_shoot ));
-    }
+
+    } /* end for loop */
+
+    af_shaper_buf_destroy( face, shaper_buf );
 
     FT_TRACE5(( "\n" ));
 
@@ -816,27 +940,36 @@
   af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
                                  FT_Face          face )
   {
-    FT_UInt   i;
     FT_Bool   started = 0, same_width = 1;
     FT_Fixed  advance, old_advance = 0;
 
+    void*  shaper_buf;
 
-    /* digit `0' is 0x30 in all supported charmaps */
-    for ( i = 0x30; i <= 0x39; i++ )
+    /* in all supported charmaps, digits have character codes 0x30-0x39 */
+    const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
+    const char*  p;
+
+
+    p          = digits;
+    shaper_buf = af_shaper_buf_create( face );
+
+    while ( *p )
     {
-      FT_ULong  glyph_index;
-      FT_Long   y_offset;
+      FT_ULong      glyph_index;
+      unsigned int  num_idx;
 
 
-      af_get_char_index( &metrics->root, i, &glyph_index, &y_offset );
-      if ( glyph_index == 0 )
+      /* reject input that maps to more than a single glyph */
+      p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
+      if ( num_idx > 1 )
         continue;
 
-      if ( FT_Get_Advance( face, glyph_index,
-                           FT_LOAD_NO_SCALE         |
-                           FT_LOAD_NO_HINTING       |
-                           FT_LOAD_IGNORE_TRANSFORM,
-                           &advance ) )
+      glyph_index = af_shaper_get_elem( &metrics->root,
+                                        shaper_buf,
+                                        0,
+                                        &advance,
+                                        NULL );
+      if ( !glyph_index )
         continue;
 
       if ( started )
@@ -854,6 +987,8 @@
       }
     }
 
+    af_shaper_buf_destroy( face, shaper_buf );
+
     metrics->root.digits_have_same_width = same_width;
   }
 
@@ -967,18 +1102,52 @@
 #endif
           if ( dim == AF_DIMENSION_VERT )
           {
-            scale = FT_MulDiv( scale, fitted, scaled );
+            FT_Pos    max_height;
+            FT_Pos    dist;
+            FT_Fixed  new_scale;
 
-            FT_TRACE5((
-              "af_latin_metrics_scale_dim:"
-              " x height alignment (style `%s'):\n"
-              "                           "
-              " vertical scaling changed from %.4f to %.4f (by %d%%)\n"
-              "\n",
-              af_style_names[metrics->root.style_class->style],
-              axis->org_scale / 65536.0,
-              scale / 65536.0,
-              ( fitted - scaled ) * 100 / scaled ));
+
+            new_scale = FT_MulDiv( scale, fitted, scaled );
+
+            /* the scaling should not change the result by more than two pixels */
+            max_height = metrics->units_per_em;
+
+            for ( nn = 0; nn < Axis->blue_count; nn++ )
+            {
+              max_height = FT_MAX( max_height, Axis->blues[nn].ascender );
+              max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
+            }
+
+            dist  = FT_ABS( FT_MulFix( max_height, new_scale - scale ) );
+            dist &= ~127;
+
+            if ( dist == 0 )
+            {
+              scale = new_scale;
+
+              FT_TRACE5((
+                "af_latin_metrics_scale_dim:"
+                " x height alignment (style `%s'):\n"
+                "                           "
+                " vertical scaling changed from %.4f to %.4f (by %d%%)\n"
+                "\n",
+                af_style_names[metrics->root.style_class->style],
+                axis->org_scale / 65536.0,
+                scale / 65536.0,
+                ( fitted - scaled ) * 100 / scaled ));
+            }
+#ifdef FT_DEBUG_LEVEL_TRACE
+            else
+            {
+              FT_TRACE5((
+                "af_latin_metrics_scale_dim:"
+                " x height alignment (style `%s'):\n"
+                "                           "
+                " excessive vertical scaling abandoned\n"
+                "\n",
+                af_style_names[metrics->root.style_class->style] ));
+            }
+#endif
           }
         }
       }
@@ -1032,8 +1201,11 @@
 
     if ( dim == AF_DIMENSION_VERT )
     {
-      FT_TRACE5(( "blue zones (style `%s')\n",
-                  af_style_names[metrics->root.style_class->style] ));
+#ifdef FT_DEBUG_LEVEL_TRACE
+      if ( axis->blue_count )
+        FT_TRACE5(( "blue zones (style `%s')\n",
+                    af_style_names[metrics->root.style_class->style] ));
+#endif
 
       /* scale the blue zones */
       for ( nn = 0; nn < axis->blue_count; nn++ )
@@ -1106,21 +1278,63 @@
 #endif
 
           blue->flags |= AF_LATIN_BLUE_ACTIVE;
-
-          FT_TRACE5(( "  reference %d: %d scaled to %.2f%s\n"
-                      "  overshoot %d: %d scaled to %.2f%s\n",
-                      nn,
-                      blue->ref.org,
-                      blue->ref.fit / 64.0,
-                      blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
-                                                         : " (inactive)",
-                      nn,
-                      blue->shoot.org,
-                      blue->shoot.fit / 64.0,
-                      blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
-                                                         : " (inactive)" ));
         }
       }
+
+      /* use sub-top blue zone only if it doesn't overlap with */
+      /* another (non-sup-top) blue zone; otherwise, the       */
+      /* effect would be similar to a neutral blue zone, which */
+      /* is not desired here                                   */
+      for ( nn = 0; nn < axis->blue_count; nn++ )
+      {
+        AF_LatinBlue  blue = &axis->blues[nn];
+        FT_UInt       i;
+
+
+        if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) )
+          continue;
+        if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
+          continue;
+
+        for ( i = 0; i < axis->blue_count; i++ )
+        {
+          AF_LatinBlue  b = &axis->blues[i];
+
+
+          if ( b->flags & AF_LATIN_BLUE_SUB_TOP )
+            continue;
+          if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) )
+            continue;
+
+          if ( b->ref.fit <= blue->shoot.fit &&
+               b->shoot.fit >= blue->ref.fit )
+          {
+            blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
+            break;
+          }
+        }
+      }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+      for ( nn = 0; nn < axis->blue_count; nn++ )
+      {
+        AF_LatinBlue  blue = &axis->blues[nn];
+
+
+        FT_TRACE5(( "  reference %d: %d scaled to %.2f%s\n"
+                    "  overshoot %d: %d scaled to %.2f%s\n",
+                    nn,
+                    blue->ref.org,
+                    blue->ref.fit / 64.0,
+                    blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
+                                                       : " (inactive)",
+                    nn,
+                    blue->shoot.org,
+                    blue->shoot.fit / 64.0,
+                    blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
+                                                       : " (inactive)" ));
+      }
+#endif
     }
   }
 
@@ -1140,6 +1354,22 @@
   }
 
 
+  /* Extract standard_width from writing system/script specific */
+  /* metrics class.                                             */
+
+  FT_LOCAL_DEF( void )
+  af_latin_get_standard_widths( AF_LatinMetrics  metrics,
+                                FT_Pos*          stdHW,
+                                FT_Pos*          stdVW )
+  {
+    if ( stdHW )
+      *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
+
+    if ( stdVW )
+      *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
+  }
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -1155,14 +1385,17 @@
   af_latin_hints_compute_segments( AF_GlyphHints  hints,
                                    AF_Dimension   dim )
   {
-    AF_AxisHints   axis          = &hints->axis[dim];
-    FT_Memory      memory        = hints->memory;
-    FT_Error       error         = FT_Err_Ok;
-    AF_Segment     segment       = NULL;
-    AF_SegmentRec  seg0;
-    AF_Point*      contour       = hints->contours;
-    AF_Point*      contour_limit = contour + hints->num_contours;
-    AF_Direction   major_dir, segment_dir;
+    AF_LatinMetrics  metrics       = (AF_LatinMetrics)hints->metrics;
+    AF_AxisHints     axis          = &hints->axis[dim];
+    FT_Memory        memory        = hints->memory;
+    FT_Error         error         = FT_Err_Ok;
+    AF_Segment       segment       = NULL;
+    AF_SegmentRec    seg0;
+    AF_Point*        contour       = hints->contours;
+    AF_Point*        contour_limit = contour + hints->num_contours;
+    AF_Direction     major_dir, segment_dir;
+
+    FT_Pos  flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
 
 
     FT_ZERO( &seg0 );
@@ -1203,11 +1436,13 @@
     /* do each contour separately */
     for ( ; contour < contour_limit; contour++ )
     {
-      AF_Point  point   =  contour[0];
-      AF_Point  last    =  point->prev;
-      int       on_edge =  0;
-      FT_Pos    min_pos =  32000;  /* minimum segment pos != min_coord */
-      FT_Pos    max_pos = -32000;  /* maximum segment pos != max_coord */
+      AF_Point  point      =  contour[0];
+      AF_Point  last       =  point->prev;
+      int       on_edge    =  0;
+      FT_Pos    min_pos    =  32000;  /* minimum segment pos != min_coord */
+      FT_Pos    max_pos    = -32000;  /* maximum segment pos != max_coord */
+      FT_Pos    min_on_pos =  32000;
+      FT_Pos    max_on_pos = -32000;
       FT_Bool   passed;
 
 
@@ -1249,6 +1484,16 @@
           if ( u > max_pos )
             max_pos = u;
 
+          /* get minimum and maximum coordinate of on points */
+          if ( !( point->flags & AF_FLAG_CONTROL ) )
+          {
+            v = point->v;
+            if ( v < min_on_pos )
+              min_on_pos = v;
+            if ( v > max_on_pos )
+              max_on_pos = v;
+          }
+
           if ( point->out_dir != segment_dir || point == last )
           {
             /* we are just leaving an edge; record a new segment! */
@@ -1256,9 +1501,10 @@
             segment->pos  = (FT_Short)( ( min_pos + max_pos ) >> 1 );
 
             /* a segment is round if either its first or last point */
-            /* is a control point                                   */
-            if ( ( segment->first->flags | point->flags ) &
-                 AF_FLAG_CONTROL                          )
+            /* is a control point, and the length of the on points  */
+            /* inbetween doesn't exceed a heuristic limit           */
+            if ( ( segment->first->flags | point->flags ) & AF_FLAG_CONTROL &&
+                 ( max_on_pos - min_on_pos ) < flat_threshold               )
               segment->flags |= AF_EDGE_ROUND;
 
             /* compute segment size */
@@ -1301,10 +1547,19 @@
           /* clear all segment fields */
           segment[0] = seg0;
 
-          segment->dir      = (FT_Char)segment_dir;
+          segment->dir   = (FT_Char)segment_dir;
+          segment->first = point;
+          segment->last  = point;
+
           min_pos = max_pos = point->u;
-          segment->first    = point;
-          segment->last     = point;
+
+          if ( point->flags & AF_FLAG_CONTROL )
+          {
+            min_on_pos =  32000;
+            max_on_pos = -32000;
+          }
+          else
+            min_on_pos = max_on_pos = point->v;
 
           on_edge = 1;
         }
@@ -1872,7 +2127,8 @@
         /* the major direction) -- this assumes the TrueType convention  */
         /* for the orientation of contours                               */
         is_top_blue =
-          (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
+          (FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP     |
+                                       AF_LATIN_BLUE_SUB_TOP ) ) != 0 );
         is_neutral_blue =
           (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
         is_major_dir =
@@ -2805,7 +3061,8 @@
   /* Apply the complete hinting algorithm to a latin glyph. */
 
   static FT_Error
-  af_latin_hints_apply( AF_GlyphHints    hints,
+  af_latin_hints_apply( FT_UInt          glyph_index,
+                        AF_GlyphHints    hints,
                         FT_Outline*      outline,
                         AF_LatinMetrics  metrics )
   {
@@ -2847,7 +3104,9 @@
       if ( error )
         goto Exit;
 
-      af_latin_hints_compute_blue_edges( hints, metrics );
+      /* apply blue zones to base characters only */
+      if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) )
+        af_latin_hints_compute_blue_edges( hints, metrics );
     }
 
     /* grid-fit the outline */
@@ -2907,6 +3166,7 @@
     (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,
     (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,
     (AF_WritingSystem_DoneMetricsFunc) NULL,
+    (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths,
 
     (AF_WritingSystem_InitHintsFunc)   af_latin_hints_init,
     (AF_WritingSystem_ApplyHintsFunc)  af_latin_hints_apply
diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h
index 6855492..414060f 100644
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -53,6 +53,8 @@
 
 #define AF_LATIN_IS_TOP_BLUE( b ) \
           ( (b)->properties & AF_BLUE_PROPERTY_LATIN_TOP )
+#define AF_LATIN_IS_SUB_TOP_BLUE( b ) \
+          ( (b)->properties & AF_BLUE_PROPERTY_LATIN_SUB_TOP )
 #define AF_LATIN_IS_NEUTRAL_BLUE( b ) \
           ( (b)->properties & AF_BLUE_PROPERTY_LATIN_NEUTRAL )
 #define AF_LATIN_IS_X_HEIGHT_BLUE( b ) \
@@ -65,8 +67,10 @@
 
 #define AF_LATIN_BLUE_ACTIVE      ( 1U << 0 ) /* zone height is <= 3/4px   */
 #define AF_LATIN_BLUE_TOP         ( 1U << 1 ) /* we have a top blue zone   */
-#define AF_LATIN_BLUE_NEUTRAL     ( 1U << 2 ) /* we have neutral blue zone */
-#define AF_LATIN_BLUE_ADJUSTMENT  ( 1U << 3 ) /* used for scale adjustment */
+#define AF_LATIN_BLUE_SUB_TOP     ( 1U << 2 ) /* we have a subscript top   */
+                                              /* blue zone                 */
+#define AF_LATIN_BLUE_NEUTRAL     ( 1U << 3 ) /* we have neutral blue zone */
+#define AF_LATIN_BLUE_ADJUSTMENT  ( 1U << 4 ) /* used for scale adjustment */
                                               /* optimization              */
 
 
@@ -74,6 +78,8 @@
   {
     AF_WidthRec  ref;
     AF_WidthRec  shoot;
+    FT_Pos       ascender;
+    FT_Pos       descender;
     FT_UInt      flags;
 
   } AF_LatinBlueRec, *AF_LatinBlue;
diff --git a/src/autofit/aflatin2.c b/src/autofit/aflatin2.c
index ac9f933..2fb7d1d 100644
--- a/src/autofit/aflatin2.c
+++ b/src/autofit/aflatin2.c
@@ -693,6 +693,22 @@
   }
 
 
+  /* Extract standard_width from writing system/script specific */
+  /* metrics class.                                             */
+
+  FT_LOCAL_DEF( void )
+  af_latin2_get_standard_widths( AF_LatinMetrics  metrics,
+                                 FT_Pos*          stdHW,
+                                 FT_Pos*          stdVW )
+  {
+    if ( stdHW )
+      *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
+
+    if ( stdVW )
+      *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
+  }
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -2300,13 +2316,16 @@
 
 
   static FT_Error
-  af_latin2_hints_apply( AF_GlyphHints    hints,
+  af_latin2_hints_apply( FT_UInt          glyph_index,
+                         AF_GlyphHints    hints,
                          FT_Outline*      outline,
                          AF_LatinMetrics  metrics )
   {
     FT_Error  error;
     int       dim;
 
+    FT_UNUSED( glyph_index );
+
 
     error = af_glyph_hints_reload( hints, outline );
     if ( error )
@@ -2389,6 +2408,7 @@
     (AF_WritingSystem_InitMetricsFunc) af_latin2_metrics_init,
     (AF_WritingSystem_ScaleMetricsFunc)af_latin2_metrics_scale,
     (AF_WritingSystem_DoneMetricsFunc) NULL,
+    (AF_WritingSystem_GetStdWidthsFunc)af_latin2_get_standard_widths,
 
     (AF_WritingSystem_InitHintsFunc)   af_latin2_hints_init,
     (AF_WritingSystem_ApplyHintsFunc)  af_latin2_hints_apply
diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c
index 7c2fa7c..aa5b8fd 100644
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -23,6 +23,8 @@
 #include "afmodule.h"
 #include "afpic.h"
 
+#include FT_INTERNAL_CALC_H
+
 
   /* Initialize glyph loader. */
 
@@ -76,6 +78,14 @@
   }
 
 
+#define af_intToFixed( i ) \
+          ( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
+#define af_fixedToInt( x ) \
+          ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
+#define af_floatToFixed( f ) \
+          ( (FT_Fixed)( (f) * 65536.0 + 0.5 ) )
+
+
   /* Do the main work of `af_loader_load_glyph'.  Note that we never   */
   /* have to deal with composite glyphs as those get loaded into       */
   /* FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. */
@@ -88,6 +98,8 @@
                     FT_UInt    glyph_index,
                     FT_Int32   load_flags )
   {
+    AF_Module  module = loader->globals->module;
+
     FT_Error          error;
     FT_Face           face     = loader->face;
     AF_StyleMetrics   metrics  = loader->metrics;
@@ -103,6 +115,132 @@
     if ( error )
       goto Exit;
 
+    /*
+     * Apply stem darkening (emboldening) here before hints are applied to
+     * the outline.  Glyphs are scaled down proportionally to the
+     * emboldening so that curve points don't fall outside their precomputed
+     * blue zones.
+     *
+     * Any emboldening done by the font driver (e.g., the CFF driver)
+     * doesn't reach here because the autohinter loads the unprocessed
+     * glyphs in font units for analysis (functions `af_*_metrics_init_*')
+     * and then above to prepare it for the rasterizers by itself,
+     * independently of the font driver.  So emboldening must be done here,
+     * within the autohinter.
+     *
+     * All glyphs to be autohinted pass through here one by one.  The
+     * standard widths can therefore change from one glyph to the next,
+     * depending on what script a glyph is assigned to (each script has its
+     * own set of standard widths and other metrics).  The darkening amount
+     * must therefore be recomputed for each size and
+     * `standard_{vertical,horizontal}_width' change.
+     */
+    if ( !module->no_stem_darkening )
+    {
+      AF_FaceGlobals         globals = loader->globals;
+      AF_WritingSystemClass  writing_system_class;
+
+      FT_Pos  stdVW = 0;
+      FT_Pos  stdHW = 0;
+
+      FT_Bool  size_changed = face->size->metrics.x_ppem
+                                != globals->stem_darkening_for_ppem;
+
+      FT_Fixed  em_size  = af_intToFixed( face->units_per_EM );
+      FT_Fixed  em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size );
+
+      FT_Matrix  scale_down_matrix = { 0x10000L, 0, 0, 0x10000L };
+
+
+      /* Skip stem darkening for broken fonts. */
+      if ( !face->units_per_EM )
+        goto After_Emboldening;
+
+      /*
+       * We depend on the writing system (script analyzers) to supply
+       * standard widths for the script of the glyph we are looking at.  If
+       * it can't deliver, stem darkening is effectively disabled.
+       */
+      writing_system_class =
+        AF_WRITING_SYSTEM_CLASSES_GET[metrics->style_class->writing_system];
+
+      if ( writing_system_class->style_metrics_getstdw )
+        writing_system_class->style_metrics_getstdw( metrics,
+                                                     &stdHW,
+                                                     &stdVW );
+      else
+        goto After_Emboldening;
+
+
+      if ( size_changed                                               ||
+           ( stdVW > 0 && stdVW != globals->standard_vertical_width ) )
+      {
+        FT_Fixed  darken_by_font_units_x, darken_x;
+
+
+        darken_by_font_units_x =
+          af_intToFixed( af_loader_compute_darkening( loader,
+                                                      face,
+                                                      stdVW ) );
+        darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x,
+                                         face->size->metrics.x_scale ),
+                              em_ratio );
+
+        globals->standard_vertical_width = stdVW;
+        globals->stem_darkening_for_ppem = face->size->metrics.x_ppem;
+        globals->darken_x                = af_fixedToInt( darken_x );
+      }
+
+      if ( size_changed                                                 ||
+           ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) )
+      {
+        FT_Fixed  darken_by_font_units_y, darken_y;
+
+
+        darken_by_font_units_y =
+          af_intToFixed( af_loader_compute_darkening( loader,
+                                                      face,
+                                                      stdHW ) );
+        darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y,
+                                         face->size->metrics.y_scale ),
+                              em_ratio );
+
+        globals->standard_horizontal_width = stdHW;
+        globals->stem_darkening_for_ppem   = face->size->metrics.x_ppem;
+        globals->darken_y                  = af_fixedToInt( darken_y );
+
+        /*
+         * Scale outlines down on the Y-axis to keep them inside their blue
+         * zones.  The stronger the emboldening, the stronger the
+         * downscaling (plus heuristical padding to prevent outlines still
+         * falling out their zones due to rounding).
+         *
+         * Reason: `FT_Outline_Embolden' works by shifting the rightmost
+         * points of stems farther to the right, and topmost points farther
+         * up.  This positions points on the Y-axis outside their
+         * pre-computed blue zones and leads to distortion when applying the
+         * hints in the code further below.  Code outside this emboldening
+         * block doesn't know we are presenting it with modified outlines
+         * the analyzer didn't see!
+         *
+         * An unfortunate side effect of downscaling is that the emboldening
+         * effect is slightly decreased.  The loss becomes more pronounced
+         * versus the CFF driver at smaller sizes, e.g., at 9ppem and below.
+         */
+        globals->scale_down_factor =
+          FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ),
+                     em_size );
+      }
+
+      FT_Outline_EmboldenXY( &slot->outline,
+                             globals->darken_x,
+                             globals->darken_y );
+
+      scale_down_matrix.yy = globals->scale_down_factor;
+      FT_Outline_Transform( &slot->outline, &scale_down_matrix );
+    }
+
+  After_Emboldening:
     loader->transformed = internal->glyph_transformed;
     if ( loader->transformed )
     {
@@ -150,7 +288,8 @@
 
 
         if ( writing_system_class->style_hints_apply )
-          writing_system_class->style_hints_apply( hints,
+          writing_system_class->style_hints_apply( glyph_index,
+                                                   hints,
                                                    &gloader->base.outline,
                                                    metrics );
       }
@@ -404,4 +543,134 @@
   }
 
 
+  /*
+   * Compute amount of font units the face should be emboldened by, in
+   * analogy to the CFF driver's `cf2_computeDarkening' function.  See there
+   * for details of the algorithm.
+   *
+   * XXX: Currently a crude adaption of the original algorithm.  Do better?
+   */
+  FT_LOCAL_DEF( FT_Int32 )
+  af_loader_compute_darkening( AF_Loader  loader,
+                               FT_Face    face,
+                               FT_Pos     standard_width )
+  {
+    AF_Module  module = loader->globals->module;
+
+    FT_UShort  units_per_EM;
+    FT_Fixed   ppem, em_ratio;
+    FT_Fixed   stem_width, stem_width_per_1000, scaled_stem, darken_amount;
+    FT_Int     log_base_2;
+    FT_Int     x1, y1, x2, y2, x3, y3, x4, y4;
+
+
+    ppem         = FT_MAX( af_intToFixed( 4 ),
+                           af_intToFixed( face->size->metrics.x_ppem ) );
+    units_per_EM = face->units_per_EM;
+
+    em_ratio = FT_DivFix( af_intToFixed( 1000 ),
+                          af_intToFixed ( units_per_EM ) );
+    if ( em_ratio < af_floatToFixed( .01 ) )
+    {
+      /* If something goes wrong, don't embolden. */
+      return 0;
+    }
+
+    x1 = module->darken_params[0];
+    y1 = module->darken_params[1];
+    x2 = module->darken_params[2];
+    y2 = module->darken_params[3];
+    x3 = module->darken_params[4];
+    y3 = module->darken_params[5];
+    x4 = module->darken_params[6];
+    y4 = module->darken_params[7];
+
+    if ( standard_width <= 0 )
+    {
+      stem_width          = af_intToFixed( 75 ); /* taken from cf2font.c */
+      stem_width_per_1000 = stem_width;
+    }
+    else
+    {
+      stem_width          = af_intToFixed( standard_width );
+      stem_width_per_1000 = FT_MulFix( stem_width, em_ratio );
+    }
+
+    log_base_2 = FT_MSB( (FT_UInt32)stem_width_per_1000 ) +
+                 FT_MSB( (FT_UInt32)ppem );
+
+    if ( log_base_2 >= 46 )
+    {
+      /* possible overflow */
+      scaled_stem = af_intToFixed( x4 );
+    }
+    else
+      scaled_stem = FT_MulFix( stem_width_per_1000, ppem );
+
+    /* now apply the darkening parameters */
+    if ( scaled_stem < af_intToFixed( x1 ) )
+      darken_amount = FT_DivFix( af_intToFixed( y1 ), ppem );
+
+    else if ( scaled_stem < af_intToFixed( x2 ) )
+    {
+      FT_Int  xdelta = x2 - x1;
+      FT_Int  ydelta = y2 - y1;
+      FT_Int  x      = stem_width_per_1000 -
+                       FT_DivFix( af_intToFixed( x1 ), ppem );
+
+
+      if ( !xdelta )
+        goto Try_x3;
+
+      darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
+                      FT_DivFix( af_intToFixed( y1 ), ppem );
+    }
+
+    else if ( scaled_stem < af_intToFixed( x3 ) )
+    {
+    Try_x3:
+      {
+        FT_Int  xdelta = x3 - x2;
+        FT_Int  ydelta = y3 - y2;
+        FT_Int  x      = stem_width_per_1000 -
+                         FT_DivFix( af_intToFixed( x2 ), ppem );
+
+
+        if ( !xdelta )
+          goto Try_x4;
+
+        darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
+                        FT_DivFix( af_intToFixed( y2 ), ppem );
+      }
+    }
+
+    else if ( scaled_stem < af_intToFixed( x4 ) )
+    {
+    Try_x4:
+      {
+        FT_Int  xdelta = x4 - x3;
+        FT_Int  ydelta = y4 - y3;
+        FT_Int  x      = stem_width_per_1000 -
+                         FT_DivFix( af_intToFixed( x3 ), ppem );
+
+
+        if ( !xdelta )
+          goto Use_y4;
+
+        darken_amount = FT_MulDiv( x, ydelta, xdelta ) +
+                        FT_DivFix( af_intToFixed( y3 ), ppem );
+      }
+    }
+
+    else
+    {
+    Use_y4:
+      darken_amount = FT_DivFix( af_intToFixed( y4 ), ppem );
+    }
+
+    /* Convert darken_amount from per 1000 em to true character space. */
+    return af_fixedToInt( FT_DivFix( darken_amount, em_ratio ) );
+  }
+
+
 /* END */
diff --git a/src/autofit/afloader.h b/src/autofit/afloader.h
index 37cfd14..4c4affc 100644
--- a/src/autofit/afloader.h
+++ b/src/autofit/afloader.h
@@ -75,6 +75,11 @@
                         FT_UInt    gindex,
                         FT_Int32   load_flags );
 
+  FT_LOCAL_DEF( FT_Int32 )
+  af_loader_compute_darkening( AF_Loader  loader,
+                               FT_Face    face,
+                               FT_Pos     standard_width );
+
 /* */
 
 
diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c
index 8ae425c..45fd360 100644
--- a/src/autofit/afmodule.c
+++ b/src/autofit/afmodule.c
@@ -25,6 +25,10 @@
 #ifdef FT_DEBUG_AUTOFIT
 
 #ifndef FT_MAKE_OPTION_SINGLE_OBJECT
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
   extern void
   af_glyph_hints_dump_segments( AF_GlyphHints  hints,
                                 FT_Bool        to_stdout );
@@ -34,6 +38,10 @@
   extern void
   af_glyph_hints_dump_edges( AF_GlyphHints  hints,
                              FT_Bool        to_stdout );
+#ifdef __cplusplus
+  }
+#endif
+
 #endif
 
   int  _af_debug_disable_horz_hints;
@@ -169,6 +177,46 @@
       return error;
     }
 #endif /* AF_CONFIG_OPTION_USE_WARPER */
+    else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
+    {
+      FT_Int*  darken_params = (FT_Int*)value;
+
+      FT_Int  x1 = darken_params[0];
+      FT_Int  y1 = darken_params[1];
+      FT_Int  x2 = darken_params[2];
+      FT_Int  y2 = darken_params[3];
+      FT_Int  x3 = darken_params[4];
+      FT_Int  y3 = darken_params[5];
+      FT_Int  x4 = darken_params[6];
+      FT_Int  y4 = darken_params[7];
+
+
+      if ( x1 < 0   || x2 < 0   || x3 < 0   || x4 < 0   ||
+           y1 < 0   || y2 < 0   || y3 < 0   || y4 < 0   ||
+           x1 > x2  || x2 > x3  || x3 > x4              ||
+           y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 )
+        return FT_THROW( Invalid_Argument );
+
+      module->darken_params[0] = x1;
+      module->darken_params[1] = y1;
+      module->darken_params[2] = x2;
+      module->darken_params[3] = y2;
+      module->darken_params[4] = x3;
+      module->darken_params[5] = y3;
+      module->darken_params[6] = x4;
+      module->darken_params[7] = y4;
+
+      return error;
+    }
+    else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
+    {
+      FT_Bool*  no_stem_darkening = (FT_Bool*)value;
+
+
+      module->no_stem_darkening = *no_stem_darkening;
+
+      return error;
+    }
 
     FT_TRACE0(( "af_property_set: missing property `%s'\n",
                 property_name ));
@@ -245,6 +293,33 @@
       return error;
     }
 #endif /* AF_CONFIG_OPTION_USE_WARPER */
+    else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
+    {
+      FT_Int*  darken_params = module->darken_params;
+      FT_Int*  val           = (FT_Int*)value;
+
+
+      val[0] = darken_params[0];
+      val[1] = darken_params[1];
+      val[2] = darken_params[2];
+      val[3] = darken_params[3];
+      val[4] = darken_params[4];
+      val[5] = darken_params[5];
+      val[6] = darken_params[6];
+      val[7] = darken_params[7];
+
+      return error;
+    }
+    else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
+    {
+      FT_Bool   no_stem_darkening = module->no_stem_darkening;
+      FT_Bool*  val               = (FT_Bool*)value;
+
+
+      *val = no_stem_darkening;
+
+      return error;
+    }
 
     FT_TRACE0(( "af_property_get: missing property `%s'\n",
                 property_name ));
@@ -254,8 +329,8 @@
 
   FT_DEFINE_SERVICE_PROPERTIESREC(
     af_service_properties,
-    (FT_Properties_SetFunc)af_property_set,
-    (FT_Properties_GetFunc)af_property_get )
+    (FT_Properties_SetFunc)af_property_set,        /* set_property */
+    (FT_Properties_GetFunc)af_property_get )       /* get_property */
 
 
   FT_DEFINE_SERVICEDESCREC1(
@@ -291,11 +366,21 @@
     AF_Module  module = (AF_Module)ft_module;
 
 
-    module->fallback_style = AF_STYLE_FALLBACK;
-    module->default_script = AF_SCRIPT_DEFAULT;
+    module->fallback_style    = AF_STYLE_FALLBACK;
+    module->default_script    = AF_SCRIPT_DEFAULT;
 #ifdef AF_CONFIG_OPTION_USE_WARPER
-    module->warping        = 0;
+    module->warping           = 0;
 #endif
+    module->no_stem_darkening = TRUE;
+
+    module->darken_params[0]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
+    module->darken_params[1]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
+    module->darken_params[2]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2;
+    module->darken_params[3]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2;
+    module->darken_params[4]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3;
+    module->darken_params[5]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3;
+    module->darken_params[6]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
+    module->darken_params[7]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
 
     return FT_Err_Ok;
   }
diff --git a/src/autofit/afmodule.h b/src/autofit/afmodule.h
index b9c2fd8..3c61d89 100644
--- a/src/autofit/afmodule.h
+++ b/src/autofit/afmodule.h
@@ -41,6 +41,8 @@
 #ifdef AF_CONFIG_OPTION_USE_WARPER
     FT_Bool       warping;
 #endif
+    FT_Bool       no_stem_darkening;
+    FT_Int        darken_params[8];
 
   } AF_ModuleRec, *AF_Module;
 
diff --git a/src/autofit/afpic.c b/src/autofit/afpic.c
index 5589e61..37254a2 100644
--- a/src/autofit/afpic.c
+++ b/src/autofit/afpic.c
@@ -122,7 +122,7 @@
 #include "afwrtsys.h"
 
 #undef  SCRIPT
-#define SCRIPT( s, S, d, h, sc1, sc2, sc3 )          \
+#define SCRIPT( s, S, d, h, sss )                    \
         FT_Init_Class_af_ ## s ## _script_class(     \
           &container->af_script_classes_rec[ss++] );
 
diff --git a/src/autofit/afpic.h b/src/autofit/afpic.h
index 25071e3..9b45069 100644
--- a/src/autofit/afpic.h
+++ b/src/autofit/afpic.h
@@ -20,8 +20,6 @@
 #define __AFPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
 
@@ -43,6 +41,8 @@
 #include "aftypes.h"
 
 
+FT_BEGIN_HEADER
+
   typedef struct  AFModulePIC_
   {
     FT_ServiceDescRec*          af_services;
@@ -93,12 +93,12 @@
   FT_Error
   autofit_module_class_pic_init( FT_Library  library );
 
+FT_END_HEADER
+
 #endif /* FT_CONFIG_OPTION_PIC */
 
  /* */
 
-FT_END_HEADER
-
 #endif /* __AFPIC_H__ */
 
 
diff --git a/src/autofit/afranges.c b/src/autofit/afranges.c
index c1e0afb..cf8bb7c 100644
--- a/src/autofit/afranges.c
+++ b/src/autofit/afranges.c
@@ -18,6 +18,43 @@
 
 #include "afranges.h"
 
+  /*
+   * The algorithm for assigning properties and styles to the `glyph_styles'
+   * array is as follows (cf. the implementation in
+   * `af_face_globals_compute_style_coverage').
+   *
+   *   Walk over all scripts (as listed in `afscript.h').
+   *
+   *   For a given script, walk over all styles (as listed in `afstyles.h').
+   *   The order of styles is important and should be as follows.
+   *
+   *   - First come styles based on OpenType features (small caps, for
+   *     example).  Since features rely on glyph indices, thus completely
+   *     bypassing character codes, no properties are assigned.
+   *
+   *   - Next comes the default style, using the character ranges as defined
+   *     below.  This also assigns properties.
+   *
+   *   Note that there also exist fallback scripts, mainly covering
+   *   superscript and subscript glyphs of a script that are not present as
+   *   OpenType features.  Fallback scripts are defined below, also
+   *   assigning properties; they are applied after the corresponding
+   *   script.
+   *
+   */
+
+
+  /* XXX Check base character ranges again:                        */
+  /*     Right now, they are quickly derived by visual inspection. */
+  /*     I can imagine that fine-tuning is necessary.              */
+
+  /* for the auto-hinter, a `non-base character' is something that should */
+  /* not be affected by blue zones, regardless of whether this is a       */
+  /* spacing or no-spacing glyph                                          */
+
+  /* the `ta_xxxx_nonbase_uniranges' ranges must be strict subsets */
+  /* of the corresponding `ta_xxxx_uniranges' ranges               */
+
 
   const AF_Script_UniRangeRec  af_arab_uniranges[] =
   {
@@ -30,6 +67,30 @@
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_arab_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0600UL,  0x0605UL ),
+    AF_UNIRANGE_REC(  0x0610UL,  0x061AUL ),
+    AF_UNIRANGE_REC(  0x064BUL,  0x065FUL ),
+    AF_UNIRANGE_REC(  0x0670UL,  0x0670UL ),
+    AF_UNIRANGE_REC(  0x06D6UL,  0x06DCUL ),
+    AF_UNIRANGE_REC(  0x06DFUL,  0x06E4UL ),
+    AF_UNIRANGE_REC(  0x06E7UL,  0x06E8UL ),
+    AF_UNIRANGE_REC(  0x06EAUL,  0x06EDUL ),
+    AF_UNIRANGE_REC(  0x08E3UL,  0x08FFUL ),
+    AF_UNIRANGE_REC(  0xFBB2UL,  0xFBC1UL ),
+    AF_UNIRANGE_REC(  0xFE70UL,  0xFE70UL ),
+    AF_UNIRANGE_REC(  0xFE72UL,  0xFE72UL ),
+    AF_UNIRANGE_REC(  0xFE74UL,  0xFE74UL ),
+    AF_UNIRANGE_REC(  0xFE76UL,  0xFE76UL ),
+    AF_UNIRANGE_REC(  0xFE78UL,  0xFE78UL ),
+    AF_UNIRANGE_REC(  0xFE7AUL,  0xFE7AUL ),
+    AF_UNIRANGE_REC(  0xFE7CUL,  0xFE7CUL ),
+    AF_UNIRANGE_REC(  0xFE7EUL,  0xFE7EUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_cyrl_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0400UL,  0x04FFUL ),  /* Cyrillic            */
@@ -39,23 +100,47 @@
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
-  /* there are some characters in the Devanagari Unicode block that are    */
+  const AF_Script_UniRangeRec  af_cyrl_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0483UL,  0x0489UL ),
+    AF_UNIRANGE_REC(  0x2DE0UL,  0x2DFFUL ),
+    AF_UNIRANGE_REC(  0xA66FUL,  0xA67FUL ),
+    AF_UNIRANGE_REC(  0xA69EUL,  0xA69FUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
+  /* There are some characters in the Devanagari Unicode block that are    */
   /* generic to Indic scripts; we omit them so that their presence doesn't */
-  /* trigger Devanagari                                                    */
+  /* trigger Devanagari.                                                   */
 
   const AF_Script_UniRangeRec  af_deva_uniranges[] =
   {
-    AF_UNIRANGE_REC(  0x0900UL,  0x093BUL ),  /* Devanagari       */
+    AF_UNIRANGE_REC(  0x0900UL,  0x093BUL ),  /* Devanagari          */
     /* omitting U+093C nukta */
-    AF_UNIRANGE_REC(  0x093DUL,  0x0950UL ),
+    AF_UNIRANGE_REC(  0x093DUL,  0x0950UL ),  /* ... continued       */
     /* omitting U+0951 udatta, U+0952 anudatta */
-    AF_UNIRANGE_REC(  0x0953UL,  0x0963UL ),
+    AF_UNIRANGE_REC(  0x0953UL,  0x0963UL ),  /* ... continued       */
     /* omitting U+0964 danda, U+0965 double danda */
-    AF_UNIRANGE_REC(  0x0966UL,  0x097FUL ),
-    AF_UNIRANGE_REC(  0x20B9UL,  0x20B9UL ),  /* (new) Rupee sign */
+    AF_UNIRANGE_REC(  0x0966UL,  0x097FUL ),  /* ... continued       */
+    AF_UNIRANGE_REC(  0x20B9UL,  0x20B9UL ),  /* (new) Rupee sign    */
+    AF_UNIRANGE_REC(  0xA8E0UL,  0xA8FFUL ),  /* Devanagari Extended */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_deva_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0900UL,  0x0902UL ),
+    AF_UNIRANGE_REC(  0x093AUL,  0x093AUL ),
+    AF_UNIRANGE_REC(  0x0941UL,  0x0948UL ),
+    AF_UNIRANGE_REC(  0x094DUL,  0x094DUL ),
+    AF_UNIRANGE_REC(  0x0953UL,  0x0957UL ),
+    AF_UNIRANGE_REC(  0x0962UL,  0x0963UL ),
+    AF_UNIRANGE_REC(  0xA8E0UL,  0xA8F1UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_grek_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0370UL,  0x03FFUL ),  /* Greek and Coptic */
@@ -63,6 +148,19 @@
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_grek_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x037AUL,  0x037AUL ),
+    AF_UNIRANGE_REC(  0x0384UL,  0x0385UL ),
+    AF_UNIRANGE_REC(  0x1FBDUL,  0x1FC1UL ),
+    AF_UNIRANGE_REC(  0x1FCDUL,  0x1FCFUL ),
+    AF_UNIRANGE_REC(  0x1FDDUL,  0x1FDFUL ),
+    AF_UNIRANGE_REC(  0x1FEDUL,  0x1FEFUL ),
+    AF_UNIRANGE_REC(  0x1FFDUL,  0x1FFEUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_hebr_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0590UL,  0x05FFUL ),  /* Hebrew                          */
@@ -70,51 +168,225 @@
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_hebr_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0591UL,  0x05BFUL ),
+    AF_UNIRANGE_REC(  0x05C1UL,  0x05C2UL ),
+    AF_UNIRANGE_REC(  0x05C4UL,  0x05C5UL ),
+    AF_UNIRANGE_REC(  0x05C7UL,  0x05C7UL ),
+    AF_UNIRANGE_REC(  0xFB1EUL,  0xFB1EUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
+  const AF_Script_UniRangeRec  af_khmr_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x1780UL,  0x17FFUL ),  /* Khmer */
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+  const AF_Script_UniRangeRec  af_khmr_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x17B7UL,  0x17BDUL ),
+    AF_UNIRANGE_REC(  0x17C6UL,  0x17C6UL ),
+    AF_UNIRANGE_REC(  0x17C9UL,  0x17D3UL ),
+    AF_UNIRANGE_REC(  0x17DDUL,  0x17DDUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
+  const AF_Script_UniRangeRec  af_khms_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x19E0UL,  0x19FFUL ),  /* Khmer Symbols */
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+  const AF_Script_UniRangeRec  af_khms_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC( 0UL, 0UL )
+  };
+
+
+  const AF_Script_UniRangeRec  af_lao_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0E80UL,  0x0EFFUL ),  /* Lao */
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+  const AF_Script_UniRangeRec  af_lao_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0EB1UL,  0x0EB1UL ),
+    AF_UNIRANGE_REC(  0x0EB4UL,  0x0EBCUL ),
+    AF_UNIRANGE_REC(  0x0EC8UL,  0x0ECDUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_latn_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0020UL,  0x007FUL ),  /* Basic Latin (no control chars)         */
-    AF_UNIRANGE_REC(  0x00A0UL,  0x00FFUL ),  /* Latin-1 Supplement (no control chars)  */
+    AF_UNIRANGE_REC(  0x00A0UL,  0x00A9UL ),  /* Latin-1 Supplement (no control chars)  */
+    AF_UNIRANGE_REC(  0x00ABUL,  0x00B1UL ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0x00B4UL,  0x00B8UL ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0x00BBUL,  0x00FFUL ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0x0100UL,  0x017FUL ),  /* Latin Extended-A                       */
     AF_UNIRANGE_REC(  0x0180UL,  0x024FUL ),  /* Latin Extended-B                       */
     AF_UNIRANGE_REC(  0x0250UL,  0x02AFUL ),  /* IPA Extensions                         */
-    AF_UNIRANGE_REC(  0x02B0UL,  0x02FFUL ),  /* Spacing Modifier Letters               */
+    AF_UNIRANGE_REC(  0x02B9UL,  0x02DFUL ),  /* Spacing Modifier Letters               */
+    AF_UNIRANGE_REC(  0x02E5UL,  0x02FFUL ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0x0300UL,  0x036FUL ),  /* Combining Diacritical Marks            */
-    AF_UNIRANGE_REC(  0x1D00UL,  0x1D7FUL ),  /* Phonetic Extensions                    */
-    AF_UNIRANGE_REC(  0x1D80UL,  0x1DBFUL ),  /* Phonetic Extensions Supplement         */
+    AF_UNIRANGE_REC(  0x1AB0UL,  0x1ABEUL ),  /* Combining Diacritical Marks Extended   */
+    AF_UNIRANGE_REC(  0x1D00UL,  0x1D2BUL ),  /* Phonetic Extensions                    */
+    AF_UNIRANGE_REC(  0x1D6BUL,  0x1D77UL ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0x1D79UL,  0x1D7FUL ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0x1D80UL,  0x1D9AUL ),  /* Phonetic Extensions Supplement         */
     AF_UNIRANGE_REC(  0x1DC0UL,  0x1DFFUL ),  /* Combining Diacritical Marks Supplement */
     AF_UNIRANGE_REC(  0x1E00UL,  0x1EFFUL ),  /* Latin Extended Additional              */
     AF_UNIRANGE_REC(  0x2000UL,  0x206FUL ),  /* General Punctuation                    */
-    AF_UNIRANGE_REC(  0x2070UL,  0x209FUL ),  /* Superscripts and Subscripts            */
     AF_UNIRANGE_REC(  0x20A0UL,  0x20B8UL ),  /* Currency Symbols ...                   */
     AF_UNIRANGE_REC(  0x20BAUL,  0x20CFUL ),  /* ... except new Rupee sign              */
     AF_UNIRANGE_REC(  0x2150UL,  0x218FUL ),  /* Number Forms                           */
-    AF_UNIRANGE_REC(  0x2460UL,  0x24FFUL ),  /* Enclosed Alphanumerics                 */
-    AF_UNIRANGE_REC(  0x2C60UL,  0x2C7FUL ),  /* Latin Extended-C                       */
+    AF_UNIRANGE_REC(  0x2C60UL,  0x2C7BUL ),  /* Latin Extended-C                       */
+    AF_UNIRANGE_REC(  0x2C7EUL,  0x2C7FUL ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0x2E00UL,  0x2E7FUL ),  /* Supplemental Punctuation               */
-    AF_UNIRANGE_REC(  0xA720UL,  0xA7FFUL ),  /* Latin Extended-D                       */
+    AF_UNIRANGE_REC(  0xA720UL,  0xA76FUL ),  /* Latin Extended-D                       */
+    AF_UNIRANGE_REC(  0xA771UL,  0xA7F7UL ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0xA7FAUL,  0xA7FFUL ),  /* ... continued                          */
+    AF_UNIRANGE_REC(  0xAB30UL,  0xAB5BUL ),  /* Latin Extended-E                       */
+    AF_UNIRANGE_REC(  0xAB60UL,  0xAB6FUL ),  /* ... continued                          */
     AF_UNIRANGE_REC(  0xFB00UL,  0xFB06UL ),  /* Alphab. Present. Forms (Latin Ligs)    */
     AF_UNIRANGE_REC( 0x1D400UL, 0x1D7FFUL ),  /* Mathematical Alphanumeric Symbols      */
-    AF_UNIRANGE_REC( 0x1F100UL, 0x1F1FFUL ),  /* Enclosed Alphanumeric Supplement       */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_latn_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x005EUL,  0x0060UL ),
+    AF_UNIRANGE_REC(  0x007EUL,  0x007EUL ),
+    AF_UNIRANGE_REC(  0x00A8UL,  0x00A9UL ),
+    AF_UNIRANGE_REC(  0x00AEUL,  0x00B0UL ),
+    AF_UNIRANGE_REC(  0x00B4UL,  0x00B4UL ),
+    AF_UNIRANGE_REC(  0x00B8UL,  0x00B8UL ),
+    AF_UNIRANGE_REC(  0x00BCUL,  0x00BEUL ),
+    AF_UNIRANGE_REC(  0x02B9UL,  0x02DFUL ),
+    AF_UNIRANGE_REC(  0x02E5UL,  0x02FFUL ),
+    AF_UNIRANGE_REC(  0x0300UL,  0x036FUL ),
+    AF_UNIRANGE_REC(  0x1AB0UL,  0x1ABEUL ),
+    AF_UNIRANGE_REC(  0x1DC0UL,  0x1DFFUL ),
+    AF_UNIRANGE_REC(  0x2017UL,  0x2017UL ),
+    AF_UNIRANGE_REC(  0x203EUL,  0x203EUL ),
+    AF_UNIRANGE_REC(  0xA788UL,  0xA788UL ),
+    AF_UNIRANGE_REC(  0xA7F8UL,  0xA7FAUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
+  const AF_Script_UniRangeRec  af_latb_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x1D62UL,  0x1D6AUL ),  /* some small subscript letters   */
+    AF_UNIRANGE_REC(  0x2080UL,  0x209CUL ),  /* subscript digits and letters   */
+    AF_UNIRANGE_REC(  0x2C7CUL,  0x2C7CUL ),  /* latin subscript small letter j */
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+  const AF_Script_UniRangeRec  af_latb_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC( 0UL, 0UL )
+  };
+
+
+  const AF_Script_UniRangeRec  af_latp_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x00AAUL,  0x00AAUL ),  /* feminine ordinal indicator          */
+    AF_UNIRANGE_REC(  0x00B2UL,  0x00B3UL ),  /* superscript two and three           */
+    AF_UNIRANGE_REC(  0x00B9UL,  0x00BAUL ),  /* superscript one, masc. ord. indic.  */
+    AF_UNIRANGE_REC(  0x02B0UL,  0x02B8UL ),  /* some latin superscript mod. letters */
+    AF_UNIRANGE_REC(  0x02E0UL,  0x02E4UL ),  /* some IPA modifier letters           */
+    AF_UNIRANGE_REC(  0x1D2CUL,  0x1D61UL ),  /* latin superscript modifier letters  */
+    AF_UNIRANGE_REC(  0x1D78UL,  0x1D78UL ),  /* modifier letter cyrillic en         */
+    AF_UNIRANGE_REC(  0x1D9BUL,  0x1DBFUL ),  /* more modifier letters               */
+    AF_UNIRANGE_REC(  0x2070UL,  0x207FUL ),  /* superscript digits and letters      */
+    AF_UNIRANGE_REC(  0x2C7DUL,  0x2C7DUL ),  /* modifier letter capital v           */
+    AF_UNIRANGE_REC(  0xA770UL,  0xA770UL ),  /* modifier letter us                  */
+    AF_UNIRANGE_REC(  0xA7F8UL,  0xA7F9UL ),  /* more modifier letters               */
+    AF_UNIRANGE_REC(  0xAB5CUL,  0xAB5FUL ),  /* more modifier letters               */
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+  const AF_Script_UniRangeRec  af_latp_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC( 0UL, 0UL )
+  };
+
+
+  const AF_Script_UniRangeRec  af_mymr_uniranges[] =
+  {
+    AF_UNIRANGE_REC( 0x1000UL, 0x109FUL ),    /* Myanmar            */
+    AF_UNIRANGE_REC( 0xA9E0UL, 0xA9FFUL ),    /* Myanmar Extended-B */
+    AF_UNIRANGE_REC( 0xAA60UL, 0xAA7FUL ),    /* Myanmar Extended-A */
+    AF_UNIRANGE_REC(      0UL,      0UL )
+  };
+
+  const AF_Script_UniRangeRec  af_mymr_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC( 0x102DUL, 0x1030UL ),
+    AF_UNIRANGE_REC( 0x1032UL, 0x1037UL ),
+    AF_UNIRANGE_REC( 0x103AUL, 0x103AUL ),
+    AF_UNIRANGE_REC( 0x103DUL, 0x103EUL ),
+    AF_UNIRANGE_REC( 0x1058UL, 0x1059UL ),
+    AF_UNIRANGE_REC( 0x105EUL, 0x1060UL ),
+    AF_UNIRANGE_REC( 0x1071UL, 0x1074UL ),
+    AF_UNIRANGE_REC( 0x1082UL, 0x1082UL ),
+    AF_UNIRANGE_REC( 0x1085UL, 0x1086UL ),
+    AF_UNIRANGE_REC( 0x108DUL, 0x108DUL ),
+    AF_UNIRANGE_REC( 0xA9E5UL, 0xA9E5UL ),
+    AF_UNIRANGE_REC( 0xAA7CUL, 0xAA7CUL ),
+    AF_UNIRANGE_REC(      0UL,      0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_none_uniranges[] =
   {
     AF_UNIRANGE_REC( 0UL, 0UL )
   };
 
+  const AF_Script_UniRangeRec  af_none_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC( 0UL, 0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_telu_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0C00UL,  0x0C7FUL ),  /* Telugu */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_telu_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0C00UL,  0x0C00UL ),
+    AF_UNIRANGE_REC(  0x0C3EUL,  0x0C40UL ),
+    AF_UNIRANGE_REC(  0x0C46UL,  0x0C56UL ),
+    AF_UNIRANGE_REC(  0x0C62UL,  0x0C63UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_thai_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0E00UL,  0x0E7FUL ),  /* Thai */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_thai_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0E31UL,  0x0E31UL ),
+    AF_UNIRANGE_REC(  0x0E34UL,  0x0E3AUL ),
+    AF_UNIRANGE_REC(  0x0E47UL,  0x0E4EUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
 #ifdef AF_CONFIG_OPTION_INDIC
 
   const AF_Script_UniRangeRec  af_beng_uniranges[] =
@@ -123,72 +395,197 @@
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_beng_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0981UL,  0x0981UL ),
+    AF_UNIRANGE_REC(  0x09BCUL,  0x09BCUL ),
+    AF_UNIRANGE_REC(  0x09C1UL,  0x09C4UL ),
+    AF_UNIRANGE_REC(  0x09CDUL,  0x09CDUL ),
+    AF_UNIRANGE_REC(  0x09E2UL,  0x09E3UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_gujr_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0A80UL,  0x0AFFUL ),  /* Gujarati */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_gujr_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0A81UL,  0x0A82UL ),
+    AF_UNIRANGE_REC(  0x0ABCUL,  0x0ABCUL ),
+    AF_UNIRANGE_REC(  0x0AC1UL,  0x0AC8UL ),
+    AF_UNIRANGE_REC(  0x0ACDUL,  0x0ACDUL ),
+    AF_UNIRANGE_REC(  0x0AE2UL,  0x0AE3UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_guru_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0A00UL,  0x0A7FUL ),  /* Gurmukhi */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_guru_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0A01UL,  0x0A02UL ),
+    AF_UNIRANGE_REC(  0x0A3CUL,  0x0A3EUL ),
+    AF_UNIRANGE_REC(  0x0A41UL,  0x0A51UL ),
+    AF_UNIRANGE_REC(  0x0A70UL,  0x0A71UL ),
+    AF_UNIRANGE_REC(  0x0A75UL,  0x0A75UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_knda_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0C80UL,  0x0CFFUL ),  /* Kannada */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_knda_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0C81UL,  0x0C81UL ),
+    AF_UNIRANGE_REC(  0x0CBCUL,  0x0CBCUL ),
+    AF_UNIRANGE_REC(  0x0CBFUL,  0x0CBFUL ),
+    AF_UNIRANGE_REC(  0x0CC6UL,  0x0CC6UL ),
+    AF_UNIRANGE_REC(  0x0CCCUL,  0x0CCDUL ),
+    AF_UNIRANGE_REC(  0x0CE2UL,  0x0CE3UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_limb_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x1900UL,  0x194FUL ),  /* Limbu */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_limb_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x1920UL,  0x1922UL ),
+    AF_UNIRANGE_REC(  0x1927UL,  0x1934UL ),
+    AF_UNIRANGE_REC(  0x1937UL,  0x193BUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_mlym_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0D00UL,  0x0D7FUL ),  /* Malayalam */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_mlym_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0D01UL,  0x0D01UL ),
+    AF_UNIRANGE_REC(  0x0D4DUL,  0x0D4EUL ),
+    AF_UNIRANGE_REC(  0x0D62UL,  0x0D63UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_orya_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0B00UL,  0x0B7FUL ),  /* Oriya */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_orya_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0B01UL,  0x0B02UL ),
+    AF_UNIRANGE_REC(  0x0B3CUL,  0x0B3CUL ),
+    AF_UNIRANGE_REC(  0x0B3FUL,  0x0B3FUL ),
+    AF_UNIRANGE_REC(  0x0B41UL,  0x0B44UL ),
+    AF_UNIRANGE_REC(  0x0B4DUL,  0x0B56UL ),
+    AF_UNIRANGE_REC(  0x0B62UL,  0x0B63UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_sinh_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0D80UL,  0x0DFFUL ),  /* Sinhala */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
-  const AF_Script_UniRangeRec  af_sund_uniranges[] =
+  const AF_Script_UniRangeRec  af_sinh_nonbase_uniranges[] =
   {
-    AF_UNIRANGE_REC(  0x1B80UL,  0x1BBFUL ),  /* Sundanese */
+    AF_UNIRANGE_REC(  0x0DCAUL,  0x0DCAUL ),
+    AF_UNIRANGE_REC(  0x0DD2UL,  0x0DD6UL ),
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+
+  const AF_Script_UniRangeRec  af_sund_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x1B80UL,  0x1BBFUL ),  /* Sundanese            */
+    AF_UNIRANGE_REC(  0x1CC0UL,  0x1CCFUL ),  /* Sundanese Supplement */
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+  const AF_Script_UniRangeRec  af_sund_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x1B80UL,  0x1B82UL ),
+    AF_UNIRANGE_REC(  0x1BA1UL,  0x1BADUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_sylo_uniranges[] =
   {
     AF_UNIRANGE_REC(  0xA800UL,  0xA82FUL ),  /* Syloti Nagri */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_sylo_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0xA802UL,  0xA802UL ),
+    AF_UNIRANGE_REC(  0xA806UL,  0xA806UL ),
+    AF_UNIRANGE_REC(  0xA80BUL,  0xA80BUL ),
+    AF_UNIRANGE_REC(  0xA825UL,  0xA826UL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_taml_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0B80UL,  0x0BFFUL ),  /* Tamil */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_taml_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0B82UL,  0x0B82UL ),
+    AF_UNIRANGE_REC(  0x0BC0UL,  0x0BC2UL ),
+    AF_UNIRANGE_REC(  0x0BCDUL,  0x0BCDUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
+
   const AF_Script_UniRangeRec  af_tibt_uniranges[] =
   {
     AF_UNIRANGE_REC(  0x0F00UL,  0x0FFFUL ),  /* Tibetan */
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_tibt_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x0F18UL,  0x0F19UL ),
+    AF_UNIRANGE_REC(  0x0F35UL,  0x0F35UL ),
+    AF_UNIRANGE_REC(  0x0F37UL,  0x0F37UL ),
+    AF_UNIRANGE_REC(  0x0F39UL,  0x0F39UL ),
+    AF_UNIRANGE_REC(  0x0F3EUL,  0x0F3FUL ),
+    AF_UNIRANGE_REC(  0x0F71UL,  0x0F7EUL ),
+    AF_UNIRANGE_REC(  0x0F80UL,  0x0F84UL ),
+    AF_UNIRANGE_REC(  0x0F86UL,  0x0F87UL ),
+    AF_UNIRANGE_REC(  0x0F8DUL,  0x0FBCUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
 #endif /* !AF_CONFIG_OPTION_INDIC */
 
 #ifdef AF_CONFIG_OPTION_CJK
@@ -210,7 +607,6 @@
     AF_UNIRANGE_REC(  0x31A0UL,  0x31BFUL ),  /* Bopomofo Extended                       */
     AF_UNIRANGE_REC(  0x31C0UL,  0x31EFUL ),  /* CJK Strokes                             */
     AF_UNIRANGE_REC(  0x31F0UL,  0x31FFUL ),  /* Katakana Phonetic Extensions            */
-    AF_UNIRANGE_REC(  0x3200UL,  0x32FFUL ),  /* Enclosed CJK Letters and Months         */
     AF_UNIRANGE_REC(  0x3300UL,  0x33FFUL ),  /* CJK Compatibility                       */
     AF_UNIRANGE_REC(  0x3400UL,  0x4DBFUL ),  /* CJK Unified Ideographs Extension A      */
     AF_UNIRANGE_REC(  0x4DC0UL,  0x4DFFUL ),  /* Yijing Hexagram Symbols                 */
@@ -224,7 +620,6 @@
     AF_UNIRANGE_REC(  0xFF00UL,  0xFFEFUL ),  /* Halfwidth and Fullwidth Forms           */
     AF_UNIRANGE_REC( 0x1B000UL, 0x1B0FFUL ),  /* Kana Supplement                         */
     AF_UNIRANGE_REC( 0x1D300UL, 0x1D35FUL ),  /* Tai Xuan Hing Symbols                   */
-    AF_UNIRANGE_REC( 0x1F200UL, 0x1F2FFUL ),  /* Enclosed Ideographic Supplement         */
     AF_UNIRANGE_REC( 0x20000UL, 0x2A6DFUL ),  /* CJK Unified Ideographs Extension B      */
     AF_UNIRANGE_REC( 0x2A700UL, 0x2B73FUL ),  /* CJK Unified Ideographs Extension C      */
     AF_UNIRANGE_REC( 0x2B740UL, 0x2B81FUL ),  /* CJK Unified Ideographs Extension D      */
@@ -232,6 +627,13 @@
     AF_UNIRANGE_REC(       0UL,       0UL )
   };
 
+  const AF_Script_UniRangeRec  af_hani_nonbase_uniranges[] =
+  {
+    AF_UNIRANGE_REC(  0x302AUL,  0x302FUL ),
+    AF_UNIRANGE_REC(  0x3190UL,  0x319FUL ),
+    AF_UNIRANGE_REC(       0UL,       0UL )
+  };
+
 #endif /* !AF_CONFIG_OPTION_CJK */
 
 /* END */
diff --git a/src/autofit/afranges.h b/src/autofit/afranges.h
index 7c78ab0..bca5084 100644
--- a/src/autofit/afranges.h
+++ b/src/autofit/afranges.h
@@ -26,11 +26,17 @@
 FT_BEGIN_HEADER
 
 #undef  SCRIPT
-#define SCRIPT( s, S, d, h, sc1, sc2, sc3 )                             \
+#define SCRIPT( s, S, d, h, ss )                                        \
           extern const AF_Script_UniRangeRec  af_ ## s ## _uniranges[];
 
 #include "afscript.h"
 
+#undef  SCRIPT
+#define SCRIPT( s, S, d, h, ss )                                                \
+          extern const AF_Script_UniRangeRec  af_ ## s ## _nonbase_uniranges[];
+
+#include "afscript.h"
+
  /* */
 
 FT_END_HEADER
diff --git a/src/autofit/afscript.h b/src/autofit/afscript.h
index dfcc830..39ec652 100644
--- a/src/autofit/afscript.h
+++ b/src/autofit/afscript.h
@@ -25,114 +25,150 @@
   /* by a description string.  Then comes the corresponding HarfBuzz  */
   /* script name tag, followed by a string of standard characters (to */
   /* derive the standard width and height of stems).                  */
+  /*                                                                  */
+  /* Note that fallback scripts only have a default style, thus we    */
+  /* use `HB_SCRIPT_INVALID' as the HarfBuzz script name tag for      */
+  /* them.                                                            */
 
   SCRIPT( arab, ARAB,
           "Arabic",
           HB_SCRIPT_ARABIC,
-          0x644, 0x62D, 0x640 ) /* ل ح ـ */
+          "\xD9\x84 \xD8\xAD \xD9\x80" ) /* ل ح ـ */
 
   SCRIPT( cyrl, CYRL,
           "Cyrillic",
           HB_SCRIPT_CYRILLIC,
-          0x43E, 0x41E, 0x0 ) /* оО */
+          "\xD0\xBE \xD0\x9E" ) /* о О */
 
   SCRIPT( deva, DEVA,
           "Devanagari",
           HB_SCRIPT_DEVANAGARI,
-          0x920, 0x935, 0x91F ) /* ठ व ट */
+          "\xE0\xA4\xA0 \xE0\xA4\xB5 \xE0\xA4\x9F" ) /* ठ व ट */
 
   SCRIPT( grek, GREK,
           "Greek",
           HB_SCRIPT_GREEK,
-          0x3BF, 0x39F, 0x0 ) /* οΟ */
+          "\xCE\xBF \xCE\x9F" ) /* ο Ο */
 
   SCRIPT( hebr, HEBR,
           "Hebrew",
           HB_SCRIPT_HEBREW,
-          0x5DD, 0x0, 0x0 ) /* ם */
+          "\xD7\x9D" ) /* ם */
+
+  /* only digit zero has a simple shape in the Khmer script */
+  SCRIPT( khmr, KHMR,
+          "Khmer",
+          HB_SCRIPT_KHMER,
+          "\xE1\x9F\xA0" ) /* ០ */
+
+  SCRIPT( khms, KHMS,
+          "Khmer Symbols",
+          HB_SCRIPT_INVALID,
+          "\xE1\xA7\xA1 \xE1\xA7\xAA" ) /* ᧡ ᧪ */
+
+  /* only digit zero has a simple shape in the Lao script */
+  SCRIPT( lao, LAO,
+          "Lao",
+          HB_SCRIPT_LAO,
+          "\xE0\xBB\x90" ) /* ໐ */
 
   SCRIPT( latn, LATN,
           "Latin",
           HB_SCRIPT_LATIN,
-          'o', 'O', '0' )
+          "o O 0" )
+
+  SCRIPT( latb, LATB,
+          "Latin Subscript Fallback",
+          HB_SCRIPT_INVALID,
+          "\xE2\x82\x92 \xE2\x82\x80" ) /* ₒ ₀ */
+
+  SCRIPT( latp, LATP,
+          "Latin Superscript Fallback",
+          HB_SCRIPT_INVALID,
+          "\xE1\xB5\x92 \xE1\xB4\xBC \xE2\x81\xB0" ) /* ᵒ ᴼ ⁰ */
+
+  SCRIPT( mymr, MYMR,
+          "Myanmar",
+          HB_SCRIPT_MYANMAR,
+          "\xE1\x80\x9D \xE1\x80\x84 \xE1\x80\x82" ) /* ဝ င ဂ */
 
   SCRIPT( none, NONE,
           "no script",
           HB_SCRIPT_INVALID,
-          0x0, 0x0, 0x0 )
+          "" )
 
   /* there are no simple forms for letters; we thus use two digit shapes */
   SCRIPT( telu, TELU,
           "Telugu",
           HB_SCRIPT_TELUGU,
-          0xC66, 0xC67, 0x0 ) /* ౦ ౧ */
+          "\xE0\xB1\xA6 \xE0\xB1\xA7" ) /* ౦ ౧ */
 
   SCRIPT( thai, THAI,
           "Thai",
           HB_SCRIPT_THAI,
-          0xE32, 0xE45, 0xE50 ) /* า ๅ ๐ */
+          "\xE0\xB8\xB2 \xE0\xB9\x85 \xE0\xB9\x90" ) /* า ๅ ๐ */
 
 #ifdef AF_CONFIG_OPTION_INDIC
 
   SCRIPT( beng, BENG,
           "Bengali",
           HB_SCRIPT_BENGALI,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( gujr, GUJR,
           "Gujarati",
           HB_SCRIPT_GUJARATI,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( guru, GURU,
           "Gurmukhi",
           HB_SCRIPT_GURMUKHI,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( knda, KNDA,
           "Kannada",
           HB_SCRIPT_KANNADA,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( limb, LIMB,
           "Limbu",
           HB_SCRIPT_LIMBU,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( mlym, MLYM,
           "Malayalam",
           HB_SCRIPT_MALAYALAM,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( orya, ORYA,
           "Oriya",
           HB_SCRIPT_ORIYA,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( sinh, SINH,
           "Sinhala",
           HB_SCRIPT_SINHALA,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( sund, SUND,
           "Sundanese",
           HB_SCRIPT_SUNDANESE,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( sylo, SYLO,
           "Syloti Nagri",
           HB_SCRIPT_SYLOTI_NAGRI,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( taml, TAML,
           "Tamil",
           HB_SCRIPT_TAMIL,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
   SCRIPT( tibt, TIBT,
           "Tibetan",
           HB_SCRIPT_TIBETAN,
-          'o', 0x0, 0x0 ) /* XXX */
+          "o" ) /* XXX */
 
 #endif /* AF_CONFIG_OPTION_INDIC */
 
@@ -141,7 +177,7 @@
   SCRIPT( hani, HANI,
           "CJKV ideographs",
           HB_SCRIPT_HAN,
-          0x7530, 0x56D7, 0x0 ) /* 田囗 */
+          "\xE7\x94\xB0 \xE5\x9B\x97" ) /* 田 囗 */
 
 #endif /* AF_CONFIG_OPTION_CJK */
 
diff --git a/src/autofit/afshaper.c b/src/autofit/afshaper.c
new file mode 100644
index 0000000..6ba9190
--- /dev/null
+++ b/src/autofit/afshaper.c
@@ -0,0 +1,676 @@
+/***************************************************************************/
+/*                                                                         */
+/*  afshaper.c                                                             */
+/*                                                                         */
+/*    HarfBuzz interface for accessing OpenType features (body).           */
+/*                                                                         */
+/*  Copyright 2013-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "afglobal.h"
+#include "aftypes.h"
+#include "afshaper.h"
+
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_afshaper
+
+
+  /*
+   * We use `sets' (in the HarfBuzz sense, which comes quite near to the
+   * usual mathematical meaning) to manage both lookups and glyph indices.
+   *
+   * 1. For each coverage, collect lookup IDs in a set.  Note that an
+   *    auto-hinter `coverage' is represented by one `feature', and a
+   *    feature consists of an arbitrary number of (font specific) `lookup's
+   *    that actually do the mapping job.  Please check the OpenType
+   *    specification for more details on features and lookups.
+   *
+   * 2. Create glyph ID sets from the corresponding lookup sets.
+   *
+   * 3. The glyph set corresponding to AF_COVERAGE_DEFAULT is computed
+   *    with all lookups specific to the OpenType script activated.  It
+   *    relies on the order of AF_DEFINE_STYLE_CLASS entries so that
+   *    special coverages (like `oldstyle figures') don't get overwritten.
+   *
+   */
+
+
+  /* load coverage tags */
+#undef  COVERAGE
+#define COVERAGE( name, NAME, description,             \
+                  tag1, tag2, tag3, tag4 )             \
+          static const hb_tag_t  name ## _coverage[] = \
+          {                                            \
+            HB_TAG( tag1, tag2, tag3, tag4 ),          \
+            HB_TAG_NONE                                \
+          };
+
+
+#include "afcover.h"
+
+
+  /* define mapping between coverage tags and AF_Coverage */
+#undef  COVERAGE
+#define COVERAGE( name, NAME, description, \
+                  tag1, tag2, tag3, tag4 ) \
+          name ## _coverage,
+
+
+  static const hb_tag_t*  coverages[] =
+  {
+#include "afcover.h"
+
+    NULL /* AF_COVERAGE_DEFAULT */
+  };
+
+
+  /* load HarfBuzz script tags */
+#undef  SCRIPT
+#define SCRIPT( s, S, d, h, ss )  h,
+
+
+  static const hb_script_t  scripts[] =
+  {
+#include "afscript.h"
+  };
+
+
+  FT_Error
+  af_shaper_get_coverage( AF_FaceGlobals  globals,
+                          AF_StyleClass   style_class,
+                          FT_UShort*      gstyles )
+  {
+    hb_face_t*  face;
+
+    hb_set_t*  gsub_lookups;  /* GSUB lookups for a given script */
+    hb_set_t*  gsub_glyphs;   /* glyphs covered by GSUB lookups  */
+    hb_set_t*  gpos_lookups;  /* GPOS lookups for a given script */
+    hb_set_t*  gpos_glyphs;   /* glyphs covered by GPOS lookups  */
+
+    hb_script_t      script;
+    const hb_tag_t*  coverage_tags;
+    hb_tag_t         script_tags[] = { HB_TAG_NONE,
+                                       HB_TAG_NONE,
+                                       HB_TAG_NONE,
+                                       HB_TAG_NONE };
+
+    hb_codepoint_t  idx;
+#ifdef FT_DEBUG_LEVEL_TRACE
+    int             count;
+#endif
+
+
+    if ( !globals || !style_class || !gstyles )
+      return FT_THROW( Invalid_Argument );
+
+    face = hb_font_get_face( globals->hb_font );
+
+    gsub_lookups = hb_set_create();
+    gsub_glyphs  = hb_set_create();
+    gpos_lookups = hb_set_create();
+    gpos_glyphs  = hb_set_create();
+
+    coverage_tags = coverages[style_class->coverage];
+    script        = scripts[style_class->script];
+
+    /* Convert a HarfBuzz script tag into the corresponding OpenType */
+    /* tag or tags -- some Indic scripts like Devanagari have an old */
+    /* and a new set of features.                                    */
+    hb_ot_tags_from_script( script,
+                            &script_tags[0],
+                            &script_tags[1] );
+
+    /* `hb_ot_tags_from_script' usually returns HB_OT_TAG_DEFAULT_SCRIPT */
+    /* as the second tag.  We change that to HB_TAG_NONE except for the  */
+    /* default script.                                                   */
+    if ( style_class->script == globals->module->default_script &&
+         style_class->coverage == AF_COVERAGE_DEFAULT           )
+    {
+      if ( script_tags[0] == HB_TAG_NONE )
+        script_tags[0] = HB_OT_TAG_DEFAULT_SCRIPT;
+      else
+      {
+        if ( script_tags[1] == HB_TAG_NONE )
+          script_tags[1] = HB_OT_TAG_DEFAULT_SCRIPT;
+        else if ( script_tags[1] != HB_OT_TAG_DEFAULT_SCRIPT )
+          script_tags[2] = HB_OT_TAG_DEFAULT_SCRIPT;
+      }
+    }
+    else
+    {
+      if ( script_tags[1] == HB_OT_TAG_DEFAULT_SCRIPT )
+        script_tags[1] = HB_TAG_NONE;
+    }
+
+    hb_ot_layout_collect_lookups( face,
+                                  HB_OT_TAG_GSUB,
+                                  script_tags,
+                                  NULL,
+                                  coverage_tags,
+                                  gsub_lookups );
+
+    if ( hb_set_is_empty( gsub_lookups ) )
+      goto Exit; /* nothing to do */
+
+    hb_ot_layout_collect_lookups( face,
+                                  HB_OT_TAG_GPOS,
+                                  script_tags,
+                                  NULL,
+                                  coverage_tags,
+                                  gpos_lookups );
+
+    FT_TRACE4(( "GSUB lookups (style `%s'):\n"
+                " ",
+                af_style_names[style_class->style] ));
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    count = 0;
+#endif
+
+    for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); )
+    {
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_TRACE4(( " %d", idx ));
+      count++;
+#endif
+
+      /* get output coverage of GSUB feature */
+      hb_ot_layout_lookup_collect_glyphs( face,
+                                          HB_OT_TAG_GSUB,
+                                          idx,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          gsub_glyphs );
+    }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    if ( !count )
+      FT_TRACE4(( " (none)" ));
+    FT_TRACE4(( "\n\n" ));
+#endif
+
+    FT_TRACE4(( "GPOS lookups (style `%s'):\n"
+                " ",
+                af_style_names[style_class->style] ));
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    count = 0;
+#endif
+
+    for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); )
+    {
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_TRACE4(( " %d", idx ));
+      count++;
+#endif
+
+      /* get input coverage of GPOS feature */
+      hb_ot_layout_lookup_collect_glyphs( face,
+                                          HB_OT_TAG_GPOS,
+                                          idx,
+                                          NULL,
+                                          gpos_glyphs,
+                                          NULL,
+                                          NULL );
+    }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    if ( !count )
+      FT_TRACE4(( " (none)" ));
+    FT_TRACE4(( "\n\n" ));
+#endif
+
+    /*
+     * We now check whether we can construct blue zones, using glyphs
+     * covered by the feature only.  In case there is not a single zone
+     * (this is, not a single character is covered), we skip this coverage.
+     *
+     */
+    if ( style_class->coverage != AF_COVERAGE_DEFAULT )
+    {
+      AF_Blue_Stringset         bss = style_class->blue_stringset;
+      const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
+
+      FT_Bool  found = 0;
+
+
+      for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
+      {
+        const char*  p = &af_blue_strings[bs->string];
+
+
+        while ( *p )
+        {
+          hb_codepoint_t  ch;
+
+
+          GET_UTF8_CHAR( ch, p );
+
+          for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups,
+                                                         &idx ); )
+          {
+            hb_codepoint_t  gidx = FT_Get_Char_Index( globals->face, ch );
+
+
+            if ( hb_ot_layout_lookup_would_substitute( face, idx,
+                                                       &gidx, 1, 1 ) )
+            {
+              found = 1;
+              break;
+            }
+          }
+        }
+      }
+
+      if ( !found )
+      {
+        FT_TRACE4(( "  no blue characters found; style skipped\n" ));
+        goto Exit;
+      }
+    }
+
+    /*
+     * Various OpenType features might use the same glyphs at different
+     * vertical positions; for example, superscript and subscript glyphs
+     * could be the same.  However, the auto-hinter is completely
+     * agnostic of OpenType features after the feature analysis has been
+     * completed: The engine then simply receives a glyph index and returns a
+     * hinted and usually rendered glyph.
+     *
+     * Consider the superscript feature of font `pala.ttf': Some of the
+     * glyphs are `real', this is, they have a zero vertical offset, but
+     * most of them are small caps glyphs shifted up to the superscript
+     * position (this is, the `sups' feature is present in both the GSUB and
+     * GPOS tables).  The code for blue zones computation actually uses a
+     * feature's y offset so that the `real' glyphs get correct hints.  But
+     * later on it is impossible to decide whether a glyph index belongs to,
+     * say, the small caps or superscript feature.
+     *
+     * For this reason, we don't assign a style to a glyph if the current
+     * feature covers the glyph in both the GSUB and the GPOS tables.  This
+     * is quite a broad condition, assuming that
+     *
+     *   (a) glyphs that get used in multiple features are present in a
+     *       feature without vertical shift,
+     *
+     * and
+     *
+     *   (b) a feature's GPOS data really moves the glyph vertically.
+     *
+     * Not fulfilling condition (a) makes a font larger; it would also
+     * reduce the number of glyphs that could be addressed directly without
+     * using OpenType features, so this assumption is rather strong.
+     *
+     * Condition (b) is much weaker, and there might be glyphs which get
+     * missed.  However, the OpenType features we are going to handle are
+     * primarily located in GSUB, and HarfBuzz doesn't provide an API to
+     * directly get the necessary information from the GPOS table.  A
+     * possible solution might be to directly parse the GPOS table to find
+     * out whether a glyph gets shifted vertically, but this is something I
+     * would like to avoid if not really necessary.
+     *
+     * Note that we don't follow this logic for the default coverage.
+     * Complex scripts like Devanagari have mandatory GPOS features to
+     * position many glyph elements, using mark-to-base or mark-to-ligature
+     * tables; the number of glyphs missed due to condition (b) would be far
+     * too large.
+     *
+     */
+    if ( style_class->coverage != AF_COVERAGE_DEFAULT )
+      hb_set_subtract( gsub_glyphs, gpos_glyphs );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    FT_TRACE4(( "  glyphs without GPOS data (`*' means already assigned)" ));
+    count = 0;
+#endif
+
+    for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); )
+    {
+#ifdef FT_DEBUG_LEVEL_TRACE
+      if ( !( count % 10 ) )
+        FT_TRACE4(( "\n"
+                    "   " ));
+
+      FT_TRACE4(( " %d", idx ));
+      count++;
+#endif
+
+      /* glyph indices returned by `hb_ot_layout_lookup_collect_glyphs' */
+      /* can be arbitrary: some fonts use fake indices for processing   */
+      /* internal to GSUB or GPOS, which is fully valid                 */
+      if ( idx >= (hb_codepoint_t)globals->glyph_count )
+        continue;
+
+      if ( gstyles[idx] == AF_STYLE_UNASSIGNED )
+        gstyles[idx] = (FT_UShort)style_class->style;
+#ifdef FT_DEBUG_LEVEL_TRACE
+      else
+        FT_TRACE4(( "*" ));
+#endif
+    }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    if ( !count )
+      FT_TRACE4(( "\n"
+                  "    (none)" ));
+    FT_TRACE4(( "\n\n" ));
+#endif
+
+  Exit:
+    hb_set_destroy( gsub_lookups );
+    hb_set_destroy( gsub_glyphs  );
+    hb_set_destroy( gpos_lookups );
+    hb_set_destroy( gpos_glyphs  );
+
+    return FT_Err_Ok;
+  }
+
+
+  /* construct HarfBuzz features */
+#undef  COVERAGE
+#define COVERAGE( name, NAME, description,                \
+                  tag1, tag2, tag3, tag4 )                \
+          static const hb_feature_t  name ## _feature[] = \
+          {                                               \
+            {                                             \
+              HB_TAG( tag1, tag2, tag3, tag4 ),           \
+              1, 0, (unsigned int)-1                      \
+            }                                             \
+          };
+
+
+#include "afcover.h"
+
+
+  /* define mapping between HarfBuzz features and AF_Coverage */
+#undef  COVERAGE
+#define COVERAGE( name, NAME, description, \
+                  tag1, tag2, tag3, tag4 ) \
+          name ## _feature,
+
+
+  static const hb_feature_t*  features[] =
+  {
+#include "afcover.h"
+
+    NULL /* AF_COVERAGE_DEFAULT */
+  };
+
+
+  void*
+  af_shaper_buf_create( FT_Face  face )
+  {
+    FT_UNUSED( face );
+
+    return (void*)hb_buffer_create();
+  }
+
+
+  void
+  af_shaper_buf_destroy( FT_Face  face,
+                         void*    buf )
+  {
+    FT_UNUSED( face );
+
+    hb_buffer_destroy( (hb_buffer_t*)buf );
+  }
+
+
+  const char*
+  af_shaper_get_cluster( const char*      p,
+                         AF_StyleMetrics  metrics,
+                         void*            buf_,
+                         unsigned int*    count )
+  {
+    AF_StyleClass        style_class;
+    const hb_feature_t*  feature;
+    FT_Int               upem;
+    const char*          q;
+    int                  len;
+
+    hb_buffer_t*    buf = (hb_buffer_t*)buf_;
+    hb_font_t*      font;
+    hb_codepoint_t  dummy;
+
+
+    upem        = (FT_Int)metrics->globals->face->units_per_EM;
+    style_class = metrics->style_class;
+    feature     = features[style_class->coverage];
+
+    font = metrics->globals->hb_font;
+
+    /* we shape at a size of units per EM; this means font units */
+    hb_font_set_scale( font, upem, upem );
+
+    while ( *p == ' ' )
+      p++;
+
+    /* count bytes up to next space (or end of buffer) */
+    q = p;
+    while ( !( *q == ' ' || *q == '\0' ) )
+      GET_UTF8_CHAR( dummy, q );
+    len = (int)( q - p );
+
+    /* feed character(s) to the HarfBuzz buffer */
+    hb_buffer_clear_contents( buf );
+    hb_buffer_add_utf8( buf, p, len, 0, len );
+
+    /* we let HarfBuzz guess the script and writing direction */
+    hb_buffer_guess_segment_properties( buf );
+
+    /* shape buffer, which means conversion from character codes to */
+    /* glyph indices, possibly applying a feature                   */
+    hb_shape( font, buf, feature, feature ? 1 : 0 );
+
+    if ( feature )
+    {
+      hb_buffer_t*  hb_buf = metrics->globals->hb_buf;
+
+      unsigned int      gcount;
+      hb_glyph_info_t*  ginfo;
+
+      unsigned int      hb_gcount;
+      hb_glyph_info_t*  hb_ginfo;
+
+
+      /* we have to check whether applying a feature does actually change */
+      /* glyph indices; otherwise the affected glyph or glyphs aren't     */
+      /* available at all in the feature                                  */
+
+      hb_buffer_clear_contents( hb_buf );
+      hb_buffer_add_utf8( hb_buf, p, len, 0, len );
+      hb_buffer_guess_segment_properties( hb_buf );
+      hb_shape( font, hb_buf, NULL, 0 );
+
+      ginfo    = hb_buffer_get_glyph_infos( buf, &gcount );
+      hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount );
+
+      if ( gcount == hb_gcount )
+      {
+        unsigned int  i;
+
+
+        for (i = 0; i < gcount; i++ )
+          if ( ginfo[i].codepoint != hb_ginfo[i].codepoint )
+            break;
+
+        if ( i == gcount )
+        {
+          /* both buffers have identical glyph indices */
+          hb_buffer_clear_contents( buf );
+        }
+      }
+    }
+
+    *count = hb_buffer_get_length( buf );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    if ( feature && *count > 1 )
+      FT_TRACE1(( "af_shaper_get_cluster:"
+                  " input character mapped to multiple glyphs\n" ));
+#endif
+
+    return q;
+  }
+
+
+  FT_ULong
+  af_shaper_get_elem( AF_StyleMetrics  metrics,
+                      void*            buf_,
+                      unsigned int     idx,
+                      FT_Long*         advance,
+                      FT_Long*         y_offset )
+  {
+    hb_buffer_t*          buf = (hb_buffer_t*)buf_;
+    hb_glyph_info_t*      ginfo;
+    hb_glyph_position_t*  gpos;
+    unsigned int          gcount;
+
+    FT_UNUSED( metrics );
+
+
+    ginfo = hb_buffer_get_glyph_infos( buf, &gcount );
+    gpos  = hb_buffer_get_glyph_positions( buf, &gcount );
+
+    if ( idx >= gcount )
+      return 0;
+
+    if ( advance )
+      *advance = gpos[idx].x_advance;
+    if ( y_offset )
+      *y_offset = gpos[idx].y_offset;
+
+    return ginfo[idx].codepoint;
+  }
+
+
+#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
+
+
+  FT_Error
+  af_shaper_get_coverage( AF_FaceGlobals  globals,
+                          AF_StyleClass   style_class,
+                          FT_UShort*      gstyles )
+  {
+    FT_UNUSED( globals );
+    FT_UNUSED( style_class );
+    FT_UNUSED( gstyles );
+
+    return FT_Err_Ok;
+  }
+
+
+  void*
+  af_shaper_buf_create( FT_Face  face )
+  {
+    FT_Error   error;
+    FT_Memory  memory = face->memory;
+    FT_ULong*  buf;
+
+
+    FT_MEM_ALLOC( buf, sizeof ( FT_ULong ) );
+
+    return (void*)buf;
+  }
+
+
+  void
+  af_shaper_buf_destroy( FT_Face  face,
+                         void*    buf )
+  {
+    FT_Memory  memory = face->memory;
+
+
+    FT_FREE( buf );
+  }
+
+
+  const char*
+  af_shaper_get_cluster( const char*      p,
+                         AF_StyleMetrics  metrics,
+                         void*            buf_,
+                         unsigned int*    count )
+  {
+    FT_Face    face      = metrics->globals->face;
+    FT_ULong   ch, dummy = 0;
+    FT_ULong*  buf       = (FT_ULong*)buf_;
+
+
+    while ( *p == ' ' )
+      p++;
+
+    GET_UTF8_CHAR( ch, p );
+
+    /* since we don't have an engine to handle clusters, */
+    /* we scan the characters but return zero            */
+    while ( !( *p == ' ' || *p == '\0' ) )
+      GET_UTF8_CHAR( dummy, p );
+
+    if ( dummy )
+    {
+      *buf   = 0;
+      *count = 0;
+    }
+    else
+    {
+      *buf   = FT_Get_Char_Index( face, ch );
+      *count = 1;
+    }
+
+    return p;
+  }
+
+
+  FT_ULong
+  af_shaper_get_elem( AF_StyleMetrics  metrics,
+                      void*            buf_,
+                      unsigned int     idx,
+                      FT_Long*         advance,
+                      FT_Long*         y_offset )
+  {
+    FT_Face   face        = metrics->globals->face;
+    FT_ULong  glyph_index = *(FT_ULong*)buf_;
+
+    FT_UNUSED( idx );
+
+
+    if ( advance )
+      FT_Get_Advance( face,
+                      glyph_index,
+                      FT_LOAD_NO_SCALE         |
+                      FT_LOAD_NO_HINTING       |
+                      FT_LOAD_IGNORE_TRANSFORM,
+                      advance );
+
+    if ( y_offset )
+      *y_offset = 0;
+
+    return glyph_index;
+  }
+
+
+#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
+
+
+/* END */
diff --git a/src/autofit/afshaper.h b/src/autofit/afshaper.h
new file mode 100644
index 0000000..db1b4e0
--- /dev/null
+++ b/src/autofit/afshaper.h
@@ -0,0 +1,71 @@
+/***************************************************************************/
+/*                                                                         */
+/*  afshaper.h                                                             */
+/*                                                                         */
+/*    HarfBuzz interface for accessing OpenType features (specification).  */
+/*                                                                         */
+/*  Copyright 2013-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AFSHAPER_H__
+#define __AFSHAPER_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
+
+#include <hb.h>
+#include <hb-ot.h>
+#include <hb-ft.h>
+
+#endif
+
+
+FT_BEGIN_HEADER
+
+  FT_Error
+  af_shaper_get_coverage( AF_FaceGlobals  globals,
+                          AF_StyleClass   style_class,
+                          FT_UShort*      gstyles );
+
+
+  void*
+  af_shaper_buf_create( FT_Face  face );
+
+  void
+  af_shaper_buf_destroy( FT_Face  face,
+                         void*    buf );
+
+  const char*
+  af_shaper_get_cluster( const char*      p,
+                         AF_StyleMetrics  metrics,
+                         void*            buf_,
+                         unsigned int*    count );
+
+  FT_ULong
+  af_shaper_get_elem( AF_StyleMetrics  metrics,
+                      void*            buf_,
+                      unsigned int     idx,
+                      FT_Long*         x_advance,
+                      FT_Long*         y_offset );
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* __AFSHAPER_H__ */
+
+
+/* END */
diff --git a/src/autofit/afstyles.h b/src/autofit/afstyles.h
index bfd5bb9..e214442 100644
--- a/src/autofit/afstyles.h
+++ b/src/autofit/afstyles.h
@@ -27,7 +27,9 @@
   /* coverage.                                                     */
   /*                                                               */
   /* Note that styles using `AF_COVERAGE_DEFAULT' should always    */
-  /* come after styles with other coverages.                       */
+  /* come after styles with other coverages.  Also note that       */
+  /* fallback scripts only use `AF_COVERAGE_DEFAULT' for its       */
+  /* style.                                                        */
   /*                                                               */
   /* Example:                                                      */
   /*                                                               */
@@ -90,6 +92,13 @@
 
   META_STYLE_LATIN( cyrl, CYRL, "Cyrillic" )
 
+  STYLE( deva_dflt, DEVA_DFLT,
+         "Devanagari default style",
+         AF_WRITING_SYSTEM_LATIN,
+         AF_SCRIPT_DEVA,
+         AF_BLUE_STRINGSET_DEVA,
+         AF_COVERAGE_DEFAULT )
+
   META_STYLE_LATIN( grek, GREK, "Greek" )
 
   STYLE( hebr_dflt, HEBR_DFLT,
@@ -98,13 +107,42 @@
          AF_SCRIPT_HEBR,
          AF_BLUE_STRINGSET_HEBR,
          AF_COVERAGE_DEFAULT )
+
+  STYLE( khmr_dflt, KHMR_DFLT,
+         "Khmer default style",
+         AF_WRITING_SYSTEM_LATIN,
+         AF_SCRIPT_KHMR,
+         AF_BLUE_STRINGSET_KHMR,
+         AF_COVERAGE_DEFAULT )
+
+  STYLE( khms_dflt, KHMS_DFLT,
+         "Khmer Symbols default style",
+         AF_WRITING_SYSTEM_LATIN,
+         AF_SCRIPT_KHMS,
+         AF_BLUE_STRINGSET_KHMS,
+         AF_COVERAGE_DEFAULT )
+
+  STYLE( lao_dflt, LAO_DFLT,
+         "Lao default style",
+         AF_WRITING_SYSTEM_LATIN,
+         AF_SCRIPT_LAO,
+         AF_BLUE_STRINGSET_LAO,
+         AF_COVERAGE_DEFAULT )
+
   META_STYLE_LATIN( latn, LATN, "Latin" )
 
-  STYLE( deva_dflt, DEVA_DFLT,
-         "Devanagari default style",
+  STYLE( latb_dflt, LATB_DFLT,
+         "Latin subscript fallback default style",
          AF_WRITING_SYSTEM_LATIN,
-         AF_SCRIPT_DEVA,
-         AF_BLUE_STRINGSET_DEVA,
+         AF_SCRIPT_LATB,
+         AF_BLUE_STRINGSET_LATB,
+         AF_COVERAGE_DEFAULT )
+
+  STYLE( latp_dflt, LATP_DFLT,
+         "Latin superscript fallback default style",
+         AF_WRITING_SYSTEM_LATIN,
+         AF_SCRIPT_LATP,
+         AF_BLUE_STRINGSET_LATP,
          AF_COVERAGE_DEFAULT )
 
 #ifdef FT_OPTION_AUTOFIT2
@@ -116,6 +154,13 @@
          AF_COVERAGE_DEFAULT )
 #endif
 
+  STYLE( mymr_dflt, MYMR_DFLT,
+         "Myanmar default style",
+         AF_WRITING_SYSTEM_LATIN,
+         AF_SCRIPT_MYMR,
+         AF_BLUE_STRINGSET_MYMR,
+         AF_COVERAGE_DEFAULT )
+
   STYLE( none_dflt, NONE_DFLT,
          "no style",
          AF_WRITING_SYSTEM_DUMMY,
diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h
index 78e3fd7..b483619 100644
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -41,6 +41,10 @@
 
 #include "afblue.h"
 
+#ifdef FT_DEBUG_AUTOFIT
+#include FT_CONFIG_STANDARD_LIBRARY_H
+#endif
+
 
 FT_BEGIN_HEADER
 
@@ -54,8 +58,6 @@
 
 #ifdef FT_DEBUG_AUTOFIT
 
-#include FT_CONFIG_STANDARD_LIBRARY_H
-
 extern int    _af_debug_disable_horz_hints;
 extern int    _af_debug_disable_vert_hints;
 extern int    _af_debug_disable_blue_hints;
@@ -209,13 +211,19 @@
   typedef void
   (*AF_WritingSystem_DoneMetricsFunc)( AF_StyleMetrics  metrics );
 
+  typedef void
+  (*AF_WritingSystem_GetStdWidthsFunc)( AF_StyleMetrics  metrics,
+                                        FT_Pos*          stdHW,
+                                        FT_Pos*          stdVW );
+
 
   typedef FT_Error
   (*AF_WritingSystem_InitHintsFunc)( AF_GlyphHints    hints,
                                      AF_StyleMetrics  metrics );
 
   typedef void
-  (*AF_WritingSystem_ApplyHintsFunc)( AF_GlyphHints    hints,
+  (*AF_WritingSystem_ApplyHintsFunc)( FT_UInt          glyph_index,
+                                      AF_GlyphHints    hints,
                                       FT_Outline*      outline,
                                       AF_StyleMetrics  metrics );
 
@@ -273,6 +281,7 @@
     AF_WritingSystem_InitMetricsFunc   style_metrics_init;
     AF_WritingSystem_ScaleMetricsFunc  style_metrics_scale;
     AF_WritingSystem_DoneMetricsFunc   style_metrics_done;
+    AF_WritingSystem_GetStdWidthsFunc  style_metrics_getstdw;
 
     AF_WritingSystem_InitHintsFunc     style_hints_init;
     AF_WritingSystem_ApplyHintsFunc    style_hints_apply;
@@ -291,15 +300,16 @@
   /*************************************************************************/
 
   /*
-   *  Each script is associated with a set of Unicode ranges that gets used
-   *  to test whether the font face supports the script.
+   *  Each script is associated with two sets of Unicode ranges to test
+   *  whether the font face supports the script, and which non-base
+   *  characters the script contains.
    *
    *  We use four-letter script tags from the OpenType specification,
    *  extended by `NONE', which indicates `no script'.
    */
 
 #undef  SCRIPT
-#define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) \
+#define SCRIPT( s, S, d, h, ss ) \
           AF_SCRIPT_ ## S,
 
   /* The list of known scripts. */
@@ -329,11 +339,11 @@
   {
     AF_Script  script;
 
-    AF_Script_UniRange  script_uni_ranges; /* last must be { 0, 0 }        */
+    /* last element in the ranges must be { 0, 0 } */
+    AF_Script_UniRange  script_uni_ranges;
+    AF_Script_UniRange  script_uni_nonbase_ranges;
 
-    FT_UInt32  standard_char1;             /* for default width and height */
-    FT_UInt32  standard_char2;             /* ditto                        */
-    FT_UInt32  standard_char3;             /* ditto                        */
+    const char*  standard_charstring;      /* for default width and height */
 
   } AF_ScriptClassRec;
 
@@ -483,6 +493,7 @@
           m_init,                                        \
           m_scale,                                       \
           m_done,                                        \
+          m_stdw,                                        \
           h_init,                                        \
           h_apply )                                      \
   FT_CALLBACK_TABLE_DEF                                  \
@@ -495,6 +506,7 @@
     m_init,                                              \
     m_scale,                                             \
     m_done,                                              \
+    m_stdw,                                              \
                                                          \
     h_init,                                              \
     h_apply                                              \
@@ -509,17 +521,15 @@
           script_class,                   \
           script,                         \
           ranges,                         \
-          std_char1,                      \
-          std_char2,                      \
-          std_char3 )                     \
+          nonbase_ranges,                 \
+          std_charstring )                \
   FT_CALLBACK_TABLE_DEF                   \
   const AF_ScriptClassRec  script_class = \
   {                                       \
     script,                               \
     ranges,                               \
-    std_char1,                            \
-    std_char2,                            \
-    std_char3                             \
+    nonbase_ranges,                       \
+    std_charstring,                       \
   };
 
 
@@ -562,16 +572,17 @@
   FT_LOCAL_DEF( void )                                                    \
   FT_Init_Class_ ## writing_system_class( AF_WritingSystemClassRec*  ac ) \
   {                                                                       \
-    ac->writing_system      = system;                                     \
+    ac->writing_system        = system;                                   \
                                                                           \
-    ac->style_metrics_size  = m_size;                                     \
+    ac->style_metrics_size    = m_size;                                   \
                                                                           \
-    ac->style_metrics_init  = m_init;                                     \
-    ac->style_metrics_scale = m_scale;                                    \
-    ac->style_metrics_done  = m_done;                                     \
+    ac->style_metrics_init    = m_init;                                   \
+    ac->style_metrics_scale   = m_scale;                                  \
+    ac->style_metrics_done    = m_done;                                   \
+    ac->style_metrics_getstdw = m_stdw;                                   \
                                                                           \
-    ac->style_hints_init    = h_init;                                     \
-    ac->style_hints_apply   = h_apply;                                    \
+    ac->style_hints_init      = h_init;                                   \
+    ac->style_hints_apply     = h_apply;                                  \
   }
 
 
@@ -583,17 +594,15 @@
           script_class,                                    \
           script_,                                         \
           ranges,                                          \
-          std_char1,                                       \
-          std_char2,                                       \
-          std_char3 )                                      \
+          nonbase_ranges,                                  \
+          std_charstring )                                 \
   FT_LOCAL_DEF( void )                                     \
   FT_Init_Class_ ## script_class( AF_ScriptClassRec*  ac ) \
   {                                                        \
-    ac->script            = script_;                       \
-    ac->script_uni_ranges = ranges;                        \
-    ac->standard_char1    = std_char1;                     \
-    ac->standard_char2    = std_char2;                     \
-    ac->standard_char3    = std_char3;                     \
+    ac->script                    = script_;               \
+    ac->script_uni_ranges         = ranges;                \
+    ac->script_uni_nonbase_ranges = nonbase_ranges;        \
+    ac->standard_charstring       = std_charstring;        \
   }
 
 
diff --git a/src/autofit/afwarp.c b/src/autofit/afwarp.c
index 59af4f0..ae92db1 100644
--- a/src/autofit/afwarp.c
+++ b/src/autofit/afwarp.c
@@ -193,7 +193,7 @@
 
     warper->best_scale   = org_scale;
     warper->best_delta   = org_delta;
-    warper->best_score   = INT_MIN;
+    warper->best_score   = FT_INT_MIN;
     warper->best_distort = 0;
 
     axis         = &hints->axis[dim];
diff --git a/src/autofit/afwarp.h b/src/autofit/afwarp.h
index 5a6208a..6069b6b 100644
--- a/src/autofit/afwarp.h
+++ b/src/autofit/afwarp.h
@@ -25,7 +25,7 @@
 
 #define AF_WARPER_SCALE
 
-#define AF_WARPER_FLOOR( x )  ( (x) & ~TYPEOF( x )63 )
+#define AF_WARPER_FLOOR( x )  ( (x) & ~FT_TYPEOF( x )63 )
 #define AF_WARPER_CEIL( x )   AF_WARPER_FLOOR( (x) + 63 )
 
 
diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c
index b6ed4a0..a971a24 100644
--- a/src/autofit/autofit.c
+++ b/src/autofit/autofit.c
@@ -34,7 +34,7 @@
 #include "afcjk.c"
 #include "afindic.c"
 
-#include "hbshim.c"
+#include "afshaper.c"
 
 #include "afloader.c"
 #include "afmodule.c"
diff --git a/src/base/basepic.h b/src/base/basepic.h
index 51ecf9e..c5d7cbf 100644
--- a/src/base/basepic.h
+++ b/src/base/basepic.h
@@ -20,10 +20,9 @@
 #define __BASEPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
+
 #ifndef FT_CONFIG_OPTION_PIC
 
 #define FT_OUTLINE_GLYPH_CLASS_GET  &ft_outline_glyph_class
@@ -43,6 +42,8 @@
 #endif
 
 
+FT_BEGIN_HEADER
+
   typedef struct  BasePIC_
   {
     FT_Module_Class**  default_module_classes;
@@ -78,12 +79,12 @@
   FT_Error
   ft_base_pic_init( FT_Library  library );
 
+FT_END_HEADER
+
 #endif /* FT_CONFIG_OPTION_PIC */
 
   /* */
 
-FT_END_HEADER
-
 #endif /* __BASEPIC_H__ */
 
 
diff --git a/src/base/ftbase.h b/src/base/ftbase.h
index cb57f96..e37fefa 100644
--- a/src/base/ftbase.h
+++ b/src/base/ftbase.h
@@ -27,6 +27,11 @@
 FT_BEGIN_HEADER
 
 
+  /* MacOS resource fork cannot exceed 16MB at least for Carbon code; */
+  /* see https://support.microsoft.com/en-us/kb/130437                */
+#define FT_MAC_RFORK_MAX_LEN  0x00FFFFFFUL
+
+
   /* Assume the stream is sfnt-wrapped PS Type1 or sfnt-wrapped CID-keyed */
   /* font, and try to load a face specified by the face_index.            */
   FT_LOCAL( FT_Error )
diff --git a/src/base/ftbdf.c b/src/base/ftbdf.c
new file mode 100644
index 0000000..aa72ddc
--- /dev/null
+++ b/src/base/ftbdf.c
@@ -0,0 +1,91 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftbdf.c                                                                */
+/*                                                                         */
+/*    FreeType API for accessing BDF-specific strings (body).              */
+/*                                                                         */
+/*  Copyright 2002-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_BDF_H
+
+
+  /* documentation is in ftbdf.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_BDF_Charset_ID( FT_Face       face,
+                         const char*  *acharset_encoding,
+                         const char*  *acharset_registry )
+  {
+    FT_Error     error;
+    const char*  encoding = NULL;
+    const char*  registry = NULL;
+
+    FT_Service_BDF  service;
+
+
+    if ( !face )
+      return FT_THROW( Invalid_Face_Handle );
+
+    FT_FACE_FIND_SERVICE( face, service, BDF );
+
+    if ( service && service->get_charset_id )
+      error = service->get_charset_id( face, &encoding, &registry );
+    else
+      error = FT_THROW( Invalid_Argument );
+
+    if ( acharset_encoding )
+      *acharset_encoding = encoding;
+
+    if ( acharset_registry )
+      *acharset_registry = registry;
+
+    return error;
+  }
+
+
+  /* documentation is in ftbdf.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_BDF_Property( FT_Face           face,
+                       const char*       prop_name,
+                       BDF_PropertyRec  *aproperty )
+  {
+    FT_Error  error;
+
+    FT_Service_BDF  service;
+
+
+    if ( !face )
+      return FT_THROW( Invalid_Face_Handle );
+
+    if ( !aproperty )
+      return FT_THROW( Invalid_Argument );
+
+    aproperty->type = BDF_PROPERTY_TYPE_NONE;
+
+    FT_FACE_FIND_SERVICE( face, service, BDF );
+
+    if ( service && service->get_property )
+      error = service->get_property( face, prop_name, aproperty );
+    else
+      error = FT_THROW( Invalid_Argument );
+
+    return error;
+  }
+
+
+/* END */
diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c
index dca0e1d..619a08b 100644
--- a/src/base/ftcalc.c
+++ b/src/base/ftcalc.c
@@ -86,8 +86,7 @@
   FT_EXPORT_DEF( FT_Fixed )
   FT_RoundFix( FT_Fixed  a )
   {
-    return a >= 0 ?   ( a + 0x8000L ) & ~0xFFFFL
-                  : -((-a + 0x8000L ) & ~0xFFFFL );
+    return ( a + 0x8000L - ( a < 0 ) ) & ~0xFFFFL;
   }
 
 
@@ -96,8 +95,7 @@
   FT_EXPORT_DEF( FT_Fixed )
   FT_CeilFix( FT_Fixed  a )
   {
-    return a >= 0 ?   ( a + 0xFFFFL ) & ~0xFFFFL
-                  : -((-a + 0xFFFFL ) & ~0xFFFFL );
+    return ( a + 0xFFFFL ) & ~0xFFFFL;
   }
 
 
@@ -106,8 +104,7 @@
   FT_EXPORT_DEF( FT_Fixed )
   FT_FloorFix( FT_Fixed  a )
   {
-    return a >= 0 ?   a & ~0xFFFFL
-                  : -((-a) & ~0xFFFFL );
+    return a & ~0xFFFFL;
   }
 
 #ifndef FT_MSB
@@ -240,22 +237,10 @@
 
 #else
 
-    FT_Int     s = 1;
-    FT_UInt64  a, b, c;
-    FT_Long    c_;
+    FT_Int64  ab = (FT_Int64)a_ * (FT_Int64)b_;
 
-
-    FT_MOVE_SIGN( a_, s );
-    FT_MOVE_SIGN( b_, s );
-
-    a = (FT_UInt64)a_;
-    b = (FT_UInt64)b_;
-
-    c = ( a * b + 0x8000UL ) >> 16;
-
-    c_ = (FT_Long)c;
-
-    return s < 0 ? -c_ : c_;
+    /* this requires arithmetic right shift of signed numbers */
+    return (FT_Long)( ( ab + 0x8000L - ( ab < 0 ) ) >> 16 );
 
 #endif /* FT_MULFIX_ASSEMBLER */
   }
@@ -437,9 +422,6 @@
 
     /* XXX: this function does not allow 64-bit arguments */
 
-    if ( a_ == 0 || b_ == c_ )
-      return a_;
-
     FT_MOVE_SIGN( a_, s );
     FT_MOVE_SIGN( b_, s );
     FT_MOVE_SIGN( c_, s );
@@ -488,9 +470,6 @@
 
     /* XXX: this function does not allow 64-bit arguments */
 
-    if ( a_ == 0 || b_ == c_ )
-      return a_;
-
     FT_MOVE_SIGN( a_, s );
     FT_MOVE_SIGN( b_, s );
     FT_MOVE_SIGN( c_, s );
@@ -546,9 +525,6 @@
     FT_UInt32  a, b;
 
 
-    if ( a_ == 0 || b_ == 0x10000L )
-      return a_;
-
     /*
      *  This is a clever way of converting a signed number `a' into its
      *  absolute value (stored back into `a') and its sign.  The sign is
@@ -599,9 +575,6 @@
 
     /* XXX: this function does not allow 64-bit arguments */
 
-    if ( a_ == 0 || b_ == 0x10000L )
-      return a_;
-
     FT_MOVE_SIGN( a_, s );
     FT_MOVE_SIGN( b_, s );
 
@@ -785,6 +758,102 @@
   }
 
 
+  /* documentation is in ftcalc.h */
+
+  FT_BASE_DEF( FT_UInt32 )
+  FT_Vector_NormLen( FT_Vector*  vector )
+  {
+    FT_Int32   x_ = vector->x;
+    FT_Int32   y_ = vector->y;
+    FT_Int32   b, z;
+    FT_UInt32  x, y, u, v, l;
+    FT_Int     sx = 1, sy = 1, shift;
+
+
+    FT_MOVE_SIGN( x_, sx );
+    FT_MOVE_SIGN( y_, sy );
+
+    x = (FT_UInt32)x_;
+    y = (FT_UInt32)y_;
+
+    /* trivial cases */
+    if ( x == 0 )
+    {
+      if ( y > 0 )
+        vector->y = sy * 0x10000;
+      return y;
+    }
+    else if ( y == 0 )
+    {
+      if ( x > 0 )
+        vector->x = sx * 0x10000;
+      return x;
+    }
+
+    /* Estimate length and prenormalize by shifting so that */
+    /* the new approximate length is between 2/3 and 4/3.   */
+    /* The magic constant 0xAAAAAAAAUL (2/3 of 2^32) helps  */
+    /* achieve this in 16.16 fixed-point representation.    */
+    l = x > y ? x + ( y >> 1 )
+              : y + ( x >> 1 );
+
+    shift  = 31 - FT_MSB( l );
+    shift -= 15 + ( l >= ( 0xAAAAAAAAUL >> shift ) );
+
+    if ( shift > 0 )
+    {
+      x <<= shift;
+      y <<= shift;
+
+      /* re-estimate length for tiny vectors */
+      l = x > y ? x + ( y >> 1 )
+                : y + ( x >> 1 );
+    }
+    else
+    {
+      x >>= -shift;
+      y >>= -shift;
+      l >>= -shift;
+    }
+
+    /* lower linear approximation for reciprocal length minus one */
+    b = 0x10000 - (FT_Int32)l;
+
+    x_ = (FT_Int32)x;
+    y_ = (FT_Int32)y;
+
+    /* Newton's iterations */
+    do
+    {
+      u = (FT_UInt32)( x_ + ( x_ * b >> 16 ) );
+      v = (FT_UInt32)( y_ + ( y_ * b >> 16 ) );
+
+      /* Normalized squared length in the parentheses approaches 2^32. */
+      /* On two's complement systems, converting to signed gives the   */
+      /* difference with 2^32 even if the expression wraps around.     */
+      z = -(FT_Int32)( u * u + v * v ) / 0x200;
+      z = z * ( ( 0x10000 + b ) >> 8 ) / 0x10000;
+
+      b += z;
+
+    } while ( z > 0 );
+
+    vector->x = sx < 0 ? -(FT_Pos)u : (FT_Pos)u;
+    vector->y = sy < 0 ? -(FT_Pos)v : (FT_Pos)v;
+
+    /* Conversion to signed helps to recover from likely wrap around */
+    /* in calculating the prenormalized length, because it gives the */
+    /* correct difference with 2^32 on two's complement systems.     */
+    l = (FT_UInt32)( 0x10000 + (FT_Int32)( u * x + v * y ) / 0x10000 );
+    if ( shift > 0 )
+      l = ( l + ( 1 << ( shift - 1 ) ) ) >> shift;
+    else
+      l <<= -shift;
+
+    return l;
+  }
+
+
 #if 0
 
   /* documentation is in ftcalc.h */
@@ -832,52 +901,34 @@
                          FT_Pos  out_x,
                          FT_Pos  out_y )
   {
-    FT_Long  result; /* avoid overflow on 16-bit system */
-
-
-    /* deal with the trivial cases quickly */
-    if ( in_y == 0 )
-    {
-      if ( in_x >= 0 )
-        result = out_y;
-      else
-        result = -out_y;
-    }
-    else if ( in_x == 0 )
-    {
-      if ( in_y >= 0 )
-        result = -out_x;
-      else
-        result = out_x;
-    }
-    else if ( out_y == 0 )
-    {
-      if ( out_x >= 0 )
-        result = in_y;
-      else
-        result = -in_y;
-    }
-    else if ( out_x == 0 )
-    {
-      if ( out_y >= 0 )
-        result = -in_x;
-      else
-        result =  in_x;
-    }
-    else /* general case */
-    {
 #ifdef FT_LONG64
 
-      FT_Int64  delta = (FT_Int64)in_x * out_y - (FT_Int64)in_y * out_x;
+    FT_Int64  delta = (FT_Int64)in_x * out_y - (FT_Int64)in_y * out_x;
 
 
-      if ( delta == 0 )
-        result = 0;
-      else
-        result = 1 - 2 * ( delta < 0 );
+    return ( delta > 0 ) - ( delta < 0 );
 
 #else
 
+    FT_Int  result;
+
+
+    if ( (FT_ULong)FT_ABS( in_x ) + (FT_ULong)FT_ABS( out_y ) <= 131071UL &&
+         (FT_ULong)FT_ABS( in_y ) + (FT_ULong)FT_ABS( out_x ) <= 131071UL )
+    {
+      FT_Long  z1 = in_x * out_y;
+      FT_Long  z2 = in_y * out_x;
+
+
+      if ( z1 > z2 )
+        result = +1;
+      else if ( z1 < z2 )
+        result = -1;
+      else
+        result = 0;
+    }
+    else /* products might overflow 32 bits */
+    {
       FT_Int64  z1, z2;
 
 
@@ -895,12 +946,12 @@
         result = -1;
       else
         result = 0;
-
-#endif
     }
 
     /* XXX: only the sign of return value, +1/0/-1 must be used */
-    return (FT_Int)result;
+    return result;
+
+#endif
   }
 
 
diff --git a/src/base/ftcid.c b/src/base/ftcid.c
new file mode 100644
index 0000000..0734881
--- /dev/null
+++ b/src/base/ftcid.c
@@ -0,0 +1,118 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcid.c                                                                */
+/*                                                                         */
+/*    FreeType API for accessing CID font information.                     */
+/*                                                                         */
+/*  Copyright 2007-2015 by                                                 */
+/*  Derek Clegg and Michael Toftdal.                                       */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CID_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_CID_H
+
+
+  /* documentation is in ftcid.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_CID_Registry_Ordering_Supplement( FT_Face       face,
+                                           const char*  *registry,
+                                           const char*  *ordering,
+                                           FT_Int       *supplement)
+  {
+    FT_Error     error;
+    const char*  r = NULL;
+    const char*  o = NULL;
+    FT_Int       s = 0;
+
+
+    error = FT_ERR( Invalid_Argument );
+
+    if ( face )
+    {
+      FT_Service_CID  service;
+
+
+      FT_FACE_FIND_SERVICE( face, service, CID );
+
+      if ( service && service->get_ros )
+        error = service->get_ros( face, &r, &o, &s );
+    }
+
+    if ( registry )
+      *registry = r;
+
+    if ( ordering )
+      *ordering = o;
+
+    if ( supplement )
+      *supplement = s;
+
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_CID_Is_Internally_CID_Keyed( FT_Face   face,
+                                      FT_Bool  *is_cid )
+  {
+    FT_Error  error = FT_ERR( Invalid_Argument );
+    FT_Bool   ic = 0;
+
+
+    if ( face )
+    {
+      FT_Service_CID  service;
+
+
+      FT_FACE_FIND_SERVICE( face, service, CID );
+
+      if ( service && service->get_is_cid )
+        error = service->get_is_cid( face, &ic);
+    }
+
+    if ( is_cid )
+      *is_cid = ic;
+
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_CID_From_Glyph_Index( FT_Face   face,
+                               FT_UInt   glyph_index,
+                               FT_UInt  *cid )
+  {
+    FT_Error  error = FT_ERR( Invalid_Argument );
+    FT_UInt   c = 0;
+
+
+    if ( face )
+    {
+      FT_Service_CID  service;
+
+
+      FT_FACE_FIND_SERVICE( face, service, CID );
+
+      if ( service && service->get_cid_from_glyph_index )
+        error = service->get_cid_from_glyph_index( face, glyph_index, &c);
+    }
+
+    if ( cid )
+      *cid = c;
+
+    return error;
+  }
+
+
+/* END */
diff --git a/src/base/ftdbgmem.c b/src/base/ftdbgmem.c
index 6f20313..02eeb01 100644
--- a/src/base/ftdbgmem.c
+++ b/src/base/ftdbgmem.c
@@ -462,7 +462,7 @@
               (FT_UInt32)( 5 * _ft_debug_lineno );
     pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
 
-    for ( ;; )
+    for (;;)
     {
       node = *pnode;
       if ( node == NULL )
diff --git a/src/base/ftdebug.c b/src/base/ftdebug.c
index 2cdb7c2..03e18a8 100644
--- a/src/base/ftdebug.c
+++ b/src/base/ftdebug.c
@@ -152,8 +152,8 @@
   /* the memory and stream components which are set to 7 and 5,            */
   /* respectively.                                                         */
   /*                                                                       */
-  /* See the file <include/internal/fttrace.h> for details of the          */
-  /* available toggle names.                                               */
+  /* See the file `include/freetype/internal/fttrace.h' for details of     */
+  /* the available toggle names.                                           */
   /*                                                                       */
   /* The level must be between 0 and 7; 0 means quiet (except for serious  */
   /* runtime errors), and 7 means _very_ verbose.                          */
diff --git a/src/base/ftglyph.c b/src/base/ftglyph.c
index cb7fc37..2778743 100644
--- a/src/base/ftglyph.c
+++ b/src/base/ftglyph.c
@@ -125,10 +125,10 @@
     FT_BitmapGlyph  glyph = (FT_BitmapGlyph)bitmap_glyph;
 
 
-    cbox->xMin = glyph->left << 6;
-    cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width << 6 );
-    cbox->yMax = glyph->top << 6;
-    cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows << 6 );
+    cbox->xMin = glyph->left * 64;
+    cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 );
+    cbox->yMax = glyph->top * 64;
+    cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 );
   }
 
 
@@ -403,9 +403,9 @@
     if ( error )
       goto Exit;
 
-    /* copy advance while converting it to 16.16 format */
-    glyph->advance.x = slot->advance.x << 10;
-    glyph->advance.y = slot->advance.y << 10;
+    /* copy advance while converting 26.6 to 16.16 format */
+    glyph->advance.x = slot->advance.x * 1024;
+    glyph->advance.y = slot->advance.y * 1024;
 
     /* now import the image from the glyph slot */
     error = clazz->glyph_init( glyph, slot );
diff --git a/src/base/ftgxval.c b/src/base/ftgxval.c
new file mode 100644
index 0000000..58868f2
--- /dev/null
+++ b/src/base/ftgxval.c
@@ -0,0 +1,142 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgxval.c                                                              */
+/*                                                                         */
+/*    FreeType API for validating TrueTyepGX/AAT tables (body).            */
+/*                                                                         */
+/*  Copyright 2004-2015 by                                                 */
+/*  Masatake YAMATO, Redhat K.K,                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+/***************************************************************************/
+/*                                                                         */
+/* gxvalid is derived from both gxlayout module and otvalid module.        */
+/* Development of gxlayout is supported by the Information-technology      */
+/* Promotion Agency(IPA), Japan.                                           */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_GX_VALIDATE_H
+
+
+  /* documentation is in ftgxval.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_TrueTypeGX_Validate( FT_Face   face,
+                          FT_UInt   validation_flags,
+                          FT_Bytes  tables[FT_VALIDATE_GX_LENGTH],
+                          FT_UInt   table_length )
+  {
+    FT_Service_GXvalidate  service;
+    FT_Error               error;
+
+
+    if ( !face )
+    {
+      error = FT_THROW( Invalid_Face_Handle );
+      goto Exit;
+    }
+
+    if ( !tables )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    FT_FACE_FIND_GLOBAL_SERVICE( face, service, GX_VALIDATE );
+
+    if ( service )
+      error = service->validate( face,
+                                 validation_flags,
+                                 tables,
+                                 table_length );
+    else
+      error = FT_THROW( Unimplemented_Feature );
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_TrueTypeGX_Free( FT_Face   face,
+                      FT_Bytes  table )
+  {
+    FT_Memory  memory;
+
+
+    if ( !face )
+      return;
+
+    memory = FT_FACE_MEMORY( face );
+
+    FT_FREE( table );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_ClassicKern_Validate( FT_Face    face,
+                           FT_UInt    validation_flags,
+                           FT_Bytes  *ckern_table )
+  {
+    FT_Service_CKERNvalidate  service;
+    FT_Error                  error;
+
+
+    if ( !face )
+    {
+      error = FT_THROW( Invalid_Face_Handle );
+      goto Exit;
+    }
+
+    if ( !ckern_table )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    FT_FACE_FIND_GLOBAL_SERVICE( face, service, CLASSICKERN_VALIDATE );
+
+    if ( service )
+      error = service->validate( face,
+                                 validation_flags,
+                                 ckern_table );
+    else
+      error = FT_THROW( Unimplemented_Feature );
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_ClassicKern_Free( FT_Face   face,
+                       FT_Bytes  table )
+  {
+    FT_Memory  memory;
+
+
+    if ( !face )
+      return;
+
+    memory = FT_FACE_MEMORY( face );
+
+
+    FT_FREE( table );
+  }
+
+
+/* END */
diff --git a/src/base/ftinit.c b/src/base/ftinit.c
index cc95e6a..b65a91d 100644
--- a/src/base/ftinit.c
+++ b/src/base/ftinit.c
@@ -23,8 +23,8 @@
   /*  FT_Add_Default_Modules():                                            */
   /*     This function is used to add the set of default modules to a      */
   /*     fresh new library object.  The set is taken from the header file  */
-  /*     `config/ftmodule.h'.  See the document `FreeType 2.0 Build        */
-  /*     System' for more information.                                     */
+  /*     `freetype/config/ftmodule.h'.  See the document `FreeType 2.0     */
+  /*     Build System' for more information.                               */
   /*                                                                       */
   /*  FT_Init_FreeType():                                                  */
   /*     This function creates a system object for the current platform,   */
diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c
index ff6f7e9..5ee7e0a 100644
--- a/src/base/ftlcdfil.c
+++ b/src/base/ftlcdfil.c
@@ -305,12 +305,10 @@
   FT_Library_SetLcdFilter( FT_Library    library,
                            FT_LcdFilter  filter )
   {
+    static const FT_Byte  default_filter[5] =
+                            { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
     static const FT_Byte  light_filter[5] =
                             { 0x00, 0x55, 0x56, 0x55, 0x00 };
-    /* the values here sum up to a value larger than 256, */
-    /* providing a cheap gamma correction                 */
-    static const FT_Byte  default_filter[5] =
-                            { 0x10, 0x40, 0x70, 0x40, 0x10 };
 
 
     if ( !library )
@@ -354,6 +352,7 @@
 #ifdef USE_LEGACY
 
     case FT_LCD_FILTER_LEGACY:
+    case FT_LCD_FILTER_LEGACY1:
       library->lcd_filter_func = _ft_lcd_filter_legacy;
       library->lcd_extra       = 0;
       break;
diff --git a/src/base/ftmac.c b/src/base/ftmac.c
new file mode 100644
index 0000000..114bbb6
--- /dev/null
+++ b/src/base/ftmac.c
@@ -0,0 +1,1080 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftmac.c                                                                */
+/*                                                                         */
+/*    Mac FOND support.  Written by just@letterror.com.                    */
+/*  Heavily modified by mpsuzuki, George Williams, and Sean McBride.       */
+/*                                                                         */
+/*  This file is for Mac OS X only; see builds/mac/ftoldmac.c for          */
+/*  classic platforms built by MPW.                                        */
+/*                                                                         */
+/*  Copyright 1996-2015 by                                                 */
+/*  Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*
+    Notes
+
+    Mac suitcase files can (and often do!) contain multiple fonts.  To
+    support this I use the face_index argument of FT_(Open|New)_Face()
+    functions, and pretend the suitcase file is a collection.
+
+    Warning: fbit and NFNT bitmap resources are not supported yet.  In old
+    sfnt fonts, bitmap glyph data for each size is stored in each `NFNT'
+    resources instead of the `bdat' table in the sfnt resource.  Therefore,
+    face->num_fixed_sizes is set to 0, because bitmap data in `NFNT'
+    resource is unavailable at present.
+
+    The Mac FOND support works roughly like this:
+
+    - Check whether the offered stream points to a Mac suitcase file.  This
+      is done by checking the file type: it has to be 'FFIL' or 'tfil'.  The
+      stream that gets passed to our init_face() routine is a stdio stream,
+      which isn't usable for us, since the FOND resources live in the
+      resource fork.  So we just grab the stream->pathname field.
+
+    - Read the FOND resource into memory, then check whether there is a
+      TrueType font and/or(!) a Type 1 font available.
+
+    - If there is a Type 1 font available (as a separate `LWFN' file), read
+      its data into memory, massage it slightly so it becomes PFB data, wrap
+      it into a memory stream, load the Type 1 driver and delegate the rest
+      of the work to it by calling FT_Open_Face().  (XXX TODO: after this
+      has been done, the kerning data from the FOND resource should be
+      appended to the face: On the Mac there are usually no AFM files
+      available.  However, this is tricky since we need to map Mac char
+      codes to ps glyph names to glyph ID's...)
+
+    - If there is a TrueType font (an `sfnt' resource), read it into memory,
+      wrap it into a memory stream, load the TrueType driver and delegate
+      the rest of the work to it, by calling FT_Open_Face().
+
+    - Some suitcase fonts (notably Onyx) might point the `LWFN' file to
+      itself, even though it doesn't contains `POST' resources.  To handle
+      this special case without opening the file an extra time, we just
+      ignore errors from the `LWFN' and fallback to the `sfnt' if both are
+      available.
+  */
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_STREAM_H
+#include "ftbase.h"
+
+  /* This is for Mac OS X.  Without redefinition, OS_INLINE */
+  /* expands to `static inline' which doesn't survive the   */
+  /* -ansi compilation flag of GCC.                         */
+#if !HAVE_ANSI_OS_INLINE
+#undef  OS_INLINE
+#define OS_INLINE  static __inline__
+#endif
+
+  /* `configure' checks the availability of `ResourceIndex' strictly */
+  /* and sets HAVE_TYPE_RESOURCE_INDEX 1 or 0 always.  If it is      */
+  /* not set (e.g., a build without `configure'), the availability   */
+  /* is guessed from the SDK version.                                */
+#ifndef HAVE_TYPE_RESOURCE_INDEX
+#if !defined( MAC_OS_X_VERSION_10_5 ) || \
+    ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 )
+#define HAVE_TYPE_RESOURCE_INDEX 0
+#else
+#define HAVE_TYPE_RESOURCE_INDEX 1
+#endif
+#endif /* !HAVE_TYPE_RESOURCE_INDEX */
+
+#if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
+  typedef short  ResourceIndex;
+#endif
+
+#include <CoreServices/CoreServices.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <sys/syslimits.h> /* PATH_MAX */
+
+  /* Don't want warnings about our own use of deprecated functions. */
+#define FT_DEPRECATED_ATTRIBUTE
+
+#include FT_MAC_H
+
+#ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
+#define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
+#endif
+
+
+  /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
+     TrueType in case *both* are available (this is not common,
+     but it *is* possible). */
+#ifndef PREFER_LWFN
+#define PREFER_LWFN  1
+#endif
+
+
+#ifdef FT_MACINTOSH
+
+  /* This function is deprecated because FSSpec is deprecated in Mac OS X  */
+  FT_EXPORT_DEF( FT_Error )
+  FT_GetFile_From_Mac_Name( const char*  fontName,
+                            FSSpec*      pathSpec,
+                            FT_Long*     face_index )
+  {
+    FT_UNUSED( fontName );
+    FT_UNUSED( pathSpec );
+    FT_UNUSED( face_index );
+
+    return FT_THROW( Unimplemented_Feature );
+  }
+
+
+  /* Private function.                                         */
+  /* The FSSpec type has been discouraged for a long time,     */
+  /* unfortunately an FSRef replacement API for                */
+  /* ATSFontGetFileSpecification() is only available in        */
+  /* Mac OS X 10.5 and later.                                  */
+  static OSStatus
+  FT_ATSFontGetFileReference( ATSFontRef  ats_font_id,
+                              FSRef*      ats_font_ref )
+  {
+#if defined( MAC_OS_X_VERSION_10_5 ) && \
+    ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+
+    OSStatus  err;
+
+    err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
+
+    return err;
+#elif __LP64__ /* No 64bit Carbon API on legacy platforms */
+    FT_UNUSED( ats_font_id );
+    FT_UNUSED( ats_font_ref );
+
+
+    return fnfErr;
+#else /* 32bit Carbon API on legacy platforms */
+    OSStatus  err;
+    FSSpec    spec;
+
+
+    err = ATSFontGetFileSpecification( ats_font_id, &spec );
+    if ( noErr == err )
+      err = FSpMakeFSRef( &spec, ats_font_ref );
+
+    return err;
+#endif
+  }
+
+
+  static FT_Error
+  FT_GetFileRef_From_Mac_ATS_Name( const char*  fontName,
+                                   FSRef*       ats_font_ref,
+                                   FT_Long*     face_index )
+  {
+    CFStringRef  cf_fontName;
+    ATSFontRef   ats_font_id;
+
+
+    *face_index = 0;
+
+    cf_fontName = CFStringCreateWithCString( NULL, fontName,
+                                             kCFStringEncodingMacRoman );
+    ats_font_id = ATSFontFindFromName( cf_fontName,
+                                       kATSOptionFlagsUnRestrictedScope );
+    CFRelease( cf_fontName );
+
+    if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
+      return FT_THROW( Unknown_File_Format );
+
+    if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
+      return FT_THROW( Unknown_File_Format );
+
+    /* face_index calculation by searching preceding fontIDs */
+    /* with same FSRef                                       */
+    {
+      ATSFontRef  id2 = ats_font_id - 1;
+      FSRef       ref2;
+
+
+      while ( id2 > 0 )
+      {
+        if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
+          break;
+        if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
+          break;
+
+        id2 --;
+      }
+      *face_index = ats_font_id - ( id2 + 1 );
+    }
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName,
+                                    UInt8*       path,
+                                    UInt32       maxPathSize,
+                                    FT_Long*     face_index )
+  {
+    FSRef     ref;
+    FT_Error  err;
+
+
+    if ( !fontName || !face_index )
+      return FT_THROW( Invalid_Argument) ;
+
+    err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
+    if ( err )
+      return err;
+
+    if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
+      return FT_THROW( Unknown_File_Format );
+
+    return FT_Err_Ok;
+  }
+
+
+  /* This function is deprecated because FSSpec is deprecated in Mac OS X  */
+  FT_EXPORT_DEF( FT_Error )
+  FT_GetFile_From_Mac_ATS_Name( const char*  fontName,
+                                FSSpec*      pathSpec,
+                                FT_Long*     face_index )
+  {
+#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
+      ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
+    FT_UNUSED( fontName );
+    FT_UNUSED( pathSpec );
+    FT_UNUSED( face_index );
+
+    return FT_THROW( Unimplemented_Feature );
+#else
+    FSRef     ref;
+    FT_Error  err;
+
+
+    if ( !fontName || !face_index )
+      return FT_THROW( Invalid_Argument );
+
+    err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
+    if ( err )
+      return err;
+
+    if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
+                                    pathSpec, NULL ) )
+      return FT_THROW( Unknown_File_Format );
+
+    return FT_Err_Ok;
+#endif
+  }
+
+
+  static OSErr
+  FT_FSPathMakeRes( const UInt8*    pathname,
+                    ResFileRefNum*  res )
+  {
+    OSErr  err;
+    FSRef  ref;
+
+
+    if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
+      return FT_THROW( Cannot_Open_Resource );
+
+    /* at present, no support for dfont format */
+    err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
+    if ( noErr == err )
+      return err;
+
+    /* fallback to original resource-fork font */
+    *res = FSOpenResFile( &ref, fsRdPerm );
+    err  = ResError();
+
+    return err;
+  }
+
+
+  /* Return the file type for given pathname */
+  static OSType
+  get_file_type_from_path( const UInt8*  pathname )
+  {
+    FSRef          ref;
+    FSCatalogInfo  info;
+
+
+    if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
+      return ( OSType ) 0;
+
+    if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
+                                    NULL, NULL, NULL ) )
+      return ( OSType ) 0;
+
+    return ((FInfo *)(info.finderInfo))->fdType;
+  }
+
+
+  /* Given a PostScript font name, create the Macintosh LWFN file name. */
+  static void
+  create_lwfn_name( char*   ps_name,
+                    Str255  lwfn_file_name )
+  {
+    int       max = 5, count = 0;
+    FT_Byte*  p = lwfn_file_name;
+    FT_Byte*  q = (FT_Byte*)ps_name;
+
+
+    lwfn_file_name[0] = 0;
+
+    while ( *q )
+    {
+      if ( ft_isupper( *q ) )
+      {
+        if ( count )
+          max = 3;
+        count = 0;
+      }
+      if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
+      {
+        *++p = *q;
+        lwfn_file_name[0]++;
+        count++;
+      }
+      q++;
+    }
+  }
+
+
+  static short
+  count_faces_sfnt( char*  fond_data )
+  {
+    /* The count is 1 greater than the value in the FOND.  */
+    /* Isn't that cute? :-)                                */
+
+    return EndianS16_BtoN( *( (short*)( fond_data +
+                                        sizeof ( FamRec ) ) ) ) + 1;
+  }
+
+
+  static short
+  count_faces_scalable( char*  fond_data )
+  {
+    AsscEntry*  assoc;
+    short       i, face, face_all;
+
+
+    face_all = EndianS16_BtoN( *( (short *)( fond_data +
+                                             sizeof ( FamRec ) ) ) ) + 1;
+    assoc    = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
+    face     = 0;
+
+    for ( i = 0; i < face_all; i++ )
+    {
+      if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
+        face++;
+    }
+    return face;
+  }
+
+
+  /* Look inside the FOND data, answer whether there should be an SFNT
+     resource, and answer the name of a possible LWFN Type 1 file.
+
+     Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
+     to load a face OTHER than the first one in the FOND!
+  */
+
+
+  static void
+  parse_fond( char*   fond_data,
+              short*  have_sfnt,
+              ResID*  sfnt_id,
+              Str255  lwfn_file_name,
+              short   face_index )
+  {
+    AsscEntry*  assoc;
+    AsscEntry*  base_assoc;
+    FamRec*     fond;
+
+
+    *sfnt_id          = 0;
+    *have_sfnt        = 0;
+    lwfn_file_name[0] = 0;
+
+    fond       = (FamRec*)fond_data;
+    assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
+    base_assoc = assoc;
+
+    /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
+    if ( 47 < face_index )
+      return;
+
+    /* Let's do a little range checking before we get too excited here */
+    if ( face_index < count_faces_sfnt( fond_data ) )
+    {
+      assoc += face_index;        /* add on the face_index! */
+
+      /* if the face at this index is not scalable,
+         fall back to the first one (old behavior) */
+      if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
+      {
+        *have_sfnt = 1;
+        *sfnt_id   = EndianS16_BtoN( assoc->fontID );
+      }
+      else if ( base_assoc->fontSize == 0 )
+      {
+        *have_sfnt = 1;
+        *sfnt_id   = EndianS16_BtoN( base_assoc->fontID );
+      }
+    }
+
+    if ( EndianS32_BtoN( fond->ffStylOff ) )
+    {
+      unsigned char*  p = (unsigned char*)fond_data;
+      StyleTable*     style;
+      unsigned short  string_count;
+      char            ps_name[256];
+      unsigned char*  names[64];
+      int             i;
+
+
+      p += EndianS32_BtoN( fond->ffStylOff );
+      style = (StyleTable*)p;
+      p += sizeof ( StyleTable );
+      string_count = EndianS16_BtoN( *(short*)(p) );
+      string_count = FT_MIN( 64, string_count );
+      p += sizeof ( short );
+
+      for ( i = 0; i < string_count; i++ )
+      {
+        names[i] = p;
+        p       += names[i][0];
+        p++;
+      }
+
+      {
+        size_t  ps_name_len = (size_t)names[0][0];
+
+
+        if ( ps_name_len != 0 )
+        {
+          ft_memcpy(ps_name, names[0] + 1, ps_name_len);
+          ps_name[ps_name_len] = 0;
+        }
+        if ( style->indexes[face_index] > 1 &&
+             style->indexes[face_index] <= string_count )
+        {
+          unsigned char*  suffixes = names[style->indexes[face_index] - 1];
+
+
+          for ( i = 1; i <= suffixes[0]; i++ )
+          {
+            unsigned char*  s;
+            size_t          j = suffixes[i] - 1;
+
+
+            if ( j < string_count && ( s = names[j] ) != NULL )
+            {
+              size_t  s_len = (size_t)s[0];
+
+
+              if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
+              {
+                ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
+                ps_name_len += s_len;
+                ps_name[ps_name_len] = 0;
+              }
+            }
+          }
+        }
+      }
+
+      create_lwfn_name( ps_name, lwfn_file_name );
+    }
+  }
+
+
+  static  FT_Error
+  lookup_lwfn_by_fond( const UInt8*      path_fond,
+                       ConstStr255Param  base_lwfn,
+                       UInt8*            path_lwfn,
+                       size_t            path_size )
+  {
+    FSRef   ref, par_ref;
+    size_t  dirname_len;
+
+
+    /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
+    /* We should not extract parent directory by string manipulation.      */
+
+    if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) )
+      return FT_THROW( Invalid_Argument );
+
+    if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
+                                    NULL, NULL, NULL, &par_ref ) )
+      return FT_THROW( Invalid_Argument );
+
+    if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) )
+      return FT_THROW( Invalid_Argument );
+
+    if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size )
+      return FT_THROW( Invalid_Argument );
+
+    /* now we have absolute dirname in path_lwfn */
+    ft_strcat( (char *)path_lwfn, "/" );
+    dirname_len = ft_strlen( (char *)path_lwfn );
+    ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 );
+    path_lwfn[dirname_len + base_lwfn[0]] = '\0';
+
+    if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) )
+      return FT_THROW( Cannot_Open_Resource );
+
+    if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
+                                    NULL, NULL, NULL, NULL ) )
+      return FT_THROW( Cannot_Open_Resource );
+
+    return FT_Err_Ok;
+  }
+
+
+  static short
+  count_faces( Handle        fond,
+               const UInt8*  pathname )
+  {
+    ResID     sfnt_id;
+    short     have_sfnt, have_lwfn;
+    Str255    lwfn_file_name;
+    UInt8     buff[PATH_MAX];
+    FT_Error  err;
+    short     num_faces;
+
+
+    have_sfnt = have_lwfn = 0;
+
+    parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
+
+    if ( lwfn_file_name[0] )
+    {
+      err = lookup_lwfn_by_fond( pathname, lwfn_file_name,
+                                 buff, sizeof ( buff )  );
+      if ( !err )
+        have_lwfn = 1;
+    }
+
+    if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
+      num_faces = 1;
+    else
+      num_faces = count_faces_scalable( *fond );
+
+    return num_faces;
+  }
+
+
+  /* Read Type 1 data from the POST resources inside the LWFN file,
+     return a PFB buffer.  This is somewhat convoluted because the FT2
+     PFB parser wants the ASCII header as one chunk, and the LWFN
+     chunks are often not organized that way, so we glue chunks
+     of the same type together. */
+  static FT_Error
+  read_lwfn( FT_Memory      memory,
+             ResFileRefNum  res,
+             FT_Byte**      pfb_data,
+             FT_ULong*      size )
+  {
+    FT_Error       error = FT_Err_Ok;
+    ResID          res_id;
+    unsigned char  *buffer, *p, *size_p = NULL;
+    FT_ULong       total_size = 0;
+    FT_ULong       old_total_size = 0;
+    FT_ULong       post_size, pfb_chunk_size;
+    Handle         post_data;
+    char           code, last_code;
+
+
+    UseResFile( res );
+
+    /* First pass: load all POST resources, and determine the size of */
+    /* the output buffer.                                             */
+    res_id    = 501;
+    last_code = -1;
+
+    for (;;)
+    {
+      post_data = Get1Resource( TTAG_POST, res_id++ );
+      if ( post_data == NULL )
+        break;  /* we are done */
+
+      code = (*post_data)[0];
+
+      if ( code != last_code )
+      {
+        if ( code == 5 )
+          total_size += 2; /* just the end code */
+        else
+          total_size += 6; /* code + 4 bytes chunk length */
+      }
+
+      total_size += (FT_ULong)GetHandleSize( post_data ) - 2;
+      last_code = code;
+
+      /* detect resource fork overflow */
+      if ( FT_MAC_RFORK_MAX_LEN < total_size )
+      {
+        error = FT_THROW( Array_Too_Large );
+        goto Error;
+      }
+
+      old_total_size = total_size;
+    }
+
+    if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
+      goto Error;
+
+    /* Second pass: append all POST data to the buffer, add PFB fields. */
+    /* Glue all consecutive chunks of the same type together.           */
+    p              = buffer;
+    res_id         = 501;
+    last_code      = -1;
+    pfb_chunk_size = 0;
+
+    for (;;)
+    {
+      post_data = Get1Resource( TTAG_POST, res_id++ );
+      if ( post_data == NULL )
+        break;  /* we are done */
+
+      post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
+      code = (*post_data)[0];
+
+      if ( code != last_code )
+      {
+        if ( last_code != -1 )
+        {
+          /* we are done adding a chunk, fill in the size field */
+          if ( size_p != NULL )
+          {
+            *size_p++ = (FT_Byte)(   pfb_chunk_size         & 0xFF );
+            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8  ) & 0xFF );
+            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
+            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
+          }
+          pfb_chunk_size = 0;
+        }
+
+        *p++ = 0x80;
+        if ( code == 5 )
+          *p++ = 0x03;  /* the end */
+        else if ( code == 2 )
+          *p++ = 0x02;  /* binary segment */
+        else
+          *p++ = 0x01;  /* ASCII segment */
+
+        if ( code != 5 )
+        {
+          size_p = p;   /* save for later */
+          p += 4;       /* make space for size field */
+        }
+      }
+
+      ft_memcpy( p, *post_data + 2, post_size );
+      pfb_chunk_size += post_size;
+      p += post_size;
+      last_code = code;
+    }
+
+    *pfb_data = buffer;
+    *size = total_size;
+
+  Error:
+    CloseResFile( res );
+    return error;
+  }
+
+
+  /* Create a new FT_Face from a file path to an LWFN file. */
+  static FT_Error
+  FT_New_Face_From_LWFN( FT_Library    library,
+                         const UInt8*  pathname,
+                         FT_Long       face_index,
+                         FT_Face*      aface )
+  {
+    FT_Byte*       pfb_data;
+    FT_ULong       pfb_size;
+    FT_Error       error;
+    ResFileRefNum  res;
+
+
+    if ( noErr != FT_FSPathMakeRes( pathname, &res ) )
+      return FT_THROW( Cannot_Open_Resource );
+
+    pfb_data = NULL;
+    pfb_size = 0;
+    error = read_lwfn( library->memory, res, &pfb_data, &pfb_size );
+    CloseResFile( res ); /* PFB is already loaded, useless anymore */
+    if ( error )
+      return error;
+
+    return open_face_from_buffer( library,
+                                  pfb_data,
+                                  pfb_size,
+                                  face_index,
+                                  "type1",
+                                  aface );
+  }
+
+
+  /* Create a new FT_Face from an SFNT resource, specified by res ID. */
+  static FT_Error
+  FT_New_Face_From_SFNT( FT_Library  library,
+                         ResID       sfnt_id,
+                         FT_Long     face_index,
+                         FT_Face*    aface )
+  {
+    Handle     sfnt = NULL;
+    FT_Byte*   sfnt_data;
+    size_t     sfnt_size;
+    FT_Error   error  = FT_Err_Ok;
+    FT_Memory  memory = library->memory;
+    int        is_cff, is_sfnt_ps;
+
+
+    sfnt = GetResource( TTAG_sfnt, sfnt_id );
+    if ( sfnt == NULL )
+      return FT_THROW( Invalid_Handle );
+
+    sfnt_size = (FT_ULong)GetHandleSize( sfnt );
+
+    /* detect resource fork overflow */
+    if ( FT_MAC_RFORK_MAX_LEN < sfnt_size )
+      return FT_THROW( Array_Too_Large );
+
+    if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
+    {
+      ReleaseResource( sfnt );
+      return error;
+    }
+
+    ft_memcpy( sfnt_data, *sfnt, sfnt_size );
+    ReleaseResource( sfnt );
+
+    is_cff     = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
+    is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 );
+
+    if ( is_sfnt_ps )
+    {
+      FT_Stream  stream;
+
+
+      if ( FT_NEW( stream ) )
+        goto Try_OpenType;
+
+      FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size );
+      if ( !open_face_PS_from_sfnt_stream( library,
+                                           stream,
+                                           face_index,
+                                           0, NULL,
+                                           aface ) )
+      {
+        FT_Stream_Close( stream );
+        FT_FREE( stream );
+        FT_FREE( sfnt_data );
+        goto Exit;
+      }
+
+      FT_FREE( stream );
+    }
+  Try_OpenType:
+    error = open_face_from_buffer( library,
+                                   sfnt_data,
+                                   sfnt_size,
+                                   face_index,
+                                   is_cff ? "cff" : "truetype",
+                                   aface );
+  Exit:
+    return error;
+  }
+
+
+  /* Create a new FT_Face from a file path to a suitcase file. */
+  static FT_Error
+  FT_New_Face_From_Suitcase( FT_Library    library,
+                             const UInt8*  pathname,
+                             FT_Long       face_index,
+                             FT_Face*      aface )
+  {
+    FT_Error       error = FT_ERR( Cannot_Open_Resource );
+    ResFileRefNum  res_ref;
+    ResourceIndex  res_index;
+    Handle         fond;
+    short          num_faces_in_res;
+
+
+    if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) )
+      return FT_THROW( Cannot_Open_Resource );
+
+    UseResFile( res_ref );
+    if ( ResError() )
+      return FT_THROW( Cannot_Open_Resource );
+
+    num_faces_in_res = 0;
+    for ( res_index = 1; ; ++res_index )
+    {
+      short  num_faces_in_fond;
+
+
+      fond = Get1IndResource( TTAG_FOND, res_index );
+      if ( ResError() )
+        break;
+
+      num_faces_in_fond  = count_faces( fond, pathname );
+      num_faces_in_res  += num_faces_in_fond;
+
+      if ( 0 <= face_index && face_index < num_faces_in_fond && error )
+        error = FT_New_Face_From_FOND( library, fond, face_index, aface );
+
+      face_index -= num_faces_in_fond;
+    }
+
+    CloseResFile( res_ref );
+    if ( !error && aface && *aface )
+      (*aface)->num_faces = num_faces_in_res;
+    return error;
+  }
+
+
+  /* documentation is in ftmac.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face_From_FOND( FT_Library  library,
+                         Handle      fond,
+                         FT_Long     face_index,
+                         FT_Face*    aface )
+  {
+    short     have_sfnt, have_lwfn = 0;
+    ResID     sfnt_id, fond_id;
+    OSType    fond_type;
+    Str255    fond_name;
+    Str255    lwfn_file_name;
+    UInt8     path_lwfn[PATH_MAX];
+    OSErr     err;
+    FT_Error  error = FT_Err_Ok;
+
+
+    /* check of `library' and `aface' delayed to `FT_New_Face_From_XXX' */
+
+    GetResInfo( fond, &fond_id, &fond_type, fond_name );
+    if ( ResError() != noErr || fond_type != TTAG_FOND )
+      return FT_THROW( Invalid_File_Format );
+
+    parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
+
+    if ( lwfn_file_name[0] )
+    {
+      ResFileRefNum  res;
+
+
+      res = HomeResFile( fond );
+      if ( noErr != ResError() )
+        goto found_no_lwfn_file;
+
+      {
+        UInt8  path_fond[PATH_MAX];
+        FSRef  ref;
+
+
+        err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum,
+                               NULL, NULL, NULL, &ref, NULL );
+        if ( noErr != err )
+          goto found_no_lwfn_file;
+
+        err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) );
+        if ( noErr != err )
+          goto found_no_lwfn_file;
+
+        error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
+                                     path_lwfn, sizeof ( path_lwfn ) );
+        if ( !error )
+          have_lwfn = 1;
+      }
+    }
+
+    if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
+      error = FT_New_Face_From_LWFN( library,
+                                     path_lwfn,
+                                     face_index,
+                                     aface );
+    else
+      error = FT_THROW( Unknown_File_Format );
+
+  found_no_lwfn_file:
+    if ( have_sfnt && error )
+      error = FT_New_Face_From_SFNT( library,
+                                     sfnt_id,
+                                     face_index,
+                                     aface );
+
+    return error;
+  }
+
+
+  /* Common function to load a new FT_Face from a resource file. */
+  static FT_Error
+  FT_New_Face_From_Resource( FT_Library    library,
+                             const UInt8*  pathname,
+                             FT_Long       face_index,
+                             FT_Face*      aface )
+  {
+    OSType    file_type;
+    FT_Error  error;
+
+
+    /* LWFN is a (very) specific file format, check for it explicitly */
+    file_type = get_file_type_from_path( pathname );
+    if ( file_type == TTAG_LWFN )
+      return FT_New_Face_From_LWFN( library, pathname, face_index, aface );
+
+    /* Otherwise the file type doesn't matter (there are more than  */
+    /* `FFIL' and `tfil').  Just try opening it as a font suitcase; */
+    /* if it works, fine.                                           */
+
+    error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface );
+    if ( error == 0 )
+      return error;
+
+    /* let it fall through to normal loader (.ttf, .otf, etc.); */
+    /* we signal this by returning no error and no FT_Face      */
+    *aface = NULL;
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_New_Face                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This is the Mac-specific implementation of FT_New_Face.  In        */
+  /*    addition to the standard FT_New_Face() functionality, it also      */
+  /*    accepts pathnames to Mac suitcase files.  For further              */
+  /*    documentation see the original FT_New_Face() in freetype.h.        */
+  /*                                                                       */
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face( FT_Library   library,
+               const char*  pathname,
+               FT_Long      face_index,
+               FT_Face*     aface )
+  {
+    FT_Open_Args  args;
+    FT_Error      error;
+
+
+    /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+    if ( !pathname )
+      return FT_THROW( Invalid_Argument );
+
+    *aface = NULL;
+
+    /* try resourcefork based font: LWFN, FFIL */
+    error = FT_New_Face_From_Resource( library, (UInt8 *)pathname,
+                                       face_index, aface );
+    if ( error != 0 || *aface != NULL )
+      return error;
+
+    /* let it fall through to normal loader (.ttf, .otf, etc.) */
+    args.flags    = FT_OPEN_PATHNAME;
+    args.pathname = (char*)pathname;
+    return FT_Open_Face( library, &args, face_index, aface );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_New_Face_From_FSRef                                             */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    FT_New_Face_From_FSRef is identical to FT_New_Face except it       */
+  /*    accepts an FSRef instead of a path.                                */
+  /*                                                                       */
+  /* This function is deprecated because Carbon data types (FSRef)         */
+  /* are not cross-platform, and thus not suitable for the freetype API.   */
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face_From_FSRef( FT_Library    library,
+                          const FSRef*  ref,
+                          FT_Long       face_index,
+                          FT_Face*      aface )
+  {
+    FT_Error      error;
+    FT_Open_Args  args;
+
+    OSErr  err;
+    UInt8  pathname[PATH_MAX];
+
+
+    /* check of `library' and `aface' delayed to */
+    /* `FT_New_Face_From_Resource'               */
+
+    if ( !ref )
+      return FT_THROW( Invalid_Argument );
+
+    err = FSRefMakePath( ref, pathname, sizeof ( pathname ) );
+    if ( err )
+      error = FT_THROW( Cannot_Open_Resource );
+
+    error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
+    if ( error != 0 || *aface != NULL )
+      return error;
+
+    /* fallback to datafork font */
+    args.flags    = FT_OPEN_PATHNAME;
+    args.pathname = (char*)pathname;
+    return FT_Open_Face( library, &args, face_index, aface );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_New_Face_From_FSSpec                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    FT_New_Face_From_FSSpec is identical to FT_New_Face except it      */
+  /*    accepts an FSSpec instead of a path.                               */
+  /*                                                                       */
+  /* This function is deprecated because FSSpec is deprecated in Mac OS X  */
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face_From_FSSpec( FT_Library     library,
+                           const FSSpec*  spec,
+                           FT_Long        face_index,
+                           FT_Face*       aface )
+  {
+#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
+      ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
+    FT_UNUSED( library );
+    FT_UNUSED( spec );
+    FT_UNUSED( face_index );
+    FT_UNUSED( aface );
+
+    return FT_THROW( Unimplemented_Feature );
+#else
+    FSRef  ref;
+
+
+    /* check of `library' and `aface' delayed to `FT_New_Face_From_FSRef' */
+
+    if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
+      return FT_THROW( Invalid_Argument );
+    else
+      return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
+#endif
+  }
+
+#endif /* FT_MACINTOSH */
+
+
+/* END */
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index 9c3332c..96572bd 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -55,7 +55,18 @@
 #pragma warning( disable : 4244 )
 #endif /* _MSC_VER */
 
-  /* it's easiest to include `md5.c' directly */
+  /* It's easiest to include `md5.c' directly.  However, since OpenSSL */
+  /* also provides the same functions, there might be conflicts if     */
+  /* both FreeType and OpenSSL are built as static libraries.  For     */
+  /* this reason, we put the MD5 stuff into the `FT_' namespace.       */
+#define MD5_u32plus  FT_MD5_u32plus
+#define MD5_CTX      FT_MD5_CTX
+#define MD5_Init     FT_MD5_Init
+#define MD5_Update   FT_MD5_Update
+#define MD5_Final    FT_MD5_Final
+
+#undef  HAVE_OPENSSL
+
 #include "md5.c"
 
 #if defined( _MSC_VER )
@@ -675,7 +686,8 @@
         /* check the size of the `fpgm' and `prep' tables, too --    */
         /* the assumption is that there don't exist real TTFs where  */
         /* both `fpgm' and `prep' tables are missing                 */
-        if ( mode == FT_RENDER_MODE_LIGHT                       ||
+        if ( ( mode == FT_RENDER_MODE_LIGHT                   &&
+               !FT_DRIVER_HINTS_LIGHTLY( driver ) )             ||
              face->internal->ignore_unpatented_hinter           ||
              ( FT_IS_SFNT( face )                             &&
                ttface->num_locations                          &&
@@ -1375,13 +1387,13 @@
     }
 
 #ifdef FT_MACINTOSH
-    /* At this point, face_index has served its purpose;      */
+    /* At this point, the face index has served its purpose;  */
     /* whoever calls this function has already used it to     */
     /* locate the correct font data.  We should not propagate */
     /* this index to FT_Open_Face() (unless it is negative).  */
 
     if ( face_index > 0 )
-      face_index = 0;
+      face_index &= 0x7FFF0000L; /* retain GX data */
 #endif
 
     error = FT_Open_Face( library, &args, face_index, aface );
@@ -1495,6 +1507,10 @@
     FT_UNUSED( params );
 
 
+    /* ignore GX stuff */
+    if ( face_index > 0 )
+      face_index &= 0xFFFFL;
+
     pos = FT_STREAM_POS();
 
     error = ft_lookup_PS_in_sfnt_stream( stream,
@@ -1505,15 +1521,18 @@
     if ( error )
       goto Exit;
 
-    if ( FT_Stream_Seek( stream, pos + offset ) )
+    error = FT_Stream_Seek( stream, pos + offset );
+    if ( error )
       goto Exit;
 
     if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
       goto Exit;
 
     error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
-    if ( error )
+    if ( error ) {
+      FT_FREE( sfnt_ps );
       goto Exit;
+    }
 
     error = open_face_from_buffer( library,
                                    sfnt_ps,
@@ -1582,12 +1601,14 @@
       /* FT2 allocator takes signed long buffer length,
        * too large value causing overflow should be checked
        */
-      FT_TRACE4(( "                 POST fragment #%d: length=0x%08x\n",
-                  i, temp));
-      if ( 0x7FFFFFFFUL < temp || pfb_len + temp + 6 < pfb_len )
+      FT_TRACE4(( "                 POST fragment #%d: length=0x%08x"
+                  " total pfb_len=0x%08x\n",
+                  i, temp, pfb_len + temp + 6));
+      if ( FT_MAC_RFORK_MAX_LEN < temp               ||
+           FT_MAC_RFORK_MAX_LEN - temp < pfb_len + 6 )
       {
-        FT_TRACE2(( "             too long fragment length makes"
-                    " pfb_len confused: temp=0x%08x\n", temp ));
+        FT_TRACE2(( "             MacOS resource length cannot exceed"
+                    " 0x%08x\n", FT_MAC_RFORK_MAX_LEN ));
         error = FT_THROW( Invalid_Offset );
         goto Exit;
       }
@@ -1660,7 +1681,7 @@
       else
       {
         FT_TRACE3(( "    Write POST fragment #%d header (4-byte) to buffer"
-                    " 0x%p + 0x%08x\n", i, pfb_data, pfb_lenpos ));
+                    " %p + 0x%08x\n", i, pfb_data, pfb_lenpos ));
         if ( pfb_lenpos + 3 > pfb_len + 2 )
           goto Exit2;
         pfb_data[pfb_lenpos    ] = (FT_Byte)( len );
@@ -1672,7 +1693,7 @@
           break;
 
         FT_TRACE3(( "    Write POST fragment #%d header (6-byte) to buffer"
-                    " 0x%p + 0x%08x\n", i, pfb_data, pfb_pos ));
+                    " %p + 0x%08x\n", i, pfb_data, pfb_pos ));
         if ( pfb_pos + 6 > pfb_len + 2 )
           goto Exit2;
         pfb_data[pfb_pos++] = 0x80;
@@ -1692,7 +1713,7 @@
         goto Exit2;
 
       FT_TRACE3(( "    Load POST fragment #%d (%d byte) to buffer"
-                  " 0x%p + 0x%08x\n", i, rlen, pfb_data, pfb_pos ));
+                  " %p + 0x%08x\n", i, rlen, pfb_data, pfb_pos ));
       error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
       if ( error )
         goto Exit2;
@@ -1737,7 +1758,7 @@
   /* The resource header says we've got resource_cnt `sfnt'      */
   /* (TrueType/OpenType) resources in this file.  Look through   */
   /* them for the one indicated by face_index, load it into mem, */
-  /* pass it on the the truetype driver and return it.           */
+  /* pass it on to the truetype driver, and return it.           */
   /*                                                             */
   static FT_Error
   Mac_Read_sfnt_Resource( FT_Library  library,
@@ -1770,6 +1791,8 @@
       goto Exit;
     if ( rlen == -1 )
       return FT_THROW( Cannot_Open_Resource );
+    if ( (FT_ULong)rlen > FT_MAC_RFORK_MAX_LEN )
+      return FT_THROW( Invalid_Offset );
 
     error = open_face_PS_from_sfnt_stream( library,
                                            stream,
@@ -1780,14 +1803,17 @@
       goto Exit;
 
     /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
-    if ( FT_Stream_Seek( stream, flag_offset + 4 ) )
+    error = FT_Stream_Seek( stream, flag_offset + 4 );
+    if ( error )
       goto Exit;
 
     if ( FT_ALLOC( sfnt_data, rlen ) )
       return error;
     error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, (FT_ULong)rlen );
-    if ( error )
+    if ( error ) {
+      FT_FREE( sfnt_data );
       goto Exit;
+    }
 
     is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
     error = open_face_from_buffer( library,
@@ -1889,13 +1915,14 @@
     if ( error )
       goto Exit;
 
-    if (            header[ 0] !=  0 ||
-                    header[74] !=  0 ||
-                    header[82] !=  0 ||
-                    header[ 1] ==  0 ||
-                    header[ 1] >  33 ||
-                    header[63] !=  0 ||
-         header[2 + header[1]] !=  0 )
+    if (            header[ 0] !=   0 ||
+                    header[74] !=   0 ||
+                    header[82] !=   0 ||
+                    header[ 1] ==   0 ||
+                    header[ 1] >   33 ||
+                    header[63] !=   0 ||
+         header[2 + header[1]] !=   0 ||
+                  header[0x53] > 0x7F )
       return FT_THROW( Unknown_File_Format );
 
     dlen = ( header[0x53] << 24 ) |
@@ -2032,7 +2059,11 @@
 #undef  FT_COMPONENT
 #define FT_COMPONENT  trace_raccess
 
-      FT_TRACE3(( "Try as dfont: %s ...", args->pathname ));
+#ifdef FT_DEBUG_LEVEL_TRACE
+      FT_TRACE3(( "Try as dfont: " ));
+      if ( !( args->flags & FT_OPEN_MEMORY ) )
+        FT_TRACE3(( "%s ...", args->pathname ));
+#endif
 
       error = IsMacResource( library, stream, 0, face_index, aface );
 
@@ -2154,7 +2185,8 @@
                FT_ERR_EQ( error, Table_Missing )                        )
           {
             /* TrueType but essential tables are missing */
-            if ( FT_Stream_Seek( stream, 0 ) )
+            error = FT_Stream_Seek( stream, 0 );
+            if ( error )
               break;
 
             error = open_face_PS_from_sfnt_stream( library,
@@ -3068,18 +3100,37 @@
 
           if ( kern_mode != FT_KERNING_UNFITTED )
           {
+            FT_Pos  orig_x = akerning->x;
+            FT_Pos  orig_y = akerning->y;
+
+
             /* we scale down kerning values for small ppem values */
             /* to avoid that rounding makes them too big.         */
             /* `25' has been determined heuristically.            */
             if ( face->size->metrics.x_ppem < 25 )
-              akerning->x = FT_MulDiv( akerning->x,
+              akerning->x = FT_MulDiv( orig_x,
                                        face->size->metrics.x_ppem, 25 );
             if ( face->size->metrics.y_ppem < 25 )
-              akerning->y = FT_MulDiv( akerning->y,
+              akerning->y = FT_MulDiv( orig_y,
                                        face->size->metrics.y_ppem, 25 );
 
             akerning->x = FT_PIX_ROUND( akerning->x );
             akerning->y = FT_PIX_ROUND( akerning->y );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+            {
+              FT_Pos  orig_x_rounded = FT_PIX_ROUND( orig_x );
+              FT_Pos  orig_y_rounded = FT_PIX_ROUND( orig_y );
+
+
+              if ( akerning->x != orig_x_rounded ||
+                   akerning->y != orig_y_rounded )
+                FT_TRACE5(( "FT_Get_Kerning: horizontal kerning"
+                            " (%d, %d) scaled down to (%d, %d) pixels\n",
+                            orig_x_rounded / 64, orig_y_rounded / 64,
+                            akerning->x / 64, akerning->y / 64 ));
+            }
+#endif
           }
         }
       }
@@ -3350,8 +3401,12 @@
         FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
         FT_TRACE1(( " 0x%x is truncated\n", charcode ));
       }
+
       result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
+      if ( result >= (FT_UInt)face->num_glyphs )
+        result = 0;
     }
+
     return result;
   }
 
@@ -3370,7 +3425,7 @@
     if ( face && face->charmap && face->num_glyphs )
     {
       gindex = FT_Get_Char_Index( face, 0 );
-      if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs )
+      if ( gindex == 0 )
         result = FT_Get_Next_Char( face, 0, &gindex );
     }
 
@@ -4116,39 +4171,50 @@
 #undef  FT_COMPONENT
 #define FT_COMPONENT  trace_bitmap
 
-    /* we convert to a single bitmap format for computing the checksum */
-    if ( !error )
+    /*
+     * Computing the MD5 checksum is expensive, unnecessarily distorting a
+     * possible profiling of FreeType if compiled with tracing support.  For
+     * this reason, we execute the following code only if explicitly
+     * requested.
+     */
+
+    /* we use FT_TRACE3 in this block */
+    if ( ft_trace_levels[trace_bitmap] >= 3 )
     {
-      FT_Bitmap  bitmap;
-      FT_Error   err;
-
-
-      FT_Bitmap_Init( &bitmap );
-
-      /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */
-      err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 );
-      if ( !err )
+      /* we convert to a single bitmap format for computing the checksum */
+      if ( !error )
       {
-        MD5_CTX        ctx;
-        unsigned char  md5[16];
-        int            i;
-        unsigned int   rows  = bitmap.rows;
-        unsigned int   pitch = (unsigned int)bitmap.pitch;
+        FT_Bitmap  bitmap;
+        FT_Error   err;
 
 
-        MD5_Init( &ctx );
-        MD5_Update( &ctx, bitmap.buffer, rows * pitch );
-        MD5_Final( md5, &ctx );
+        FT_Bitmap_Init( &bitmap );
 
-        FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n"
-                    "  ",
-                    rows, pitch ));
-        for ( i = 0; i < 16; i++ )
-          FT_TRACE3(( "%02X", md5[i] ));
-        FT_TRACE3(( "\n" ));
+        /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */
+        err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 );
+        if ( !err )
+        {
+          MD5_CTX        ctx;
+          unsigned char  md5[16];
+          int            i;
+          unsigned int   rows  = bitmap.rows;
+          unsigned int   pitch = (unsigned int)bitmap.pitch;
+
+
+          MD5_Init( &ctx );
+          MD5_Update( &ctx, bitmap.buffer, rows * pitch );
+          MD5_Final( md5, &ctx );
+
+          FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n"
+                      "  ",
+                      rows, pitch ));
+          for ( i = 0; i < 16; i++ )
+            FT_TRACE3(( "%02X", md5[i] ));
+          FT_TRACE3(( "\n" ));
+        }
+
+        FT_Bitmap_Done( library, &bitmap );
       }
-
-      FT_Bitmap_Done( library, &bitmap );
     }
 
 #undef  FT_COMPONENT
diff --git a/src/base/ftotval.c b/src/base/ftotval.c
new file mode 100644
index 0000000..786457b
--- /dev/null
+++ b/src/base/ftotval.c
@@ -0,0 +1,91 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftotval.c                                                              */
+/*                                                                         */
+/*    FreeType API for validating OpenType tables (body).                  */
+/*                                                                         */
+/*  Copyright 2004-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_OPENTYPE_VALIDATE_H
+#include FT_OPENTYPE_VALIDATE_H
+
+
+  /* documentation is in ftotval.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_OpenType_Validate( FT_Face    face,
+                        FT_UInt    validation_flags,
+                        FT_Bytes  *BASE_table,
+                        FT_Bytes  *GDEF_table,
+                        FT_Bytes  *GPOS_table,
+                        FT_Bytes  *GSUB_table,
+                        FT_Bytes  *JSTF_table )
+  {
+    FT_Service_OTvalidate  service;
+    FT_Error               error;
+
+
+    if ( !face )
+    {
+      error = FT_THROW( Invalid_Face_Handle );
+      goto Exit;
+    }
+
+    if ( !( BASE_table &&
+            GDEF_table &&
+            GPOS_table &&
+            GSUB_table &&
+            JSTF_table ) )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE );
+
+    if ( service )
+      error = service->validate( face,
+                                 validation_flags,
+                                 BASE_table,
+                                 GDEF_table,
+                                 GPOS_table,
+                                 GSUB_table,
+                                 JSTF_table );
+    else
+      error = FT_THROW( Unimplemented_Feature );
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_OpenType_Free( FT_Face   face,
+                    FT_Bytes  table )
+  {
+    FT_Memory  memory;
+
+
+    if ( !face )
+      return;
+
+    memory = FT_FACE_MEMORY( face );
+
+    FT_FREE( table );
+  }
+
+
+/* END */
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index d821c49..201ceab 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -52,8 +52,9 @@
                         const FT_Outline_Funcs*  func_interface,
                         void*                    user )
   {
-#undef SCALED
-#define SCALED( x )  ( ( (x) << shift ) - delta )
+#undef  SCALED
+#define SCALED( x )  ( ( (x) < 0 ? -( -(x) << shift )             \
+                                 :  (  (x) << shift ) ) - delta )
 
     FT_Vector   v_last;
     FT_Vector   v_control;
@@ -907,8 +908,7 @@
                          FT_Pos       ystrength )
   {
     FT_Vector*  points;
-    FT_Vector   v_prev, v_first, v_next, v_cur;
-    FT_Int      c, n, first;
+    FT_Int      c, first, last;
     FT_Int      orientation;
 
 
@@ -934,87 +934,98 @@
     first = 0;
     for ( c = 0; c < outline->n_contours; c++ )
     {
-      FT_Vector  in, out, shift;
-      FT_Fixed   l_in, l_out, l, q, d;
-      int        last = outline->contours[c];
+      FT_Vector  in, out, anchor, shift;
+      FT_Fixed   l_in, l_out, l_anchor = 0, l, q, d;
+      FT_Int     i, j, k;
 
 
-      v_first = points[first];
-      v_prev  = points[last];
-      v_cur   = v_first;
+      l_in = 0;
+      last = outline->contours[c];
 
-      /* compute incoming normalized vector */
-      in.x = v_cur.x - v_prev.x;
-      in.y = v_cur.y - v_prev.y;
-      l_in = FT_Vector_Length( &in );
-      if ( l_in )
+      /* pacify compiler */
+      in.x = in.y = anchor.x = anchor.y = 0;
+
+      /* Counter j cycles though the points; counter i advances only  */
+      /* when points are moved; anchor k marks the first moved point. */
+      for ( i = last, j = first, k = -1;
+            j != i && i != k;
+            j = j < last ? j + 1 : first )
       {
-        in.x = FT_DivFix( in.x, l_in );
-        in.y = FT_DivFix( in.y, l_in );
-      }
-
-      for ( n = first; n <= last; n++ )
-      {
-        if ( n < last )
-          v_next = points[n + 1];
-        else
-          v_next = v_first;
-
-        /* compute outgoing normalized vector */
-        out.x = v_next.x - v_cur.x;
-        out.y = v_next.y - v_cur.y;
-        l_out = FT_Vector_Length( &out );
-        if ( l_out )
+        if ( j != k )
         {
-          out.x = FT_DivFix( out.x, l_out );
-          out.y = FT_DivFix( out.y, l_out );
-        }
+          out.x = points[j].x - points[i].x;
+          out.y = points[j].y - points[i].y;
+          l_out = (FT_Fixed)FT_Vector_NormLen( &out );
 
-        d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y );
-
-        /* shift only if turn is less than ~160 degrees */
-        if ( d > -0xF000L )
-        {
-          d = d + 0x10000L;
-
-          /* shift components are aligned along lateral bisector */
-          /* and directed according to the outline orientation.  */
-          shift.x = in.y + out.y;
-          shift.y = in.x + out.x;
-
-          if ( orientation == FT_ORIENTATION_TRUETYPE )
-            shift.x = -shift.x;
-          else
-            shift.y = -shift.y;
-
-          /* restrict shift magnitude to better handle collapsing segments */
-          q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x );
-          if ( orientation == FT_ORIENTATION_TRUETYPE )
-            q = -q;
-
-          l = FT_MIN( l_in, l_out );
-
-          /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
-          if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) )
-            shift.x = FT_MulDiv( shift.x, xstrength, d );
-          else
-            shift.x = FT_MulDiv( shift.x, l, q );
-
-
-          if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) )
-            shift.y = FT_MulDiv( shift.y, ystrength, d );
-          else
-            shift.y = FT_MulDiv( shift.y, l, q );
+          if ( l_out == 0 )
+            continue;
         }
         else
-          shift.x = shift.y = 0;
+        {
+          out   = anchor;
+          l_out = l_anchor;
+        }
 
-        outline->points[n].x = v_cur.x + xstrength + shift.x;
-        outline->points[n].y = v_cur.y + ystrength + shift.y;
+        if ( l_in != 0 )
+        {
+          if ( k < 0 )
+          {
+            k        = i;
+            anchor   = in;
+            l_anchor = l_in;
+          }
 
-        in    = out;
-        l_in  = l_out;
-        v_cur = v_next;
+          d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y );
+
+          /* shift only if turn is less than ~160 degrees */
+          if ( d > -0xF000L )
+          {
+            d = d + 0x10000L;
+
+            /* shift components along lateral bisector in proper orientation */
+            shift.x = in.y + out.y;
+            shift.y = in.x + out.x;
+
+            if ( orientation == FT_ORIENTATION_TRUETYPE )
+              shift.x = -shift.x;
+            else
+              shift.y = -shift.y;
+
+            /* restrict shift magnitude to better handle collapsing segments */
+            q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x );
+            if ( orientation == FT_ORIENTATION_TRUETYPE )
+              q = -q;
+
+            l = FT_MIN( l_in, l_out );
+
+            /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
+            if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) )
+              shift.x = FT_MulDiv( shift.x, xstrength, d );
+            else
+              shift.x = FT_MulDiv( shift.x, l, q );
+
+
+            if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) )
+              shift.y = FT_MulDiv( shift.y, ystrength, d );
+            else
+              shift.y = FT_MulDiv( shift.y, l, q );
+          }
+          else
+            shift.x = shift.y = 0;
+
+          for ( ;
+                i != j;
+                i = i < last ? i + 1 : first )
+          {
+            points[i].x += xstrength + shift.x;
+            points[i].y += ystrength + shift.y;
+          }
+        }
+        else
+          i = j;
+
+        in   = out;
+        l_in = l_out;
       }
 
       first = last + 1;
@@ -1066,13 +1077,16 @@
       FT_Int  last = outline->contours[c];
 
 
-      v_prev = points[last];
+      v_prev.x = points[last].x >> xshift;
+      v_prev.y = points[last].y >> yshift;
 
       for ( n = first; n <= last; n++ )
       {
-        v_cur = points[n];
-        area += ( ( v_cur.y - v_prev.y ) >> yshift ) *
-                ( ( v_cur.x + v_prev.x ) >> xshift );
+        v_cur.x = points[n].x >> xshift;
+        v_cur.y = points[n].y >> yshift;
+
+        area += ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x );
+
         v_prev = v_cur;
       }
 
diff --git a/src/base/ftpfr.c b/src/base/ftpfr.c
new file mode 100644
index 0000000..39f089e
--- /dev/null
+++ b/src/base/ftpfr.c
@@ -0,0 +1,153 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftpfr.c                                                                */
+/*                                                                         */
+/*    FreeType API for accessing PFR-specific data (body).                 */
+/*                                                                         */
+/*  Copyright 2002-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_PFR_H
+
+
+  /* check the format */
+  static FT_Service_PfrMetrics
+  ft_pfr_check( FT_Face  face )
+  {
+    FT_Service_PfrMetrics  service = NULL;
+
+
+    if ( face )
+      FT_FACE_LOOKUP_SERVICE( face, service, PFR_METRICS );
+
+    return service;
+  }
+
+
+  /* documentation is in ftpfr.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_PFR_Metrics( FT_Face    face,
+                      FT_UInt   *aoutline_resolution,
+                      FT_UInt   *ametrics_resolution,
+                      FT_Fixed  *ametrics_x_scale,
+                      FT_Fixed  *ametrics_y_scale )
+  {
+    FT_Error               error = FT_Err_Ok;
+    FT_Service_PfrMetrics  service;
+
+
+    if ( !face )
+      return FT_THROW( Invalid_Face_Handle );
+
+    service = ft_pfr_check( face );
+    if ( service )
+    {
+      error = service->get_metrics( face,
+                                    aoutline_resolution,
+                                    ametrics_resolution,
+                                    ametrics_x_scale,
+                                    ametrics_y_scale );
+    }
+    else
+    {
+      FT_Fixed  x_scale, y_scale;
+
+
+      /* this is not a PFR font */
+      if ( aoutline_resolution )
+        *aoutline_resolution = face->units_per_EM;
+
+      if ( ametrics_resolution )
+        *ametrics_resolution = face->units_per_EM;
+
+      x_scale = y_scale = 0x10000L;
+      if ( face->size )
+      {
+        x_scale = face->size->metrics.x_scale;
+        y_scale = face->size->metrics.y_scale;
+      }
+
+      if ( ametrics_x_scale )
+        *ametrics_x_scale = x_scale;
+
+      if ( ametrics_y_scale )
+        *ametrics_y_scale = y_scale;
+
+      error = FT_THROW( Unknown_File_Format );
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in ftpfr.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_PFR_Kerning( FT_Face     face,
+                      FT_UInt     left,
+                      FT_UInt     right,
+                      FT_Vector  *avector )
+  {
+    FT_Error               error;
+    FT_Service_PfrMetrics  service;
+
+
+    if ( !face )
+      return FT_THROW( Invalid_Face_Handle );
+
+    if ( !avector )
+      return FT_THROW( Invalid_Argument );
+
+    service = ft_pfr_check( face );
+    if ( service )
+      error = service->get_kerning( face, left, right, avector );
+    else
+      error = FT_Get_Kerning( face, left, right,
+                              FT_KERNING_UNSCALED, avector );
+
+    return error;
+  }
+
+
+  /* documentation is in ftpfr.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_PFR_Advance( FT_Face   face,
+                      FT_UInt   gindex,
+                      FT_Pos   *aadvance )
+  {
+    FT_Error               error;
+    FT_Service_PfrMetrics  service;
+
+
+    if ( !face )
+      return FT_THROW( Invalid_Face_Handle );
+
+    if ( !aadvance )
+      return FT_THROW( Invalid_Argument );
+
+    service = ft_pfr_check( face );
+    if ( service )
+      error = service->get_advance( face, gindex, aadvance );
+    else
+      /* XXX: TODO: PROVIDE ADVANCE-LOADING METHOD TO ALL FONT DRIVERS */
+      error = FT_THROW( Invalid_Argument );
+
+    return error;
+  }
+
+
+/* END */
diff --git a/src/base/ftrfork.c b/src/base/ftrfork.c
index 82d54f8..c30c766 100644
--- a/src/base/ftrfork.c
+++ b/src/base/ftrfork.c
@@ -71,24 +71,35 @@
     if ( error )
       return error;
 
-    *rdata_pos = rfork_offset + ( ( head[0] << 24 ) |
-                                  ( head[1] << 16 ) |
-                                  ( head[2] <<  8 ) |
-                                    head[3]         );
-    map_pos    = rfork_offset + ( ( head[4] << 24 ) |
-                                  ( head[5] << 16 ) |
-                                  ( head[6] <<  8 ) |
-                                    head[7]         );
-    rdata_len = ( head[ 8] << 24 ) |
-                ( head[ 9] << 16 ) |
-                ( head[10] <<  8 ) |
-                  head[11];
+    /* ensure positive values */
+    if ( head[0] >= 0x80 || head[4] >= 0x80 || head[8] >= 0x80 )
+      return FT_THROW( Unknown_File_Format );
+
+    *rdata_pos = ( head[ 0] << 24 ) |
+                 ( head[ 1] << 16 ) |
+                 ( head[ 2] <<  8 ) |
+                   head[ 3];
+    map_pos    = ( head[ 4] << 24 ) |
+                 ( head[ 5] << 16 ) |
+                 ( head[ 6] <<  8 ) |
+                   head[ 7];
+    rdata_len  = ( head[ 8] << 24 ) |
+                 ( head[ 9] << 16 ) |
+                 ( head[10] <<  8 ) |
+                   head[11];
 
     /* map_len = head[12] .. head[15] */
 
-    if ( *rdata_pos + rdata_len != map_pos || map_pos == rfork_offset )
+    if ( *rdata_pos != map_pos - rdata_len || map_pos == 0 )
       return FT_THROW( Unknown_File_Format );
 
+    if ( FT_LONG_MAX - rfork_offset < *rdata_pos ||
+         FT_LONG_MAX - rfork_offset < map_pos    )
+      return FT_THROW( Unknown_File_Format );
+
+    *rdata_pos += rfork_offset;
+    map_pos    += rfork_offset;
+
     error = FT_Stream_Seek( stream, (FT_ULong)map_pos );
     if ( error )
       return error;
diff --git a/src/base/ftstroke.c b/src/base/ftstroke.c
index 842ee30..fecb3cc 100644
--- a/src/base/ftstroke.c
+++ b/src/base/ftstroke.c
@@ -24,6 +24,16 @@
 #include FT_INTERNAL_DEBUG_H
 #include FT_INTERNAL_OBJECTS_H
 
+#include "basepic.h"
+
+
+  /* declare an extern to access `ft_outline_glyph_class' globally     */
+  /* allocated  in `ftglyph.c', and use the FT_OUTLINE_GLYPH_CLASS_GET */
+  /* macro to access it when FT_CONFIG_OPTION_PIC is defined           */
+#ifndef FT_CONFIG_OPTION_PIC
+  FT_CALLBACK_TABLE const FT_Glyph_Class  ft_outline_glyph_class;
+#endif
+
 
   /* documentation is in ftstroke.h */
 
@@ -2285,15 +2295,6 @@
   }
 
 
-  /* declare an extern to access `ft_outline_glyph_class' globally     */
-  /* allocated  in `ftglyph.c', and use the FT_OUTLINE_GLYPH_CLASS_GET */
-  /* macro to access it when FT_CONFIG_OPTION_PIC is defined           */
-#ifndef FT_CONFIG_OPTION_PIC
-  extern const FT_Glyph_Class  ft_outline_glyph_class;
-#endif
-#include "basepic.h"
-
-
   /* documentation is in ftstroke.h */
 
   FT_EXPORT_DEF( FT_Error )
diff --git a/src/cache/ftcache.c b/src/cache/ftcache.c
new file mode 100644
index 0000000..8de527a
--- /dev/null
+++ b/src/cache/ftcache.c
@@ -0,0 +1,31 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcache.c                                                              */
+/*                                                                         */
+/*    The FreeType Caching sub-system (body only).                         */
+/*                                                                         */
+/*  Copyright 2000-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftcmru.c"
+#include "ftcmanag.c"
+#include "ftccache.c"
+#include "ftccmap.c"
+#include "ftcglyph.c"
+#include "ftcimage.c"
+#include "ftcsbits.c"
+#include "ftcbasic.c"
+
+/* END */
diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c
index d8c5b99..b82a789 100644
--- a/src/cache/ftccache.c
+++ b/src/cache/ftccache.c
@@ -576,7 +576,7 @@
       FTC_Node*  pnode  = bucket;
 
 
-      for ( ;; )
+      for (;;)
       {
         FTC_Node  node = *pnode;
         FT_Bool   list_changed = FALSE;
diff --git a/src/cache/ftcerror.h b/src/cache/ftcerror.h
new file mode 100644
index 0000000..15adec5
--- /dev/null
+++ b/src/cache/ftcerror.h
@@ -0,0 +1,41 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcerror.h                                                             */
+/*                                                                         */
+/*    Caching sub-system error codes (specification only).                 */
+/*                                                                         */
+/*  Copyright 2001-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the caching sub-system error enumeration  */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __FTCERROR_H__
+#define __FTCERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#undef  FT_ERR_PREFIX
+#define FT_ERR_PREFIX  FTC_Err_
+#define FT_ERR_BASE    FT_Mod_Err_Cache
+
+#include FT_ERRORS_H
+
+#endif /* __FTCERROR_H__ */
+
+/* END */
diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c
new file mode 100644
index 0000000..f519a61
--- /dev/null
+++ b/src/cache/ftcimage.c
@@ -0,0 +1,164 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcimage.c                                                             */
+/*                                                                         */
+/*    FreeType Image cache (body).                                         */
+/*                                                                         */
+/*  Copyright 2000-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include "ftcimage.h"
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "ftccback.h"
+#include "ftcerror.h"
+
+
+  /* finalize a given glyph image node */
+  FT_LOCAL_DEF( void )
+  ftc_inode_free( FTC_Node   ftcinode,
+                  FTC_Cache  cache )
+  {
+    FTC_INode  inode = (FTC_INode)ftcinode;
+    FT_Memory  memory = cache->memory;
+
+
+    if ( inode->glyph )
+    {
+      FT_Done_Glyph( inode->glyph );
+      inode->glyph = NULL;
+    }
+
+    FTC_GNode_Done( FTC_GNODE( inode ), cache );
+    FT_FREE( inode );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  FTC_INode_Free( FTC_INode  inode,
+                  FTC_Cache  cache )
+  {
+    ftc_inode_free( FTC_NODE( inode ), cache );
+  }
+
+
+  /* initialize a new glyph image node */
+  FT_LOCAL_DEF( FT_Error )
+  FTC_INode_New( FTC_INode   *pinode,
+                 FTC_GQuery   gquery,
+                 FTC_Cache    cache )
+  {
+    FT_Memory  memory = cache->memory;
+    FT_Error   error;
+    FTC_INode  inode  = NULL;
+
+
+    if ( !FT_NEW( inode ) )
+    {
+      FTC_GNode         gnode  = FTC_GNODE( inode );
+      FTC_Family        family = gquery->family;
+      FT_UInt           gindex = gquery->gindex;
+      FTC_IFamilyClass  clazz  = FTC_CACHE__IFAMILY_CLASS( cache );
+
+
+      /* initialize its inner fields */
+      FTC_GNode_Init( gnode, gindex, family );
+
+      /* we will now load the glyph image */
+      error = clazz->family_load_glyph( family, gindex, cache,
+                                        &inode->glyph );
+      if ( error )
+      {
+        FTC_INode_Free( inode, cache );
+        inode = NULL;
+      }
+    }
+
+    *pinode = inode;
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  ftc_inode_new( FTC_Node   *ftcpinode,
+                 FT_Pointer  ftcgquery,
+                 FTC_Cache   cache )
+  {
+    FTC_INode  *pinode = (FTC_INode*)ftcpinode;
+    FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
+
+
+    return FTC_INode_New( pinode, gquery, cache );
+  }
+
+
+  FT_LOCAL_DEF( FT_Offset )
+  ftc_inode_weight( FTC_Node   ftcinode,
+                    FTC_Cache  ftccache )
+  {
+    FTC_INode  inode = (FTC_INode)ftcinode;
+    FT_Offset  size  = 0;
+    FT_Glyph   glyph = inode->glyph;
+
+    FT_UNUSED( ftccache );
+
+
+    switch ( glyph->format )
+    {
+    case FT_GLYPH_FORMAT_BITMAP:
+      {
+        FT_BitmapGlyph  bitg;
+
+
+        bitg = (FT_BitmapGlyph)glyph;
+        size = bitg->bitmap.rows * (FT_Offset)FT_ABS( bitg->bitmap.pitch ) +
+               sizeof ( *bitg );
+      }
+      break;
+
+    case FT_GLYPH_FORMAT_OUTLINE:
+      {
+        FT_OutlineGlyph  outg;
+
+
+        outg = (FT_OutlineGlyph)glyph;
+        size = (FT_Offset)outg->outline.n_points *
+                 ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) +
+               (FT_Offset)outg->outline.n_contours * sizeof ( FT_Short ) +
+               sizeof ( *outg );
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    size += sizeof ( *inode );
+    return size;
+  }
+
+
+#if 0
+
+  FT_LOCAL_DEF( FT_Offset )
+  FTC_INode_Weight( FTC_INode  inode )
+  {
+    return ftc_inode_weight( FTC_NODE( inode ), NULL );
+  }
+
+#endif /* 0 */
+
+
+/* END */
diff --git a/src/cache/ftcimage.h b/src/cache/ftcimage.h
new file mode 100644
index 0000000..b312eaa
--- /dev/null
+++ b/src/cache/ftcimage.h
@@ -0,0 +1,107 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcimage.h                                                             */
+/*                                                                         */
+/*    FreeType Generic Image cache (specification)                         */
+/*                                                                         */
+/*  Copyright 2000-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+ /*
+  *  FTC_ICache is an _abstract_ cache used to store a single FT_Glyph
+  *  image per cache node.
+  *
+  *  FTC_ICache extends FTC_GCache.  For an implementation example,
+  *  see FTC_ImageCache in `src/cache/ftbasic.c'.
+  */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Each image cache really manages FT_Glyph objects.                     */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#ifndef __FTCIMAGE_H__
+#define __FTCIMAGE_H__
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include "ftcglyph.h"
+
+FT_BEGIN_HEADER
+
+
+  /* the FT_Glyph image node type - we store only 1 glyph per node */
+  typedef struct  FTC_INodeRec_
+  {
+    FTC_GNodeRec  gnode;
+    FT_Glyph      glyph;
+
+  } FTC_INodeRec, *FTC_INode;
+
+#define FTC_INODE( x )         ( (FTC_INode)( x ) )
+#define FTC_INODE_GINDEX( x )  FTC_GNODE(x)->gindex
+#define FTC_INODE_FAMILY( x )  FTC_GNODE(x)->family
+
+  typedef FT_Error
+  (*FTC_IFamily_LoadGlyphFunc)( FTC_Family  family,
+                                FT_UInt     gindex,
+                                FTC_Cache   cache,
+                                FT_Glyph   *aglyph );
+
+  typedef struct  FTC_IFamilyClassRec_
+  {
+    FTC_MruListClassRec        clazz;
+    FTC_IFamily_LoadGlyphFunc  family_load_glyph;
+
+  } FTC_IFamilyClassRec;
+
+  typedef const FTC_IFamilyClassRec*  FTC_IFamilyClass;
+
+#define FTC_IFAMILY_CLASS( x )  ((FTC_IFamilyClass)(x))
+
+#define FTC_CACHE__IFAMILY_CLASS( x ) \
+          FTC_IFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS(x)->family_class )
+
+
+  /* can be used as a @FTC_Node_FreeFunc */
+  FT_LOCAL( void )
+  FTC_INode_Free( FTC_INode  inode,
+                  FTC_Cache  cache );
+
+  /* Can be used as @FTC_Node_NewFunc.  `gquery.index' and `gquery.family'
+   * must be set correctly.  This function will call the `family_load_glyph'
+   * method to load the FT_Glyph into the cache node.
+   */
+  FT_LOCAL( FT_Error )
+  FTC_INode_New( FTC_INode   *pinode,
+                 FTC_GQuery   gquery,
+                 FTC_Cache    cache );
+
+#if 0
+  /* can be used as @FTC_Node_WeightFunc */
+  FT_LOCAL( FT_ULong )
+  FTC_INode_Weight( FTC_INode  inode );
+#endif
+
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* __FTCIMAGE_H__ */
+
+
+/* END */
diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c
new file mode 100644
index 0000000..658614c
--- /dev/null
+++ b/src/cache/ftcmanag.c
@@ -0,0 +1,703 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcmanag.c                                                             */
+/*                                                                         */
+/*    FreeType Cache Manager (body).                                       */
+/*                                                                         */
+/*  Copyright 2000-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include "ftcmanag.h"
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SIZES_H
+
+#include "ftccback.h"
+#include "ftcerror.h"
+
+#ifdef FT_CONFIG_OPTION_PIC
+#error "cache system does not support PIC yet"
+#endif
+
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cache
+
+
+  static FT_Error
+  ftc_scaler_lookup_size( FTC_Manager  manager,
+                          FTC_Scaler   scaler,
+                          FT_Size     *asize )
+  {
+    FT_Face   face;
+    FT_Size   size = NULL;
+    FT_Error  error;
+
+
+    error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
+    if ( error )
+      goto Exit;
+
+    error = FT_New_Size( face, &size );
+    if ( error )
+      goto Exit;
+
+    FT_Activate_Size( size );
+
+    if ( scaler->pixel )
+      error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
+    else
+      error = FT_Set_Char_Size( face,
+                                (FT_F26Dot6)scaler->width,
+                                (FT_F26Dot6)scaler->height,
+                                scaler->x_res,
+                                scaler->y_res );
+    if ( error )
+    {
+      FT_Done_Size( size );
+      size = NULL;
+    }
+
+  Exit:
+    *asize = size;
+    return error;
+  }
+
+
+  typedef struct  FTC_SizeNodeRec_
+  {
+    FTC_MruNodeRec  node;
+    FT_Size         size;
+    FTC_ScalerRec   scaler;
+
+  } FTC_SizeNodeRec, *FTC_SizeNode;
+
+#define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )
+
+
+  FT_CALLBACK_DEF( void )
+  ftc_size_node_done( FTC_MruNode  ftcnode,
+                      FT_Pointer   data )
+  {
+    FTC_SizeNode  node = (FTC_SizeNode)ftcnode;
+    FT_Size       size = node->size;
+    FT_UNUSED( data );
+
+
+    if ( size )
+      FT_Done_Size( size );
+  }
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_size_node_compare( FTC_MruNode  ftcnode,
+                         FT_Pointer   ftcscaler )
+  {
+    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
+    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
+    FTC_Scaler    scaler0 = &node->scaler;
+
+
+    if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
+    {
+      FT_Activate_Size( node->size );
+      return 1;
+    }
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_size_node_init( FTC_MruNode  ftcnode,
+                      FT_Pointer   ftcscaler,
+                      FT_Pointer   ftcmanager )
+  {
+    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
+    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
+    FTC_Manager   manager = (FTC_Manager)ftcmanager;
+
+
+    node->scaler = scaler[0];
+
+    return ftc_scaler_lookup_size( manager, scaler, &node->size );
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_size_node_reset( FTC_MruNode  ftcnode,
+                       FT_Pointer   ftcscaler,
+                       FT_Pointer   ftcmanager )
+  {
+    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
+    FTC_Scaler    scaler  = (FTC_Scaler)ftcscaler;
+    FTC_Manager   manager = (FTC_Manager)ftcmanager;
+
+
+    FT_Done_Size( node->size );
+
+    node->scaler = scaler[0];
+
+    return ftc_scaler_lookup_size( manager, scaler, &node->size );
+  }
+
+
+  static
+  const FTC_MruListClassRec  ftc_size_list_class =
+  {
+    sizeof ( FTC_SizeNodeRec ),
+    ftc_size_node_compare,
+    ftc_size_node_init,
+    ftc_size_node_reset,
+    ftc_size_node_done
+  };
+
+
+  /* helper function used by ftc_face_node_done */
+  static FT_Bool
+  ftc_size_node_compare_faceid( FTC_MruNode  ftcnode,
+                                FT_Pointer   ftcface_id )
+  {
+    FTC_SizeNode  node    = (FTC_SizeNode)ftcnode;
+    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
+
+
+    return FT_BOOL( node->scaler.face_id == face_id );
+  }
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Manager_LookupSize( FTC_Manager  manager,
+                          FTC_Scaler   scaler,
+                          FT_Size     *asize )
+  {
+    FT_Error     error;
+    FTC_MruNode  mrunode;
+
+
+    if ( !asize || !scaler )
+      return FT_THROW( Invalid_Argument );
+
+    *asize = NULL;
+
+    if ( !manager )
+      return FT_THROW( Invalid_Cache_Handle );
+
+#ifdef FTC_INLINE
+
+    FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
+                            mrunode, error );
+
+#else
+    error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode );
+#endif
+
+    if ( !error )
+      *asize = FTC_SIZE_NODE( mrunode )->size;
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    FACE MRU IMPLEMENTATION                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct  FTC_FaceNodeRec_
+  {
+    FTC_MruNodeRec  node;
+    FTC_FaceID      face_id;
+    FT_Face         face;
+
+  } FTC_FaceNodeRec, *FTC_FaceNode;
+
+#define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_face_node_init( FTC_MruNode  ftcnode,
+                      FT_Pointer   ftcface_id,
+                      FT_Pointer   ftcmanager )
+  {
+    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
+    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
+    FTC_Manager   manager = (FTC_Manager)ftcmanager;
+    FT_Error      error;
+
+
+    node->face_id = face_id;
+
+    error = manager->request_face( face_id,
+                                   manager->library,
+                                   manager->request_data,
+                                   &node->face );
+    if ( !error )
+    {
+      /* destroy initial size object; it will be re-created later */
+      if ( node->face->size )
+        FT_Done_Size( node->face->size );
+    }
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ftc_face_node_done( FTC_MruNode  ftcnode,
+                      FT_Pointer   ftcmanager )
+  {
+    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
+    FTC_Manager   manager = (FTC_Manager)ftcmanager;
+
+
+    /* we must begin by removing all scalers for the target face */
+    /* from the manager's list                                   */
+    FTC_MruList_RemoveSelection( &manager->sizes,
+                                 ftc_size_node_compare_faceid,
+                                 node->face_id );
+
+    /* all right, we can discard the face now */
+    FT_Done_Face( node->face );
+    node->face    = NULL;
+    node->face_id = NULL;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_face_node_compare( FTC_MruNode  ftcnode,
+                         FT_Pointer   ftcface_id )
+  {
+    FTC_FaceNode  node    = (FTC_FaceNode)ftcnode;
+    FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
+
+
+    return FT_BOOL( node->face_id == face_id );
+  }
+
+
+  static
+  const FTC_MruListClassRec  ftc_face_list_class =
+  {
+    sizeof ( FTC_FaceNodeRec),
+
+    ftc_face_node_compare,
+    ftc_face_node_init,
+    0,                          /* FTC_MruNode_ResetFunc */
+    ftc_face_node_done
+  };
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Manager_LookupFace( FTC_Manager  manager,
+                          FTC_FaceID   face_id,
+                          FT_Face     *aface )
+  {
+    FT_Error     error;
+    FTC_MruNode  mrunode;
+
+
+    if ( !aface || !face_id )
+      return FT_THROW( Invalid_Argument );
+
+    *aface = NULL;
+
+    if ( !manager )
+      return FT_THROW( Invalid_Cache_Handle );
+
+    /* we break encapsulation for the sake of speed */
+#ifdef FTC_INLINE
+
+    FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
+                            mrunode, error );
+
+#else
+    error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode );
+#endif
+
+    if ( !error )
+      *aface = FTC_FACE_NODE( mrunode )->face;
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    CACHE MANAGER ROUTINES                     *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Manager_New( FT_Library          library,
+                   FT_UInt             max_faces,
+                   FT_UInt             max_sizes,
+                   FT_ULong            max_bytes,
+                   FTC_Face_Requester  requester,
+                   FT_Pointer          req_data,
+                   FTC_Manager        *amanager )
+  {
+    FT_Error     error;
+    FT_Memory    memory;
+    FTC_Manager  manager = 0;
+
+
+    if ( !library )
+      return FT_THROW( Invalid_Library_Handle );
+
+    if ( !amanager || !requester )
+      return FT_THROW( Invalid_Argument );
+
+    memory = library->memory;
+
+    if ( FT_NEW( manager ) )
+      goto Exit;
+
+    if ( max_faces == 0 )
+      max_faces = FTC_MAX_FACES_DEFAULT;
+
+    if ( max_sizes == 0 )
+      max_sizes = FTC_MAX_SIZES_DEFAULT;
+
+    if ( max_bytes == 0 )
+      max_bytes = FTC_MAX_BYTES_DEFAULT;
+
+    manager->library      = library;
+    manager->memory       = memory;
+    manager->max_weight   = max_bytes;
+
+    manager->request_face = requester;
+    manager->request_data = req_data;
+
+    FTC_MruList_Init( &manager->faces,
+                      &ftc_face_list_class,
+                      max_faces,
+                      manager,
+                      memory );
+
+    FTC_MruList_Init( &manager->sizes,
+                      &ftc_size_list_class,
+                      max_sizes,
+                      manager,
+                      memory );
+
+    *amanager = manager;
+
+  Exit:
+    return error;
+  }
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Manager_Done( FTC_Manager  manager )
+  {
+    FT_Memory  memory;
+    FT_UInt    idx;
+
+
+    if ( !manager || !manager->library )
+      return;
+
+    memory = manager->memory;
+
+    /* now discard all caches */
+    for (idx = manager->num_caches; idx-- > 0; )
+    {
+      FTC_Cache  cache = manager->caches[idx];
+
+
+      if ( cache )
+      {
+        cache->clazz.cache_done( cache );
+        FT_FREE( cache );
+        manager->caches[idx] = NULL;
+      }
+    }
+    manager->num_caches = 0;
+
+    /* discard faces and sizes */
+    FTC_MruList_Done( &manager->sizes );
+    FTC_MruList_Done( &manager->faces );
+
+    manager->library = NULL;
+    manager->memory  = NULL;
+
+    FT_FREE( manager );
+  }
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Manager_Reset( FTC_Manager  manager )
+  {
+    if ( !manager )
+      return;
+
+    FTC_MruList_Reset( &manager->sizes );
+    FTC_MruList_Reset( &manager->faces );
+
+    FTC_Manager_FlushN( manager, manager->num_nodes );
+  }
+
+
+#ifdef FT_DEBUG_ERROR
+
+  static void
+  FTC_Manager_Check( FTC_Manager  manager )
+  {
+    FTC_Node  node, first;
+
+
+    first = manager->nodes_list;
+
+    /* check node weights */
+    if ( first )
+    {
+      FT_Offset  weight = 0;
+
+
+      node = first;
+
+      do
+      {
+        FTC_Cache  cache = manager->caches[node->cache_index];
+
+
+        if ( (FT_UInt)node->cache_index >= manager->num_caches )
+          FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
+                      node->cache_index ));
+        else
+          weight += cache->clazz.node_weight( node, cache );
+
+        node = FTC_NODE__NEXT( node );
+
+      } while ( node != first );
+
+      if ( weight != manager->cur_weight )
+        FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
+                    manager->cur_weight, weight ));
+    }
+
+    /* check circular list */
+    if ( first )
+    {
+      FT_UFast  count = 0;
+
+
+      node = first;
+      do
+      {
+        count++;
+        node = FTC_NODE__NEXT( node );
+
+      } while ( node != first );
+
+      if ( count != manager->num_nodes )
+        FT_TRACE0(( "FTC_Manager_Check:"
+                    " invalid cache node count %d instead of %d\n",
+                    manager->num_nodes, count ));
+    }
+  }
+
+#endif /* FT_DEBUG_ERROR */
+
+
+  /* `Compress' the manager's data, i.e., get rid of old cache nodes */
+  /* that are not referenced anymore in order to limit the total     */
+  /* memory used by the cache.                                       */
+
+  /* documentation is in ftcmanag.h */
+
+  FT_LOCAL_DEF( void )
+  FTC_Manager_Compress( FTC_Manager  manager )
+  {
+    FTC_Node   node, first;
+
+
+    if ( !manager )
+      return;
+
+    first = manager->nodes_list;
+
+#ifdef FT_DEBUG_ERROR
+    FTC_Manager_Check( manager );
+
+    FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
+                manager->cur_weight, manager->max_weight,
+                manager->num_nodes ));
+#endif
+
+    if ( manager->cur_weight < manager->max_weight || first == NULL )
+      return;
+
+    /* go to last node -- it's a circular list */
+    node = FTC_NODE__PREV( first );
+    do
+    {
+      FTC_Node  prev;
+
+
+      prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );
+
+      if ( node->ref_count <= 0 )
+        ftc_node_destroy( node, manager );
+
+      node = prev;
+
+    } while ( node && manager->cur_weight > manager->max_weight );
+  }
+
+
+  /* documentation is in ftcmanag.h */
+
+  FT_LOCAL_DEF( FT_Error )
+  FTC_Manager_RegisterCache( FTC_Manager      manager,
+                             FTC_CacheClass   clazz,
+                             FTC_Cache       *acache )
+  {
+    FT_Error   error = FT_ERR( Invalid_Argument );
+    FTC_Cache  cache = NULL;
+
+
+    if ( manager && clazz && acache )
+    {
+      FT_Memory  memory = manager->memory;
+
+
+      if ( manager->num_caches >= FTC_MAX_CACHES )
+      {
+        error = FT_THROW( Too_Many_Caches );
+        FT_ERROR(( "FTC_Manager_RegisterCache:"
+                   " too many registered caches\n" ));
+        goto Exit;
+      }
+
+      if ( !FT_ALLOC( cache, clazz->cache_size ) )
+      {
+        cache->manager   = manager;
+        cache->memory    = memory;
+        cache->clazz     = clazz[0];
+        cache->org_class = clazz;
+
+        /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
+        /* IF IT IS NOT SET CORRECTLY                          */
+        cache->index = manager->num_caches;
+
+        error = clazz->cache_init( cache );
+        if ( error )
+        {
+          clazz->cache_done( cache );
+          FT_FREE( cache );
+          goto Exit;
+        }
+
+        manager->caches[manager->num_caches++] = cache;
+      }
+    }
+
+  Exit:
+    if ( acache )
+      *acache = cache;
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_UInt )
+  FTC_Manager_FlushN( FTC_Manager  manager,
+                      FT_UInt      count )
+  {
+    FTC_Node  first = manager->nodes_list;
+    FTC_Node  node;
+    FT_UInt   result;
+
+
+    /* try to remove `count' nodes from the list */
+    if ( first == NULL )  /* empty list! */
+      return 0;
+
+    /* go to last node - it's a circular list */
+    node = FTC_NODE__PREV(first);
+    for ( result = 0; result < count; )
+    {
+      FTC_Node  prev = FTC_NODE__PREV( node );
+
+
+      /* don't touch locked nodes */
+      if ( node->ref_count <= 0 )
+      {
+        ftc_node_destroy( node, manager );
+        result++;
+      }
+
+      if ( node == first )
+        break;
+
+      node = prev;
+    }
+    return  result;
+  }
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Manager_RemoveFaceID( FTC_Manager  manager,
+                            FTC_FaceID   face_id )
+  {
+    FT_UInt  nn;
+
+
+    if ( !manager || !face_id )
+      return;
+
+    /* this will remove all FTC_SizeNode that correspond to
+     * the face_id as well
+     */
+    FTC_MruList_RemoveSelection( &manager->faces,
+                                 ftc_face_node_compare,
+                                 face_id );
+
+    for ( nn = 0; nn < manager->num_caches; nn++ )
+      FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
+  }
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Node_Unref( FTC_Node     node,
+                  FTC_Manager  manager )
+  {
+    if ( node                                             &&
+         manager                                          &&
+         (FT_UInt)node->cache_index < manager->num_caches )
+      node->ref_count--;
+  }
+
+
+/* END */
diff --git a/src/cache/ftcmru.h b/src/cache/ftcmru.h
new file mode 100644
index 0000000..c0c35f9
--- /dev/null
+++ b/src/cache/ftcmru.h
@@ -0,0 +1,246 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcmru.h                                                               */
+/*                                                                         */
+/*    Simple MRU list-cache (specification).                               */
+/*                                                                         */
+/*  Copyright 2000-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* An MRU is a list that cannot hold more than a certain number of       */
+  /* elements (`max_elements').  All elements in the list are sorted in    */
+  /* least-recently-used order, i.e., the `oldest' element is at the tail  */
+  /* of the list.                                                          */
+  /*                                                                       */
+  /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'),   */
+  /* the list is searched for an element with the corresponding key.  If   */
+  /* it is found, the element is moved to the head of the list and is      */
+  /* returned.                                                             */
+  /*                                                                       */
+  /* If no corresponding element is found, the lookup routine will try to  */
+  /* obtain a new element with the relevant key.  If the list is already   */
+  /* full, the oldest element from the list is discarded and replaced by a */
+  /* new one; a new element is added to the list otherwise.                */
+  /*                                                                       */
+  /* Note that it is possible to pre-allocate the element list nodes.      */
+  /* This is handy if `max_elements' is sufficiently small, as it saves    */
+  /* allocations/releases during the lookup process.                       */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#ifndef __FTCMRU_H__
+#define __FTCMRU_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#ifdef FREETYPE_H
+#error "freetype.h of FreeType 1 has been loaded!"
+#error "Please fix the directory search order for header files"
+#error "so that freetype.h of FreeType 2 is found first."
+#endif
+
+#define  xxFT_DEBUG_ERROR
+#define  FTC_INLINE
+
+FT_BEGIN_HEADER
+
+  typedef struct FTC_MruNodeRec_*  FTC_MruNode;
+
+  typedef struct  FTC_MruNodeRec_
+  {
+    FTC_MruNode  next;
+    FTC_MruNode  prev;
+
+  } FTC_MruNodeRec;
+
+
+  FT_LOCAL( void )
+  FTC_MruNode_Prepend( FTC_MruNode  *plist,
+                       FTC_MruNode   node );
+
+  FT_LOCAL( void )
+  FTC_MruNode_Up( FTC_MruNode  *plist,
+                  FTC_MruNode   node );
+
+  FT_LOCAL( void )
+  FTC_MruNode_Remove( FTC_MruNode  *plist,
+                      FTC_MruNode   node );
+
+
+  typedef struct FTC_MruListRec_*              FTC_MruList;
+
+  typedef struct FTC_MruListClassRec_ const *  FTC_MruListClass;
+
+
+  typedef FT_Bool
+  (*FTC_MruNode_CompareFunc)( FTC_MruNode  node,
+                              FT_Pointer   key );
+
+  typedef FT_Error
+  (*FTC_MruNode_InitFunc)( FTC_MruNode  node,
+                           FT_Pointer   key,
+                           FT_Pointer   data );
+
+  typedef FT_Error
+  (*FTC_MruNode_ResetFunc)( FTC_MruNode  node,
+                            FT_Pointer   key,
+                            FT_Pointer   data );
+
+  typedef void
+  (*FTC_MruNode_DoneFunc)( FTC_MruNode  node,
+                           FT_Pointer   data );
+
+
+  typedef struct  FTC_MruListClassRec_
+  {
+    FT_Offset                node_size;
+    FTC_MruNode_CompareFunc  node_compare;
+    FTC_MruNode_InitFunc     node_init;
+    FTC_MruNode_ResetFunc    node_reset;
+    FTC_MruNode_DoneFunc     node_done;
+
+  } FTC_MruListClassRec;
+
+  typedef struct  FTC_MruListRec_
+  {
+    FT_UInt              num_nodes;
+    FT_UInt              max_nodes;
+    FTC_MruNode          nodes;
+    FT_Pointer           data;
+    FTC_MruListClassRec  clazz;
+    FT_Memory            memory;
+
+  } FTC_MruListRec;
+
+
+  FT_LOCAL( void )
+  FTC_MruList_Init( FTC_MruList       list,
+                    FTC_MruListClass  clazz,
+                    FT_UInt           max_nodes,
+                    FT_Pointer        data,
+                    FT_Memory         memory );
+
+  FT_LOCAL( void )
+  FTC_MruList_Reset( FTC_MruList  list );
+
+
+  FT_LOCAL( void )
+  FTC_MruList_Done( FTC_MruList  list );
+
+
+  FT_LOCAL( FT_Error )
+  FTC_MruList_New( FTC_MruList   list,
+                   FT_Pointer    key,
+                   FTC_MruNode  *anode );
+
+  FT_LOCAL( void )
+  FTC_MruList_Remove( FTC_MruList  list,
+                      FTC_MruNode  node );
+
+  FT_LOCAL( void )
+  FTC_MruList_RemoveSelection( FTC_MruList              list,
+                               FTC_MruNode_CompareFunc  selection,
+                               FT_Pointer               key );
+
+
+#ifdef FTC_INLINE
+
+#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error )           \
+  FT_BEGIN_STMNT                                                            \
+    FTC_MruNode*             _pfirst  = &(list)->nodes;                     \
+    FTC_MruNode_CompareFunc  _compare = (FTC_MruNode_CompareFunc)(compare); \
+    FTC_MruNode              _first, _node;                                 \
+                                                                            \
+                                                                            \
+    error  = FT_Err_Ok;                                                     \
+    _first = *(_pfirst);                                                    \
+    _node  = NULL;                                                          \
+                                                                            \
+    if ( _first )                                                           \
+    {                                                                       \
+      _node = _first;                                                       \
+      do                                                                    \
+      {                                                                     \
+        if ( _compare( _node, (key) ) )                                     \
+        {                                                                   \
+          if ( _node != _first )                                            \
+            FTC_MruNode_Up( _pfirst, _node );                               \
+                                                                            \
+          node = _node;                                                     \
+          goto _MruOk;                                                      \
+        }                                                                   \
+        _node = _node->next;                                                \
+                                                                            \
+      } while ( _node != _first) ;                                          \
+    }                                                                       \
+                                                                            \
+    error = FTC_MruList_New( (list), (key), (FTC_MruNode*)(void*)&(node) ); \
+  _MruOk:                                                                   \
+    ;                                                                       \
+  FT_END_STMNT
+
+#define FTC_MRULIST_LOOKUP( list, key, node, error ) \
+  FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error )
+
+#else  /* !FTC_INLINE */
+
+  FT_LOCAL( FTC_MruNode )
+  FTC_MruList_Find( FTC_MruList  list,
+                    FT_Pointer   key );
+
+  FT_LOCAL( FT_Error )
+  FTC_MruList_Lookup( FTC_MruList   list,
+                      FT_Pointer    key,
+                      FTC_MruNode  *pnode );
+
+#define FTC_MRULIST_LOOKUP( list, key, node, error ) \
+  error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) )
+
+#endif /* !FTC_INLINE */
+
+
+#define FTC_MRULIST_LOOP( list, node )        \
+  FT_BEGIN_STMNT                              \
+    FTC_MruNode  _first = (list)->nodes;      \
+                                              \
+                                              \
+    if ( _first )                             \
+    {                                         \
+      FTC_MruNode  _node = _first;            \
+                                              \
+                                              \
+      do                                      \
+      {                                       \
+        *(FTC_MruNode*)&(node) = _node;
+
+
+#define FTC_MRULIST_LOOP_END()               \
+        _node = _node->next;                 \
+                                             \
+      } while ( _node != _first );           \
+    }                                        \
+  FT_END_STMNT
+
+ /* */
+
+FT_END_HEADER
+
+
+#endif /* __FTCMRU_H__ */
+
+
+/* END */
diff --git a/src/cff/cf2arrst.c b/src/cff/cf2arrst.c
index 528b1fa..89f3e9f 100644
--- a/src/cff/cf2arrst.c
+++ b/src/cff/cf2arrst.c
@@ -104,7 +104,7 @@
       size_t  newSize = numElements * arrstack->sizeItem;
 
 
-      if ( numElements > LONG_MAX / arrstack->sizeItem )
+      if ( numElements > FT_LONG_MAX / arrstack->sizeItem )
         goto exit;
 
 
diff --git a/src/cff/cf2ft.c b/src/cff/cf2ft.c
index d2544a2..55f3206 100644
--- a/src/cff/cf2ft.c
+++ b/src/cff/cf2ft.c
@@ -544,14 +544,17 @@
   /* return 0 on success                                   */
   FT_LOCAL_DEF( CF2_Int )
   cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
-                              CF2_UInt      idx,
+                              CF2_Int       subrNum,
                               CF2_Buffer    buf )
   {
+    CF2_UInt  idx;
+
+
     FT_ASSERT( decoder );
 
     FT_ZERO( buf );
 
-    idx += (CF2_UInt)decoder->globals_bias;
+    idx = (CF2_UInt)( subrNum + decoder->globals_bias );
     if ( idx >= decoder->num_globals )
       return TRUE;     /* error */
 
@@ -628,14 +631,17 @@
 
   FT_LOCAL_DEF( CF2_Int )
   cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
-                             CF2_UInt      idx,
+                             CF2_Int       subrNum,
                              CF2_Buffer    buf )
   {
+    CF2_UInt  idx;
+
+
     FT_ASSERT( decoder );
 
     FT_ZERO( buf );
 
-    idx += (CF2_UInt)decoder->locals_bias;
+    idx = (CF2_UInt)( subrNum + decoder->locals_bias );
     if ( idx >= decoder->num_locals )
       return TRUE;     /* error */
 
diff --git a/src/cff/cf2ft.h b/src/cff/cf2ft.h
index 3073df3..9810511 100644
--- a/src/cff/cf2ft.h
+++ b/src/cff/cf2ft.h
@@ -99,7 +99,7 @@
 
   FT_LOCAL( CF2_Int )
   cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
-                              CF2_UInt      idx,
+                              CF2_Int       subrNum,
                               CF2_Buffer    buf );
   FT_LOCAL( FT_Error )
   cf2_getSeacComponent( CFF_Decoder*  decoder,
@@ -110,7 +110,7 @@
                          CF2_Buffer    buf );
   FT_LOCAL( CF2_Int )
   cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
-                             CF2_UInt      idx,
+                             CF2_Int       subrNum,
                              CF2_Buffer    buf );
 
   FT_LOCAL( CF2_Fixed )
diff --git a/src/cff/cf2hints.c b/src/cff/cf2hints.c
index 0e27000..bbbe8e3 100644
--- a/src/cff/cf2hints.c
+++ b/src/cff/cf2hints.c
@@ -587,8 +587,9 @@
     }
 
     /* paired edges must be in proper order */
-    FT_ASSERT( !isPair                                         ||
-               topHintEdge->csCoord >= bottomHintEdge->csCoord );
+    if ( isPair                                         &&
+         topHintEdge->csCoord < bottomHintEdge->csCoord )
+      return;
 
     /* linear search to find index value of insertion point */
     indexInsert = 0;
diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c
index 537e060..1910f1b 100644
--- a/src/cff/cf2intrp.c
+++ b/src/cff/cf2intrp.c
@@ -184,7 +184,7 @@
       return;
 
     FT_ASSERT( hintmask->byteCount > 0 );
-    FT_ASSERT( hintmask->byteCount <
+    FT_ASSERT( hintmask->byteCount <=
                  sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) );
 
     /* set mask to all ones */
@@ -746,7 +746,7 @@
       case cf2_cmdCALLGSUBR:
       case cf2_cmdCALLSUBR:
         {
-          CF2_UInt  subrIndex;
+          CF2_Int  subrNum;
 
 
           FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
@@ -766,17 +766,17 @@
                            (size_t)charstringIndex + 1 );
 
           /* set up the new CFF region and pointer */
-          subrIndex = (CF2_UInt)cf2_stack_popInt( opStack );
+          subrNum = cf2_stack_popInt( opStack );
 
           switch ( op1 )
           {
           case cf2_cmdCALLGSUBR:
             FT_TRACE4(( " (idx %d, entering level %d)\n",
-                        subrIndex + (CF2_UInt)decoder->globals_bias,
+                        subrNum + decoder->globals_bias,
                         charstringIndex + 1 ));
 
             if ( cf2_initGlobalRegionBuffer( decoder,
-                                             subrIndex,
+                                             subrNum,
                                              charstring ) )
             {
               lastError = FT_THROW( Invalid_Glyph_Format );
@@ -787,11 +787,11 @@
           default:
             /* cf2_cmdCALLSUBR */
             FT_TRACE4(( " (idx %d, entering level %d)\n",
-                        subrIndex + (CF2_UInt)decoder->locals_bias,
+                        subrNum + decoder->locals_bias,
                         charstringIndex + 1 ));
 
             if ( cf2_initLocalRegionBuffer( decoder,
-                                            subrIndex,
+                                            subrNum,
                                             charstring ) )
             {
               lastError = FT_THROW( Invalid_Glyph_Format );
@@ -1305,7 +1305,7 @@
           /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
           /* we enforce it by clearing the second bit           */
           /* (and sorting the stack indexing to suit)           */
-          count  = count1 & ~2;
+          count  = count1 & ~2U;
           index += count1 - count;
 
           FT_TRACE4(( " vvcurveto\n" ));
@@ -1350,7 +1350,7 @@
           /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
           /* we enforce it by clearing the second bit           */
           /* (and sorting the stack indexing to suit)           */
-          count  = count1 & ~2;
+          count  = count1 & ~2U;
           index += count1 - count;
 
           FT_TRACE4(( " hhcurveto\n" ));
@@ -1399,7 +1399,7 @@
           /* 8n+4, or 8n+5, we enforce it by clearing the     */
           /* second bit                                       */
           /* (and sorting the stack indexing to suit)         */
-          count  = count1 & ~2;
+          count  = count1 & ~2U;
           index += count1 - count;
 
           FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
diff --git a/src/cff/cffdrivr.c b/src/cff/cffdrivr.c
index a718b7a..9a06b7c 100644
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -358,8 +358,8 @@
 
   FT_DEFINE_SERVICE_GLYPHDICTREC(
     cff_service_glyph_dict,
-    (FT_GlyphDict_GetNameFunc)  cff_get_glyph_name,
-    (FT_GlyphDict_NameIndexFunc)cff_get_name_index
+    (FT_GlyphDict_GetNameFunc)  cff_get_glyph_name,      /* get_name   */
+    (FT_GlyphDict_NameIndexFunc)cff_get_name_index       /* name_index */
   )
 
 
@@ -421,11 +421,13 @@
 
   FT_DEFINE_SERVICE_PSINFOREC(
     cff_service_ps_info,
-    (PS_GetFontInfoFunc)   cff_ps_get_font_info,
-    (PS_GetFontExtraFunc)  NULL,
-    (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names,
-    (PS_GetFontPrivateFunc)NULL,        /* unsupported with CFF fonts */
-    (PS_GetFontValueFunc)  NULL         /* not implemented            */
+    (PS_GetFontInfoFunc)   cff_ps_get_font_info,    /* ps_get_font_info    */
+    (PS_GetFontExtraFunc)  NULL,                    /* ps_get_font_extra   */
+    (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names,  /* ps_has_glyph_names  */
+    /* unsupported with CFF fonts */
+    (PS_GetFontPrivateFunc)NULL,                    /* ps_get_font_private */
+    /* not implemented            */
+    (PS_GetFontValueFunc)  NULL                     /* ps_get_font_value   */
   )
 
 
@@ -444,7 +446,7 @@
     /* following the OpenType specification 1.7, we return the name stored */
     /* in the `name' table for a CFF wrapped into an SFNT container        */
 
-    if ( sfnt )
+    if ( FT_IS_SFNT( FT_FACE( face ) ) && sfnt )
     {
       FT_Library             library     = FT_FACE_LIBRARY( face );
       FT_Module              sfnt_module = FT_Get_Module( library, "sfnt" );
@@ -464,7 +466,7 @@
 
   FT_DEFINE_SERVICE_PSFONTNAMEREC(
     cff_service_ps_name,
-    (FT_PsName_GetFunc)cff_get_ps_name
+    (FT_PsName_GetFunc)cff_get_ps_name      /* get_ps_font_name */
   )
 
 
@@ -511,7 +513,7 @@
 
   FT_DEFINE_SERVICE_TTCMAPSREC(
     cff_service_get_cmap_info,
-    (TT_CMap_Info_GetFunc)cff_get_cmap_info
+    (TT_CMap_Info_GetFunc)cff_get_cmap_info    /* get_cmap_info */
   )
 
 
@@ -641,9 +643,12 @@
 
   FT_DEFINE_SERVICE_CIDREC(
     cff_service_cid_info,
-    (FT_CID_GetRegistryOrderingSupplementFunc)cff_get_ros,
-    (FT_CID_GetIsInternallyCIDKeyedFunc)      cff_get_is_cid,
-    (FT_CID_GetCIDFromGlyphIndexFunc)         cff_get_cid_from_glyph_index
+    (FT_CID_GetRegistryOrderingSupplementFunc)
+      cff_get_ros,                             /* get_ros                  */
+    (FT_CID_GetIsInternallyCIDKeyedFunc)
+      cff_get_is_cid,                          /* get_is_cid               */
+    (FT_CID_GetCIDFromGlyphIndexFunc)
+      cff_get_cid_from_glyph_index             /* get_cid_from_glyph_index */
   )
 
 
@@ -776,8 +781,8 @@
 
   FT_DEFINE_SERVICE_PROPERTIESREC(
     cff_service_properties,
-    (FT_Properties_SetFunc)cff_property_set,
-    (FT_Properties_GetFunc)cff_property_get )
+    (FT_Properties_SetFunc)cff_property_set,      /* set_property */
+    (FT_Properties_GetFunc)cff_property_get )     /* get_property */
 
 
   /*************************************************************************/
@@ -865,9 +870,10 @@
   FT_DEFINE_DRIVER(
     cff_driver_class,
 
-      FT_MODULE_FONT_DRIVER       |
-      FT_MODULE_DRIVER_SCALABLE   |
-      FT_MODULE_DRIVER_HAS_HINTER,
+      FT_MODULE_FONT_DRIVER          |
+      FT_MODULE_DRIVER_SCALABLE      |
+      FT_MODULE_DRIVER_HAS_HINTER    |
+      FT_MODULE_DRIVER_HINTS_LIGHTLY,
 
       sizeof ( CFF_DriverRec ),
       "cff",
@@ -876,31 +882,29 @@
 
       0,   /* module-specific interface */
 
-      cff_driver_init,
-      cff_driver_done,
-      cff_get_interface,
+      cff_driver_init,          /* FT_Module_Constructor  module_init   */
+      cff_driver_done,          /* FT_Module_Destructor   module_done   */
+      cff_get_interface,        /* FT_Module_Requester    get_interface */
 
-    /* now the specific driver fields */
     sizeof ( TT_FaceRec ),
     sizeof ( CFF_SizeRec ),
     sizeof ( CFF_GlyphSlotRec ),
 
-    cff_face_init,
-    cff_face_done,
-    cff_size_init,
-    cff_size_done,
-    cff_slot_init,
-    cff_slot_done,
+    cff_face_init,              /* FT_Face_InitFunc  init_face */
+    cff_face_done,              /* FT_Face_DoneFunc  done_face */
+    cff_size_init,              /* FT_Size_InitFunc  init_size */
+    cff_size_done,              /* FT_Size_DoneFunc  done_size */
+    cff_slot_init,              /* FT_Slot_InitFunc  init_slot */
+    cff_slot_done,              /* FT_Slot_DoneFunc  done_slot */
 
-    cff_glyph_load,
+    cff_glyph_load,             /* FT_Slot_LoadFunc  load_glyph */
 
-    cff_get_kerning,
-    0,                       /* FT_Face_AttachFunc */
-    cff_get_advances,
+    cff_get_kerning,            /* FT_Face_GetKerningFunc   get_kerning  */
+    0,                          /* FT_Face_AttachFunc       attach_file  */
+    cff_get_advances,           /* FT_Face_GetAdvancesFunc  get_advances */
 
-    cff_size_request,
-
-    CFF_SIZE_SELECT
+    cff_size_request,           /* FT_Size_RequestFunc  request_size */
+    CFF_SIZE_SELECT             /* FT_Size_SelectFunc   select_size  */
   )
 
 
diff --git a/src/cff/cffgload.c b/src/cff/cffgload.c
index 43054f8..5f57403 100644
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -2949,7 +2949,6 @@
       {
         FT_BBox            cbox;
         FT_Glyph_Metrics*  metrics = &glyph->root.metrics;
-        FT_Vector          advance;
         FT_Bool            has_vertical_info;
 
 
@@ -3014,26 +3013,27 @@
 
         glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
 
-        if ( !( font_matrix.xx == 0x10000L &&
-                font_matrix.yy == 0x10000L &&
-                font_matrix.xy == 0        &&
-                font_matrix.yx == 0        ) )
+        /* apply the font matrix, if any */
+        if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
+             font_matrix.xy != 0        || font_matrix.yx != 0        )
+        {
           FT_Outline_Transform( &glyph->root.outline, &font_matrix );
 
-        if ( !( font_offset.x == 0 &&
-                font_offset.y == 0 ) )
+          metrics->horiAdvance = FT_MulFix( metrics->horiAdvance,
+                                            font_matrix.xx );
+          metrics->vertAdvance = FT_MulFix( metrics->vertAdvance,
+                                            font_matrix.yy );
+        }
+
+        if ( font_offset.x || font_offset.y )
+        {
           FT_Outline_Translate( &glyph->root.outline,
-                                font_offset.x, font_offset.y );
+                                font_offset.x,
+                                font_offset.y );
 
-        advance.x = metrics->horiAdvance;
-        advance.y = 0;
-        FT_Vector_Transform( &advance, &font_matrix );
-        metrics->horiAdvance = advance.x + font_offset.x;
-
-        advance.x = 0;
-        advance.y = metrics->vertAdvance;
-        FT_Vector_Transform( &advance, &font_matrix );
-        metrics->vertAdvance = advance.y + font_offset.y;
+          metrics->horiAdvance += font_offset.x;
+          metrics->vertAdvance += font_offset.y;
+        }
 
         if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
         {
@@ -3064,9 +3064,7 @@
         metrics->width  = cbox.xMax - cbox.xMin;
         metrics->height = cbox.yMax - cbox.yMin;
 
-        if ( !face->horizontal.number_Of_HMetrics )
-          metrics->horiBearingX = cbox.xMin;
-
+        metrics->horiBearingX = cbox.xMin;
         metrics->horiBearingY = cbox.yMax;
 
         if ( has_vertical_info )
diff --git a/src/cff/cffload.c b/src/cff/cffload.c
index fcb7348..c61222d 100644
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -1495,9 +1495,9 @@
     if ( pure_cff )
     {
       /* well, we don't really forget the `disabled' fonts... */
-      subfont_index = (FT_UInt)face_index;
+      subfont_index = (FT_UInt)( face_index & 0xFFFF );
 
-      if ( subfont_index >= font->name_index.count )
+      if ( face_index > 0 && subfont_index >= font->name_index.count )
       {
         FT_ERROR(( "cff_font_load:"
                    " invalid subfont index for pure CFF font (%d)\n",
diff --git a/src/cff/cffobjs.c b/src/cff/cffobjs.c
index 4a1ef11..d628b68 100644
--- a/src/cff/cffobjs.c
+++ b/src/cff/cffobjs.c
@@ -583,10 +583,15 @@
       if ( error )
         goto Exit;
 
+      /* if we are performing a simple font format check, exit immediately */
+      /* (this is here for pure CFF)                                       */
+      if ( face_index < 0 )
+        return FT_Err_Ok;
+
       cff->pshinter = pshinter;
       cff->psnames  = psnames;
 
-      cffface->face_index = face_index;
+      cffface->face_index = face_index & 0xFFFF;
 
       /* Complement the root flags with some interesting information. */
       /* Note that this is only necessary for pure CFF and CEF fonts; */
@@ -629,7 +634,7 @@
       if ( !dict->has_font_matrix )
         dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM;
 
-      /* Normalize the font matrix so that `matrix->xx' is 1; the */
+      /* Normalize the font matrix so that `matrix->yy' is 1; the */
       /* scaling is done with `units_per_em' then (at this point, */
       /* it already contains the scaling factor, but without      */
       /* normalization of the matrix).                            */
@@ -765,8 +770,9 @@
           (FT_Short)( dict->underline_thickness >> 16 );
 
         /* retrieve font family & style name */
-        cffface->family_name = cff_index_get_name( cff,
-                                                   (FT_UInt)face_index );
+        cffface->family_name = cff_index_get_name(
+                                 cff,
+                                 (FT_UInt)( face_index & 0xFFFF ) );
         if ( cffface->family_name )
         {
           char*  full   = cff_index_get_sid_string( cff,
@@ -1046,7 +1052,7 @@
     driver->hinting_engine = FT_CFF_HINTING_ADOBE;
 #endif
 
-    driver->no_stem_darkening = FALSE;
+    driver->no_stem_darkening = TRUE;
 
     driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
     driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
diff --git a/src/cff/cffpic.h b/src/cff/cffpic.h
index a29620e..9a221a7 100644
--- a/src/cff/cffpic.h
+++ b/src/cff/cffpic.h
@@ -20,8 +20,6 @@
 #define __CFFPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
 
@@ -49,6 +47,8 @@
 #include FT_SERVICE_PROPERTIES_H
 
 
+FT_BEGIN_HEADER
+
   typedef struct  CffModulePIC_
   {
     FT_ServiceDescRec*        cff_services;
@@ -96,12 +96,12 @@
   FT_Error
   cff_driver_class_pic_init( FT_Library  library );
 
+FT_END_HEADER
+
 #endif /* FT_CONFIG_OPTION_PIC */
 
  /* */
 
-FT_END_HEADER
-
 #endif /* __CFFPIC_H__ */
 
 
diff --git a/src/gzip/ftgzip.c b/src/gzip/ftgzip.c
index 879eb88..27c6254 100644
--- a/src/gzip/ftgzip.c
+++ b/src/gzip/ftgzip.c
@@ -377,7 +377,10 @@
       size = stream->read( stream, stream->pos, zip->input,
                            FT_GZIP_BUFFER_SIZE );
       if ( size == 0 )
+      {
+        zip->limit = zip->cursor;
         return FT_THROW( Invalid_Stream_Operation );
+      }
     }
     else
     {
@@ -386,7 +389,10 @@
         size = FT_GZIP_BUFFER_SIZE;
 
       if ( size == 0 )
+      {
+        zip->limit = zip->cursor;
         return FT_THROW( Invalid_Stream_Operation );
+      }
 
       FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
     }
@@ -433,7 +439,8 @@
       }
       else if ( err != Z_OK )
       {
-        error = FT_THROW( Invalid_Stream_Operation );
+        zip->limit = zip->cursor;
+        error      = FT_THROW( Invalid_Stream_Operation );
         break;
       }
     }
@@ -557,19 +564,22 @@
 
       stream->descriptor.pointer = NULL;
     }
+
+    if ( !stream->read )
+      FT_FREE( stream->base );
   }
 
 
-  static FT_ULong
-  ft_gzip_stream_io( FT_Stream  stream,
-                     FT_ULong   pos,
-                     FT_Byte*   buffer,
-                     FT_ULong   count )
+  static unsigned long
+  ft_gzip_stream_io( FT_Stream       stream,
+                     unsigned long   offset,
+                     unsigned char*  buffer,
+                     unsigned long   count )
   {
     FT_GZipFile  zip = (FT_GZipFile)stream->descriptor.pointer;
 
 
-    return ft_gzip_file_io( zip, pos, buffer, count );
+    return ft_gzip_file_io( zip, offset, buffer, count );
   }
 
 
@@ -584,7 +594,7 @@
     old_pos = stream->pos;
     if ( !FT_Stream_Seek( stream, stream->size - 4 ) )
     {
-      result = FT_Stream_ReadULong( stream, &error );
+      result = FT_Stream_ReadULongLE( stream, &error );
       if ( error )
         result = 0;
 
@@ -681,11 +691,15 @@
         }
         error = FT_Err_Ok;
       }
+
+      if ( zip_size )
+        stream->size = zip_size;
+      else
+        stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
     }
 
-    stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
     stream->pos   = 0;
-    stream->base  = 0;
+    stream->base  = NULL;
     stream->read  = ft_gzip_stream_io;
     stream->close = ft_gzip_stream_close;
 
diff --git a/src/pfr/pfrload.c b/src/pfr/pfrload.c
deleted file mode 100644
index ec7311d..0000000
--- a/src/pfr/pfrload.c
+++ /dev/null
@@ -1,941 +0,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  pfrload.c                                                              */
-/*                                                                         */
-/*    FreeType PFR loader (body).                                          */
-/*                                                                         */
-/*  Copyright 2002-2015 by                                                 */
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
-/*                                                                         */
-/*  This file is part of the FreeType project, and may only be used,       */
-/*  modified, and distributed under the terms of the FreeType project      */
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
-/*  this file you indicate that you have read the license and              */
-/*  understand and accept it fully.                                        */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "pfrload.h"
-#include FT_INTERNAL_DEBUG_H
-#include FT_INTERNAL_STREAM_H
-
-#include "pfrerror.h"
-
-#undef  FT_COMPONENT
-#define FT_COMPONENT  trace_pfr
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                          EXTRA ITEMS                          *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_LOCAL_DEF( FT_Error )
-  pfr_extra_items_skip( FT_Byte*  *pp,
-                        FT_Byte*   limit )
-  {
-    return pfr_extra_items_parse( pp, limit, NULL, NULL );
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  pfr_extra_items_parse( FT_Byte*       *pp,
-                         FT_Byte*        limit,
-                         PFR_ExtraItem   item_list,
-                         FT_Pointer      item_data )
-  {
-    FT_Error  error = FT_Err_Ok;
-    FT_Byte*  p     = *pp;
-    FT_UInt   num_items, item_type, item_size;
-
-
-    PFR_CHECK( 1 );
-    num_items = PFR_NEXT_BYTE( p );
-
-    for ( ; num_items > 0; num_items-- )
-    {
-      PFR_CHECK( 2 );
-      item_size = PFR_NEXT_BYTE( p );
-      item_type = PFR_NEXT_BYTE( p );
-
-      PFR_CHECK( item_size );
-
-      if ( item_list )
-      {
-        PFR_ExtraItem  extra = item_list;
-
-
-        for ( extra = item_list; extra->parser != NULL; extra++ )
-        {
-          if ( extra->type == item_type )
-          {
-            error = extra->parser( p, p + item_size, item_data );
-            if ( error ) goto Exit;
-
-            break;
-          }
-        }
-      }
-
-      p += item_size;
-    }
-
-  Exit:
-    *pp = p;
-    return error;
-
-  Too_Short:
-    FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" ));
-    error = FT_THROW( Invalid_Table );
-    goto Exit;
-  }
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                          PFR HEADER                           *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-   static const FT_Frame_Field  pfr_header_fields[] =
-   {
-#undef  FT_STRUCTURE
-#define FT_STRUCTURE  PFR_HeaderRec
-
-     FT_FRAME_START( 58 ),
-       FT_FRAME_ULONG ( signature ),
-       FT_FRAME_USHORT( version ),
-       FT_FRAME_USHORT( signature2 ),
-       FT_FRAME_USHORT( header_size ),
-
-       FT_FRAME_USHORT( log_dir_size ),
-       FT_FRAME_USHORT( log_dir_offset ),
-
-       FT_FRAME_USHORT( log_font_max_size ),
-       FT_FRAME_UOFF3 ( log_font_section_size ),
-       FT_FRAME_UOFF3 ( log_font_section_offset ),
-
-       FT_FRAME_USHORT( phy_font_max_size ),
-       FT_FRAME_UOFF3 ( phy_font_section_size ),
-       FT_FRAME_UOFF3 ( phy_font_section_offset ),
-
-       FT_FRAME_USHORT( gps_max_size ),
-       FT_FRAME_UOFF3 ( gps_section_size ),
-       FT_FRAME_UOFF3 ( gps_section_offset ),
-
-       FT_FRAME_BYTE  ( max_blue_values ),
-       FT_FRAME_BYTE  ( max_x_orus ),
-       FT_FRAME_BYTE  ( max_y_orus ),
-
-       FT_FRAME_BYTE  ( phy_font_max_size_high ),
-       FT_FRAME_BYTE  ( color_flags ),
-
-       FT_FRAME_UOFF3 ( bct_max_size ),
-       FT_FRAME_UOFF3 ( bct_set_max_size ),
-       FT_FRAME_UOFF3 ( phy_bct_set_max_size ),
-
-       FT_FRAME_USHORT( num_phy_fonts ),
-       FT_FRAME_BYTE  ( max_vert_stem_snap ),
-       FT_FRAME_BYTE  ( max_horz_stem_snap ),
-       FT_FRAME_USHORT( max_chars ),
-     FT_FRAME_END
-   };
-
-
-  FT_LOCAL_DEF( FT_Error )
-  pfr_header_load( PFR_Header  header,
-                   FT_Stream   stream )
-  {
-    FT_Error  error;
-
-
-    /* read header directly */
-    if ( !FT_STREAM_SEEK( 0 )                                &&
-         !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) )
-    {
-      /* make a few adjustments to the header */
-      header->phy_font_max_size +=
-        (FT_UInt32)header->phy_font_max_size_high << 16;
-    }
-
-    return error;
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  pfr_header_check( PFR_Header  header )
-  {
-    FT_Bool  result = 1;
-
-
-    /* check signature and header size */
-    if ( header->signature  != 0x50465230L ||   /* "PFR0" */
-         header->version     > 4           ||
-         header->header_size < 58          ||
-         header->signature2 != 0x0D0A      )    /* CR/LF  */
-    {
-      result = 0;
-    }
-    return  result;
-  }
-
-
-  /***********************************************************************/
-  /***********************************************************************/
-  /*****                                                             *****/
-  /*****                    PFR LOGICAL FONTS                        *****/
-  /*****                                                             *****/
-  /***********************************************************************/
-  /***********************************************************************/
-
-
-  FT_LOCAL_DEF( FT_Error )
-  pfr_log_font_count( FT_Stream  stream,
-                      FT_UInt32  section_offset,
-                      FT_Long   *acount )
-  {
-    FT_Error  error;
-    FT_UInt   count;
-    FT_UInt   result = 0;
-
-
-    if ( FT_STREAM_SEEK( section_offset ) || FT_READ_USHORT( count ) )
-      goto Exit;
-
-    result = count;
-
-  Exit:
-    *acount = (FT_Long)result;
-    return error;
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  pfr_log_font_load( PFR_LogFont  log_font,
-                     FT_Stream    stream,
-                     FT_UInt      idx,
-                     FT_UInt32    section_offset,
-                     FT_Bool      size_increment )
-  {
-    FT_UInt    num_log_fonts;
-    FT_UInt    flags;
-    FT_UInt32  offset;
-    FT_UInt32  size;
-    FT_Error   error;
-
-
-    if ( FT_STREAM_SEEK( section_offset ) ||
-         FT_READ_USHORT( num_log_fonts )  )
-      goto Exit;
-
-    if ( idx >= num_log_fonts )
-      return FT_THROW( Invalid_Argument );
-
-    if ( FT_STREAM_SKIP( idx * 5 ) ||
-         FT_READ_USHORT( size )    ||
-         FT_READ_UOFF3 ( offset )  )
-      goto Exit;
-
-    /* save logical font size and offset */
-    log_font->size   = size;
-    log_font->offset = offset;
-
-    /* now, check the rest of the table before loading it */
-    {
-      FT_Byte*  p;
-      FT_Byte*  limit;
-      FT_UInt   local;
-
-
-      if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) )
-        goto Exit;
-
-      p     = stream->cursor;
-      limit = p + size;
-
-      PFR_CHECK(13);
-
-      log_font->matrix[0] = PFR_NEXT_LONG( p );
-      log_font->matrix[1] = PFR_NEXT_LONG( p );
-      log_font->matrix[2] = PFR_NEXT_LONG( p );
-      log_font->matrix[3] = PFR_NEXT_LONG( p );
-
-      flags = PFR_NEXT_BYTE( p );
-
-      local = 0;
-      if ( flags & PFR_LOG_STROKE )
-      {
-        local++;
-        if ( flags & PFR_LOG_2BYTE_STROKE )
-          local++;
-
-        if ( (flags & PFR_LINE_JOIN_MASK) == PFR_LINE_JOIN_MITER )
-          local += 3;
-      }
-      if ( flags & PFR_LOG_BOLD )
-      {
-        local++;
-        if ( flags & PFR_LOG_2BYTE_BOLD )
-          local++;
-      }
-
-      PFR_CHECK( local );
-
-      if ( flags & PFR_LOG_STROKE )
-      {
-        log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE )
-                                     ? PFR_NEXT_SHORT( p )
-                                     : PFR_NEXT_BYTE( p );
-
-        if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER )
-          log_font->miter_limit = PFR_NEXT_LONG( p );
-      }
-
-      if ( flags & PFR_LOG_BOLD )
-      {
-        log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD )
-                                   ? PFR_NEXT_SHORT( p )
-                                   : PFR_NEXT_BYTE( p );
-      }
-
-      if ( flags & PFR_LOG_EXTRA_ITEMS )
-      {
-        error = pfr_extra_items_skip( &p, limit );
-        if (error) goto Fail;
-      }
-
-      PFR_CHECK(5);
-      log_font->phys_size   = PFR_NEXT_USHORT( p );
-      log_font->phys_offset = PFR_NEXT_ULONG( p );
-      if ( size_increment )
-      {
-        PFR_CHECK( 1 );
-        log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16;
-      }
-    }
-
-  Fail:
-    FT_FRAME_EXIT();
-
-  Exit:
-    return error;
-
-  Too_Short:
-    FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" ));
-    error = FT_THROW( Invalid_Table );
-    goto Fail;
-  }
-
-
-  /***********************************************************************/
-  /***********************************************************************/
-  /*****                                                             *****/
-  /*****                    PFR PHYSICAL FONTS                       *****/
-  /*****                                                             *****/
-  /***********************************************************************/
-  /***********************************************************************/
-
-
-  /* load bitmap strikes lists */
-  FT_CALLBACK_DEF( FT_Error )
-  pfr_extra_item_load_bitmap_info( FT_Byte*     p,
-                                   FT_Byte*     limit,
-                                   PFR_PhyFont  phy_font )
-  {
-    FT_Memory   memory = phy_font->memory;
-    PFR_Strike  strike;
-    FT_UInt     flags0;
-    FT_UInt     n, count, size1;
-    FT_Error    error = FT_Err_Ok;
-
-
-    PFR_CHECK( 5 );
-
-    p += 3;  /* skip bctSize */
-    flags0 = PFR_NEXT_BYTE( p );
-    count  = PFR_NEXT_BYTE( p );
-
-    /* re-allocate when needed */
-    if ( phy_font->num_strikes + count > phy_font->max_strikes )
-    {
-      FT_UInt  new_max = FT_PAD_CEIL( phy_font->num_strikes + count, 4 );
-
-
-      if ( FT_RENEW_ARRAY( phy_font->strikes,
-                           phy_font->num_strikes,
-                           new_max ) )
-        goto Exit;
-
-      phy_font->max_strikes = new_max;
-    }
-
-    size1 = 1 + 1 + 1 + 2 + 2 + 1;
-    if ( flags0 & PFR_STRIKE_2BYTE_XPPM )
-      size1++;
-
-    if ( flags0 & PFR_STRIKE_2BYTE_YPPM )
-      size1++;
-
-    if ( flags0 & PFR_STRIKE_3BYTE_SIZE )
-      size1++;
-
-    if ( flags0 & PFR_STRIKE_3BYTE_OFFSET )
-      size1++;
-
-    if ( flags0 & PFR_STRIKE_2BYTE_COUNT )
-      size1++;
-
-    strike = phy_font->strikes + phy_font->num_strikes;
-
-    PFR_CHECK( count * size1 );
-
-    for ( n = 0; n < count; n++, strike++ )
-    {
-      strike->x_ppm       = ( flags0 & PFR_STRIKE_2BYTE_XPPM )
-                            ? PFR_NEXT_USHORT( p )
-                            : PFR_NEXT_BYTE( p );
-
-      strike->y_ppm       = ( flags0 & PFR_STRIKE_2BYTE_YPPM )
-                            ? PFR_NEXT_USHORT( p )
-                            : PFR_NEXT_BYTE( p );
-
-      strike->flags       = PFR_NEXT_BYTE( p );
-
-      strike->bct_size    = ( flags0 & PFR_STRIKE_3BYTE_SIZE )
-                            ? PFR_NEXT_ULONG( p )
-                            : PFR_NEXT_USHORT( p );
-
-      strike->bct_offset  = ( flags0 & PFR_STRIKE_3BYTE_OFFSET )
-                            ? PFR_NEXT_ULONG( p )
-                            : PFR_NEXT_USHORT( p );
-
-      strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT )
-                            ? PFR_NEXT_USHORT( p )
-                            : PFR_NEXT_BYTE( p );
-    }
-
-    phy_font->num_strikes += count;
-
-  Exit:
-    return error;
-
-  Too_Short:
-    error = FT_THROW( Invalid_Table );
-    FT_ERROR(( "pfr_extra_item_load_bitmap_info:"
-               " invalid bitmap info table\n" ));
-    goto Exit;
-  }
-
-
-  /* Load font ID.  This is a so-called "unique" name that is rather
-   * long and descriptive (like "Tiresias ScreenFont v7.51").
-   *
-   * Note that a PFR font's family name is contained in an *undocumented*
-   * string of the "auxiliary data" portion of a physical font record.  This
-   * may also contain the "real" style name!
-   *
-   * If no family name is present, the font ID is used instead for the
-   * family.
-   */
-  FT_CALLBACK_DEF( FT_Error )
-  pfr_extra_item_load_font_id( FT_Byte*     p,
-                               FT_Byte*     limit,
-                               PFR_PhyFont  phy_font )
-  {
-    FT_Error   error  = FT_Err_Ok;
-    FT_Memory  memory = phy_font->memory;
-    FT_UInt    len    = (FT_UInt)( limit - p );
-
-
-    if ( phy_font->font_id != NULL )
-      goto Exit;
-
-    if ( FT_ALLOC( phy_font->font_id, len + 1 ) )
-      goto Exit;
-
-    /* copy font ID name, and terminate it for safety */
-    FT_MEM_COPY( phy_font->font_id, p, len );
-    phy_font->font_id[len] = 0;
-
-  Exit:
-    return error;
-  }
-
-
-  /* load stem snap tables */
-  FT_CALLBACK_DEF( FT_Error )
-  pfr_extra_item_load_stem_snaps( FT_Byte*     p,
-                                  FT_Byte*     limit,
-                                  PFR_PhyFont  phy_font )
-  {
-    FT_UInt    count, num_vert, num_horz;
-    FT_Int*    snaps  = NULL;
-    FT_Error   error  = FT_Err_Ok;
-    FT_Memory  memory = phy_font->memory;
-
-
-    if ( phy_font->vertical.stem_snaps != NULL )
-      goto Exit;
-
-    PFR_CHECK( 1 );
-    count = PFR_NEXT_BYTE( p );
-
-    num_vert = count & 15;
-    num_horz = count >> 4;
-    count    = num_vert + num_horz;
-
-    PFR_CHECK( count * 2 );
-
-    if ( FT_NEW_ARRAY( snaps, count ) )
-      goto Exit;
-
-    phy_font->vertical.stem_snaps = snaps;
-    phy_font->horizontal.stem_snaps = snaps + num_vert;
-
-    for ( ; count > 0; count--, snaps++ )
-      *snaps = FT_NEXT_SHORT( p );
-
-  Exit:
-    return error;
-
-  Too_Short:
-    error = FT_THROW( Invalid_Table );
-    FT_ERROR(( "pfr_exta_item_load_stem_snaps:"
-               " invalid stem snaps table\n" ));
-    goto Exit;
-  }
-
-
-
-  /* load kerning pair data */
-  FT_CALLBACK_DEF( FT_Error )
-  pfr_extra_item_load_kerning_pairs( FT_Byte*     p,
-                                     FT_Byte*     limit,
-                                     PFR_PhyFont  phy_font )
-  {
-    PFR_KernItem  item   = NULL;
-    FT_Error      error  = FT_Err_Ok;
-    FT_Memory     memory = phy_font->memory;
-
-
-    FT_TRACE2(( "pfr_extra_item_load_kerning_pairs()\n" ));
-
-    if ( FT_NEW( item ) )
-      goto Exit;
-
-    PFR_CHECK( 4 );
-
-    item->pair_count = PFR_NEXT_BYTE( p );
-    item->base_adj   = PFR_NEXT_SHORT( p );
-    item->flags      = PFR_NEXT_BYTE( p );
-    item->offset     = phy_font->offset +
-                       (FT_Offset)( p - phy_font->cursor );
-
-#ifndef PFR_CONFIG_NO_CHECKS
-    item->pair_size = 3;
-
-    if ( item->flags & PFR_KERN_2BYTE_CHAR )
-      item->pair_size += 2;
-
-    if ( item->flags & PFR_KERN_2BYTE_ADJ )
-      item->pair_size += 1;
-
-    PFR_CHECK( item->pair_count * item->pair_size );
-#endif
-
-    /* load first and last pairs into the item to speed up */
-    /* lookup later...                                     */
-    if ( item->pair_count > 0 )
-    {
-      FT_UInt   char1, char2;
-      FT_Byte*  q;
-
-
-      if ( item->flags & PFR_KERN_2BYTE_CHAR )
-      {
-        q     = p;
-        char1 = PFR_NEXT_USHORT( q );
-        char2 = PFR_NEXT_USHORT( q );
-
-        item->pair1 = PFR_KERN_INDEX( char1, char2 );
-
-        q = p + item->pair_size * ( item->pair_count - 1 );
-        char1 = PFR_NEXT_USHORT( q );
-        char2 = PFR_NEXT_USHORT( q );
-
-        item->pair2 = PFR_KERN_INDEX( char1, char2 );
-      }
-      else
-      {
-        q     = p;
-        char1 = PFR_NEXT_BYTE( q );
-        char2 = PFR_NEXT_BYTE( q );
-
-        item->pair1 = PFR_KERN_INDEX( char1, char2 );
-
-        q = p + item->pair_size * ( item->pair_count - 1 );
-        char1 = PFR_NEXT_BYTE( q );
-        char2 = PFR_NEXT_BYTE( q );
-
-        item->pair2 = PFR_KERN_INDEX( char1, char2 );
-      }
-
-      /* add new item to the current list */
-      item->next                 = NULL;
-      *phy_font->kern_items_tail = item;
-      phy_font->kern_items_tail  = &item->next;
-      phy_font->num_kern_pairs  += item->pair_count;
-    }
-    else
-    {
-      /* empty item! */
-      FT_FREE( item );
-    }
-
-  Exit:
-    return error;
-
-  Too_Short:
-    FT_FREE( item );
-
-    error = FT_THROW( Invalid_Table );
-    FT_ERROR(( "pfr_extra_item_load_kerning_pairs:"
-               " invalid kerning pairs table\n" ));
-    goto Exit;
-  }
-
-
-
-  static const PFR_ExtraItemRec  pfr_phy_font_extra_items[] =
-  {
-    { 1, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_bitmap_info },
-    { 2, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_font_id },
-    { 3, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_stem_snaps },
-    { 4, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_kerning_pairs },
-    { 0, NULL }
-  };
-
-
-  /* Loads a name from the auxiliary data.  Since this extracts undocumented
-   * strings from the font file, we need to be careful here.
-   */
-  static FT_Error
-  pfr_aux_name_load( FT_Byte*     p,
-                     FT_UInt      len,
-                     FT_Memory    memory,
-                     FT_String*  *astring )
-  {
-    FT_Error    error  = FT_Err_Ok;
-    FT_String*  result = NULL;
-    FT_UInt     n, ok;
-
-
-    if ( len > 0 && p[len - 1] == 0 )
-      len--;
-
-    /* check that each character is ASCII for making sure not to
-       load garbage
-     */
-    ok = ( len > 0 );
-    for ( n = 0; n < len; n++ )
-      if ( p[n] < 32 || p[n] > 127 )
-      {
-        ok = 0;
-        break;
-      }
-
-    if ( ok )
-    {
-      if ( FT_ALLOC( result, len + 1 ) )
-        goto Exit;
-
-      FT_MEM_COPY( result, p, len );
-      result[len] = 0;
-    }
-  Exit:
-    *astring = result;
-    return error;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  pfr_phy_font_done( PFR_PhyFont  phy_font,
-                     FT_Memory    memory )
-  {
-    FT_FREE( phy_font->font_id );
-    FT_FREE( phy_font->family_name );
-    FT_FREE( phy_font->style_name );
-
-    FT_FREE( phy_font->vertical.stem_snaps );
-    phy_font->vertical.num_stem_snaps = 0;
-
-    phy_font->horizontal.stem_snaps     = NULL;
-    phy_font->horizontal.num_stem_snaps = 0;
-
-    FT_FREE( phy_font->strikes );
-    phy_font->num_strikes = 0;
-    phy_font->max_strikes = 0;
-
-    FT_FREE( phy_font->chars );
-    phy_font->num_chars    = 0;
-    phy_font->chars_offset = 0;
-
-    FT_FREE( phy_font->blue_values );
-    phy_font->num_blue_values = 0;
-
-    {
-      PFR_KernItem  item, next;
-
-
-      item = phy_font->kern_items;
-      while ( item )
-      {
-        next = item->next;
-        FT_FREE( item );
-        item = next;
-      }
-      phy_font->kern_items      = NULL;
-      phy_font->kern_items_tail = NULL;
-    }
-
-    phy_font->num_kern_pairs = 0;
-  }
-
-
-  FT_LOCAL_DEF( FT_Error )
-  pfr_phy_font_load( PFR_PhyFont  phy_font,
-                     FT_Stream    stream,
-                     FT_UInt32    offset,
-                     FT_UInt32    size )
-  {
-    FT_Error   error;
-    FT_Memory  memory = stream->memory;
-    FT_UInt    flags;
-    FT_ULong   num_aux;
-    FT_Byte*   p;
-    FT_Byte*   limit;
-
-
-    phy_font->memory = memory;
-    phy_font->offset = offset;
-
-    phy_font->kern_items      = NULL;
-    phy_font->kern_items_tail = &phy_font->kern_items;
-
-    if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) )
-      goto Exit;
-
-    phy_font->cursor = stream->cursor;
-
-    p     = stream->cursor;
-    limit = p + size;
-
-    PFR_CHECK( 15 );
-    phy_font->font_ref_number    = PFR_NEXT_USHORT( p );
-    phy_font->outline_resolution = PFR_NEXT_USHORT( p );
-    phy_font->metrics_resolution = PFR_NEXT_USHORT( p );
-    phy_font->bbox.xMin          = PFR_NEXT_SHORT( p );
-    phy_font->bbox.yMin          = PFR_NEXT_SHORT( p );
-    phy_font->bbox.xMax          = PFR_NEXT_SHORT( p );
-    phy_font->bbox.yMax          = PFR_NEXT_SHORT( p );
-    phy_font->flags      = flags = PFR_NEXT_BYTE( p );
-
-    /* get the standard advance for non-proportional fonts */
-    if ( !(flags & PFR_PHY_PROPORTIONAL) )
-    {
-      PFR_CHECK( 2 );
-      phy_font->standard_advance = PFR_NEXT_SHORT( p );
-    }
-
-    /* load the extra items when present */
-    if ( flags & PFR_PHY_EXTRA_ITEMS )
-    {
-      error =  pfr_extra_items_parse( &p, limit,
-                                      pfr_phy_font_extra_items, phy_font );
-
-      if ( error )
-        goto Fail;
-    }
-
-    /* In certain fonts, the auxiliary bytes contain interesting  */
-    /* information. These are not in the specification but can be */
-    /* guessed by looking at the content of a few PFR0 fonts.     */
-    PFR_CHECK( 3 );
-    num_aux = PFR_NEXT_ULONG( p );
-
-    if ( num_aux > 0 )
-    {
-      FT_Byte*  q = p;
-      FT_Byte*  q2;
-
-
-      PFR_CHECK( num_aux );
-      p += num_aux;
-
-      while ( num_aux > 0 )
-      {
-        FT_UInt  length, type;
-
-
-        if ( q + 4 > p )
-          break;
-
-        length = PFR_NEXT_USHORT( q );
-        if ( length < 4 || length > num_aux )
-          break;
-
-        q2   = q + length - 2;
-        type = PFR_NEXT_USHORT( q );
-
-        switch ( type )
-        {
-        case 1:
-          /* this seems to correspond to the font's family name,
-           * padded to 16-bits with one zero when necessary
-           */
-          error = pfr_aux_name_load( q, length - 4U, memory,
-                                     &phy_font->family_name );
-          if ( error )
-            goto Exit;
-          break;
-
-        case 2:
-          if ( q + 32 > q2 )
-            break;
-
-          q += 10;
-          phy_font->ascent  = PFR_NEXT_SHORT( q );
-          phy_font->descent = PFR_NEXT_SHORT( q );
-          phy_font->leading = PFR_NEXT_SHORT( q );
-          break;
-
-        case 3:
-          /* this seems to correspond to the font's style name,
-           * padded to 16-bits with one zero when necessary
-           */
-          error = pfr_aux_name_load( q, length - 4U, memory,
-                                     &phy_font->style_name );
-          if ( error )
-            goto Exit;
-          break;
-
-        default:
-          ;
-        }
-
-        q        = q2;
-        num_aux -= length;
-      }
-    }
-
-    /* read the blue values */
-    {
-      FT_UInt  n, count;
-
-
-      PFR_CHECK( 1 );
-      phy_font->num_blue_values = count = PFR_NEXT_BYTE( p );
-
-      PFR_CHECK( count * 2 );
-
-      if ( FT_NEW_ARRAY( phy_font->blue_values, count ) )
-        goto Fail;
-
-      for ( n = 0; n < count; n++ )
-        phy_font->blue_values[n] = PFR_NEXT_SHORT( p );
-    }
-
-    PFR_CHECK( 8 );
-    phy_font->blue_fuzz  = PFR_NEXT_BYTE( p );
-    phy_font->blue_scale = PFR_NEXT_BYTE( p );
-
-    phy_font->vertical.standard   = PFR_NEXT_USHORT( p );
-    phy_font->horizontal.standard = PFR_NEXT_USHORT( p );
-
-    /* read the character descriptors */
-    {
-      FT_UInt  n, count, Size;
-
-
-      phy_font->num_chars    = count = PFR_NEXT_USHORT( p );
-      phy_font->chars_offset = offset + (FT_Offset)( p - stream->cursor );
-
-      if ( FT_NEW_ARRAY( phy_font->chars, count ) )
-        goto Fail;
-
-      Size = 1 + 1 + 2;
-      if ( flags & PFR_PHY_2BYTE_CHARCODE )
-        Size += 1;
-
-      if ( flags & PFR_PHY_PROPORTIONAL )
-        Size += 2;
-
-      if ( flags & PFR_PHY_ASCII_CODE )
-        Size += 1;
-
-      if ( flags & PFR_PHY_2BYTE_GPS_SIZE )
-        Size += 1;
-
-      if ( flags & PFR_PHY_3BYTE_GPS_OFFSET )
-        Size += 1;
-
-      PFR_CHECK( count * Size );
-
-      for ( n = 0; n < count; n++ )
-      {
-        PFR_Char  cur = &phy_font->chars[n];
-
-
-        cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE )
-                         ? PFR_NEXT_USHORT( p )
-                         : PFR_NEXT_BYTE( p );
-
-        cur->advance   = ( flags & PFR_PHY_PROPORTIONAL )
-                         ? PFR_NEXT_SHORT( p )
-                         : phy_font->standard_advance;
-
-#if 0
-        cur->ascii     = ( flags & PFR_PHY_ASCII_CODE )
-                         ? PFR_NEXT_BYTE( p )
-                         : 0;
-#else
-        if ( flags & PFR_PHY_ASCII_CODE )
-          p += 1;
-#endif
-        cur->gps_size  = ( flags & PFR_PHY_2BYTE_GPS_SIZE )
-                         ? PFR_NEXT_USHORT( p )
-                         : PFR_NEXT_BYTE( p );
-
-        cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET )
-                          ? PFR_NEXT_ULONG( p )
-                          : PFR_NEXT_USHORT( p );
-      }
-    }
-
-    /* that's it! */
-
-  Fail:
-    FT_FRAME_EXIT();
-
-    /* save position of bitmap info */
-    phy_font->bct_offset = FT_STREAM_POS();
-    phy_font->cursor     = NULL;
-
-  Exit:
-    return error;
-
-  Too_Short:
-    error = FT_THROW( Invalid_Table );
-    FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" ));
-    goto Fail;
-  }
-
-
-/* END */
diff --git a/src/psaux/psobjs.c b/src/psaux/psobjs.c
index c7cbc67..1d3c7e6 100644
--- a/src/psaux/psobjs.c
+++ b/src/psaux/psobjs.c
@@ -594,6 +594,9 @@
       error = FT_THROW( Invalid_File_Format );
     }
 
+    if ( cur > limit )
+      cur = limit;
+
     parser->error  = error;
     parser->cursor = cur;
   }
@@ -1229,15 +1232,17 @@
             if ( result < 0 || (FT_UInt)result < max_objects )
             {
               FT_ERROR(( "ps_parser_load_field:"
-                         " expected %d integers in the %s subarray\n"
+                         " expected %d integer%s in the %s subarray\n"
                          "                     "
                          " of /FontBBox in the /Blend dictionary\n",
-                         max_objects,
+                         max_objects, max_objects > 1 ? "s" : "",
                          i == 0 ? "first"
                                 : ( i == 1 ? "second"
                                            : ( i == 2 ? "third"
                                                       : "fourth" ) ) ));
               error = FT_THROW( Invalid_File_Format );
+
+              FT_FREE( temp );
               goto Exit;
             }
 
diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c
index 2e19928..5811fcb 100644
--- a/src/psaux/t1decode.c
+++ b/src/psaux/t1decode.c
@@ -512,7 +512,7 @@
         break;
 
       case 12:
-        if ( ip > limit )
+        if ( ip >= limit )
         {
           FT_ERROR(( "t1_decoder_parse_charstrings:"
                      " invalid escape (12+EOF)\n" ));
@@ -669,7 +669,7 @@
         if ( large_int )
           FT_TRACE4(( " %ld", value ));
         else
-          FT_TRACE4(( " %ld", Fix2Int( value ) ));
+          FT_TRACE4(( " %ld", value / 65536 ));
 #endif
 
         *top++       = value;
diff --git a/src/pshinter/pshalgo.c b/src/pshinter/pshalgo.c
index bfdb3ed..6e654cb 100644
--- a/src/pshinter/pshalgo.c
+++ b/src/pshinter/pshalgo.c
@@ -916,103 +916,9 @@
   /*************************************************************************/
   /*************************************************************************/
 
-#if 1
-
 #define  psh_corner_is_flat      ft_corner_is_flat
 #define  psh_corner_orientation  ft_corner_orientation
 
-#else
-
-  FT_LOCAL_DEF( FT_Int )
-  psh_corner_is_flat( FT_Pos  x_in,
-                      FT_Pos  y_in,
-                      FT_Pos  x_out,
-                      FT_Pos  y_out )
-  {
-    FT_Pos  ax = x_in;
-    FT_Pos  ay = y_in;
-
-    FT_Pos  d_in, d_out, d_corner;
-
-
-    if ( ax < 0 )
-      ax = -ax;
-    if ( ay < 0 )
-      ay = -ay;
-    d_in = ax + ay;
-
-    ax = x_out;
-    if ( ax < 0 )
-      ax = -ax;
-    ay = y_out;
-    if ( ay < 0 )
-      ay = -ay;
-    d_out = ax + ay;
-
-    ax = x_out + x_in;
-    if ( ax < 0 )
-      ax = -ax;
-    ay = y_out + y_in;
-    if ( ay < 0 )
-      ay = -ay;
-    d_corner = ax + ay;
-
-    return ( d_in + d_out - d_corner ) < ( d_corner >> 4 );
-  }
-
-  static FT_Int
-  psh_corner_orientation( FT_Pos  in_x,
-                          FT_Pos  in_y,
-                          FT_Pos  out_x,
-                          FT_Pos  out_y )
-  {
-    FT_Int  result;
-
-
-    /* deal with the trivial cases quickly */
-    if ( in_y == 0 )
-    {
-      if ( in_x >= 0 )
-        result = out_y;
-      else
-        result = -out_y;
-    }
-    else if ( in_x == 0 )
-    {
-      if ( in_y >= 0 )
-        result = -out_x;
-      else
-        result = out_x;
-    }
-    else if ( out_y == 0 )
-    {
-      if ( out_x >= 0 )
-        result = in_y;
-      else
-        result = -in_y;
-    }
-    else if ( out_x == 0 )
-    {
-      if ( out_y >= 0 )
-        result = -in_x;
-      else
-        result =  in_x;
-    }
-    else /* general case */
-    {
-      long long  delta = (long long)in_x * out_y - (long long)in_y * out_x;
-
-      if ( delta == 0 )
-        result = 0;
-      else
-        result = 1 - 2 * ( delta < 0 );
-    }
-
-    return result;
-  }
-
-#endif /* !1 */
-
 
 #ifdef COMPUTE_INFLEXS
 
diff --git a/src/pshinter/pshglob.c b/src/pshinter/pshglob.c
index 6723b71..4616bdc 100644
--- a/src/pshinter/pshglob.c
+++ b/src/pshinter/pshglob.c
@@ -339,7 +339,7 @@
             bot   = zone[1].org_bottom;
             delta = bot - top;
 
-            if ( delta < 2 * fuzz )
+            if ( delta / 2 < fuzz )
               zone[0].org_top = zone[1].org_bottom = top + delta / 2;
             else
             {
diff --git a/src/pshinter/pshpic.h b/src/pshinter/pshpic.h
index 62de457..ca35cd6 100644
--- a/src/pshinter/pshpic.h
+++ b/src/pshinter/pshpic.h
@@ -20,8 +20,6 @@
 #define __PSHPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
 
@@ -33,6 +31,8 @@
 
 #include FT_INTERNAL_POSTSCRIPT_HINTS_H
 
+FT_BEGIN_HEADER
+
   typedef struct  PSHinterPIC_
   {
     PSHinter_Interface  pshinter_interface;
@@ -51,12 +51,12 @@
   FT_Error
   pshinter_module_class_pic_init( FT_Library  library );
 
+FT_END_HEADER
+
 #endif /* FT_CONFIG_OPTION_PIC */
 
  /* */
 
-FT_END_HEADER
-
 #endif /* __PSHPIC_H__ */
 
 
diff --git a/src/psnames/psmodule.c b/src/psnames/psmodule.c
index 0f04c2f..5406098 100644
--- a/src/psnames/psmodule.c
+++ b/src/psnames/psmodule.c
@@ -525,31 +525,31 @@
 
   FT_DEFINE_SERVICE_PSCMAPSREC(
     pscmaps_interface,
-    (PS_Unicode_ValueFunc)     ps_unicode_value,
-    (PS_Unicodes_InitFunc)     ps_unicodes_init,
-    (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index,
-    (PS_Unicodes_CharNextFunc) ps_unicodes_char_next,
+    (PS_Unicode_ValueFunc)     ps_unicode_value,        /* unicode_value         */
+    (PS_Unicodes_InitFunc)     ps_unicodes_init,        /* unicodes_init         */
+    (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index,  /* unicodes_char_index   */
+    (PS_Unicodes_CharNextFunc) ps_unicodes_char_next,   /* unicodes_char_next    */
 
-    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,
-    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings,
+    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,   /* macintosh_name        */
+    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings     */
 
-    t1_standard_encoding,
-    t1_expert_encoding )
+    t1_standard_encoding,                               /* adobe_std_encoding    */
+    t1_expert_encoding )                                /* adobe_expert_encoding */
 
 #else
 
   FT_DEFINE_SERVICE_PSCMAPSREC(
     pscmaps_interface,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
+    NULL,                                               /* unicode_value         */
+    NULL,                                               /* unicodes_init         */
+    NULL,                                               /* unicodes_char_index   */
+    NULL,                                               /* unicodes_char_next    */
 
-    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,
-    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings,
+    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,   /* macintosh_name        */
+    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings     */
 
-    t1_standard_encoding,
-    t1_expert_encoding )
+    t1_standard_encoding,                               /* adobe_std_encoding    */
+    t1_expert_encoding )                                /* adobe_expert_encoding */
 
 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
 
diff --git a/src/psnames/pspic.h b/src/psnames/pspic.h
index 88ccda3..443225a 100644
--- a/src/psnames/pspic.h
+++ b/src/psnames/pspic.h
@@ -20,10 +20,9 @@
 #define __PSPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
+
 #ifndef FT_CONFIG_OPTION_PIC
 
 #define PSCMAPS_SERVICES_GET   pscmaps_services
@@ -33,6 +32,9 @@
 
 #include FT_SERVICE_POSTSCRIPT_CMAPS_H
 
+
+FT_BEGIN_HEADER
+
   typedef struct  PSModulePIC_
   {
     FT_ServiceDescRec*     pscmaps_services;
@@ -54,12 +56,12 @@
   FT_Error
   psnames_module_class_pic_init( FT_Library  library );
 
+FT_END_HEADER
+
 #endif /* FT_CONFIG_OPTION_PIC */
 
  /* */
 
-FT_END_HEADER
-
 #endif /* __PSPIC_H__ */
 
 
diff --git a/src/raster/ftmisc.h b/src/raster/ftmisc.h
index 19be4ca..b87e0b6 100644
--- a/src/raster/ftmisc.h
+++ b/src/raster/ftmisc.h
@@ -37,7 +37,7 @@
 #define FT_LOCAL_DEF( x )   static x
 
 
-  /* from include/freetype2/fttypes.h */
+  /* from include/freetype/fttypes.h */
 
   typedef unsigned char  FT_Byte;
   typedef signed int     FT_Int;
@@ -54,7 +54,7 @@
               (FT_ULong)_x4         )
 
 
-  /* from include/freetype2/ftsystem.h */
+  /* from include/freetype/ftsystem.h */
 
   typedef struct FT_MemoryRec_*  FT_Memory;
 
diff --git a/src/raster/ftraster.c b/src/raster/ftraster.c
index eeab143..e4bab98 100644
--- a/src/raster/ftraster.c
+++ b/src/raster/ftraster.c
@@ -24,8 +24,8 @@
   /*                                                                       */
   /* - copy `src/raster/ftraster.c' (this file) to your current directory  */
   /*                                                                       */
-  /* - copy `include/ftimage.h' and `src/raster/ftmisc.h' to your current  */
-  /*   directory                                                           */
+  /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' to your */
+  /*   current directory                                                   */
   /*                                                                       */
   /* - compile `ftraster' with the _STANDALONE_ macro defined, as in       */
   /*                                                                       */
@@ -450,7 +450,9 @@
 #define CEILING( x )  ( ( (x) + ras.precision - 1 ) & -ras.precision )
 #define TRUNC( x )    ( (Long)(x) >> ras.precision_bits )
 #define FRAC( x )     ( (x) & ( ras.precision - 1 ) )
-#define SCALED( x )   ( ( (Long)(x) << ras.scale_shift ) - ras.precision_half )
+#define SCALED( x )   ( ( (x) < 0 ? -( -(x) << ras.scale_shift )   \
+                                  :  (  (x) << ras.scale_shift ) ) \
+                        - ras.precision_half )
 
 #define IS_BOTTOM_OVERSHOOT( x ) \
           (Bool)( CEILING( x ) - x >= ras.precision_half )
@@ -799,15 +801,14 @@
 
     /* if it is <, simply insert it, ignore if == */
     if ( n >= 0 && y > y_turns[n] )
-      while ( n >= 0 )
+      do
       {
         Int  y2 = (Int)y_turns[n];
 
 
         y_turns[n] = y;
         y = y2;
-        n--;
-      }
+      } while ( --n >= 0 );
 
     if ( n < 0 )
     {
@@ -848,7 +849,7 @@
 
     if ( n > 1 && p )
     {
-      while ( n > 0 )
+      do
       {
         Int  bottom, top;
 
@@ -876,8 +877,7 @@
           return FAILURE;
 
         p = p->link;
-        n--;
-      }
+      } while ( --n );
     }
     else
       ras.fProfile = NULL;
@@ -1248,7 +1248,7 @@
 
     start_arc = arc;
 
-    while ( arc >= start_arc && e <= e2 )
+    do
     {
       ras.joint = FALSE;
 
@@ -1281,7 +1281,7 @@
         }
         arc -= degree;
       }
-    }
+    } while ( arc >= start_arc && e <= e2 );
 
   Fin:
     ras.top  = top;
@@ -2114,7 +2114,7 @@
     while ( current )
     {
       current->X       = *current->offset;
-      current->offset += current->flags & Flow_Up ? 1 : -1;
+      current->offset += ( current->flags & Flow_Up ) ? 1 : -1;
       current->height--;
       current = current->link;
     }
diff --git a/src/raster/ftrend1.h b/src/raster/ftrend1.h
index c367260..edc5d13 100644
--- a/src/raster/ftrend1.h
+++ b/src/raster/ftrend1.h
@@ -29,12 +29,6 @@
 
   FT_DECLARE_RENDERER( ft_raster1_renderer_class )
 
-  /* this renderer is _NOT_ part of the default modules, you'll need */
-  /* to register it by hand in your application.  It should only be  */
-  /* used for backwards-compatibility with FT 1.x anyway.            */
-  /*                                                                 */
-  FT_DECLARE_RENDERER( ft_raster5_renderer_class )
-
 
 FT_END_HEADER
 
diff --git a/src/raster/rastpic.c b/src/raster/rastpic.c
index fe58c99..77e7ec3 100644
--- a/src/raster/rastpic.c
+++ b/src/raster/rastpic.c
@@ -59,8 +59,9 @@
     FT_Memory          memory        = library->memory;
 
 
-    /* since this function also serves raster5 renderer, */
-    /* it implements reference counting                  */
+    /* XXX: since this function also served the no longer available  */
+    /*      raster5 renderer it uses reference counting, which could */
+    /*      be removed now                                           */
     if ( pic_container->raster )
     {
       ((RasterPIC*)pic_container->raster)->ref_count++;
@@ -82,21 +83,6 @@
     return error;
   }
 
-
-  /* re-route these init and free functions to the above functions */
-  FT_Error
-  ft_raster5_renderer_class_pic_init( FT_Library  library )
-  {
-    return ft_raster1_renderer_class_pic_init( library );
-  }
-
-
-  void
-  ft_raster5_renderer_class_pic_free( FT_Library  library )
-  {
-    ft_raster1_renderer_class_pic_free( library );
-  }
-
 #endif /* FT_CONFIG_OPTION_PIC */
 
 
diff --git a/src/raster/rastpic.h b/src/raster/rastpic.h
index a875884..408996a 100644
--- a/src/raster/rastpic.h
+++ b/src/raster/rastpic.h
@@ -20,11 +20,11 @@
 #define __RASTPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
 
+FT_BEGIN_HEADER
+
 #ifndef FT_CONFIG_OPTION_PIC
 
 #define FT_STANDARD_RASTER_GET  ft_standard_raster
@@ -48,15 +48,9 @@
   void
   ft_raster1_renderer_class_pic_free( FT_Library  library );
 
-  void
-  ft_raster5_renderer_class_pic_free( FT_Library  library );
-
   FT_Error
   ft_raster1_renderer_class_pic_init( FT_Library  library );
 
-  FT_Error
-  ft_raster5_renderer_class_pic_init( FT_Library  library );
-
 #endif /* FT_CONFIG_OPTION_PIC */
 
  /* */
diff --git a/src/sfnt/sfdriver.c b/src/sfnt/sfdriver.c
index 0948ad4..5dd8449 100644
--- a/src/sfnt/sfdriver.c
+++ b/src/sfnt/sfdriver.c
@@ -139,9 +139,9 @@
 
   FT_DEFINE_SERVICE_SFNT_TABLEREC(
     sfnt_service_sfnt_table,
-    (FT_SFNT_TableLoadFunc)tt_face_load_any,
-    (FT_SFNT_TableGetFunc) get_sfnt_table,
-    (FT_SFNT_TableInfoFunc)sfnt_table_info )
+    (FT_SFNT_TableLoadFunc)tt_face_load_any,     /* load_table */
+    (FT_SFNT_TableGetFunc) get_sfnt_table,       /* get_table  */
+    (FT_SFNT_TableInfoFunc)sfnt_table_info )     /* table_info */
 
 
 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
@@ -205,8 +205,8 @@
 
   FT_DEFINE_SERVICE_GLYPHDICTREC(
     sfnt_service_glyph_dict,
-    (FT_GlyphDict_GetNameFunc)  sfnt_get_glyph_name,
-    (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index )
+    (FT_GlyphDict_GetNameFunc)  sfnt_get_glyph_name,    /* get_name   */
+    (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index )   /* name_index */
 
 
 #endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
@@ -330,7 +330,7 @@
 
   FT_DEFINE_SERVICE_PSFONTNAMEREC(
     sfnt_service_ps_name,
-    (FT_PsName_GetFunc)sfnt_get_ps_name )
+    (FT_PsName_GetFunc)sfnt_get_ps_name )     /* get_ps_font_name */
 
 
   /*
@@ -338,7 +338,7 @@
    */
   FT_DEFINE_SERVICE_TTCMAPSREC(
     tt_service_get_cmap_info,
-    (TT_CMap_Info_GetFunc)tt_get_cmap_info )
+    (TT_CMap_Info_GetFunc)tt_get_cmap_info )  /* get_cmap_info */
 
 
 #ifdef TT_CONFIG_OPTION_BDF
@@ -381,8 +381,8 @@
 
   FT_DEFINE_SERVICE_BDFRec(
     sfnt_service_bdf,
-    (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id,
-    (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop )
+    (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id,     /* get_charset_id */
+    (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop )  /* get_property   */
 
 
 #endif /* TT_CONFIG_OPTION_BDF */
@@ -505,7 +505,9 @@
     PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike     ),
     PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ),
 
-    tt_face_get_metrics
+    tt_face_get_metrics,
+
+    tt_face_get_name
   )
 
 
diff --git a/src/sfnt/sfntpic.h b/src/sfnt/sfntpic.h
index 563d634..d99be6a 100644
--- a/src/sfnt/sfntpic.h
+++ b/src/sfnt/sfntpic.h
@@ -20,8 +20,6 @@
 #define __SFNTPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
 
@@ -31,7 +29,6 @@
 #define SFNT_SERVICE_GLYPH_DICT_GET  sfnt_service_glyph_dict
 #define SFNT_SERVICE_PS_NAME_GET     sfnt_service_ps_name
 #define TT_SERVICE_CMAP_INFO_GET     tt_service_get_cmap_info
-#define SFNT_SERVICES_GET            sfnt_services
 #define TT_CMAP_CLASSES_GET          tt_cmap_classes
 #define SFNT_SERVICE_SFNT_TABLE_GET  sfnt_service_sfnt_table
 #define SFNT_SERVICE_BDF_GET         sfnt_service_bdf
@@ -56,6 +53,8 @@
 #include "ttcmap.h"
 
 
+FT_BEGIN_HEADER
+
   typedef struct  sfntModulePIC_
   {
     FT_ServiceDescRec*        sfnt_services;
@@ -83,8 +82,6 @@
           ( GET_PIC( library )->sfnt_service_ps_name )
 #define TT_SERVICE_CMAP_INFO_GET                           \
           ( GET_PIC( library )->tt_service_get_cmap_info )
-#define SFNT_SERVICES_GET                       \
-          ( GET_PIC( library )->sfnt_services )
 #define TT_CMAP_CLASSES_GET                       \
           ( GET_PIC( library )->tt_cmap_classes )
 #define SFNT_SERVICE_SFNT_TABLE_GET                       \
@@ -102,12 +99,13 @@
   FT_Error
   sfnt_module_class_pic_init( FT_Library  library );
 
+
+FT_END_HEADER
+
 #endif /* FT_CONFIG_OPTION_PIC */
 
   /* */
 
-FT_END_HEADER
-
 #endif /* __SFNTPIC_H__ */
 
 
diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c
index 40c27fa..de030ea 100644
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -120,27 +120,9 @@
                                                    FT_Memory     memory );
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Function>                                                            */
-  /*    tt_face_get_name                                                   */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    Returns a given ENGLISH name record in ASCII.                      */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    face   :: A handle to the source face object.                      */
-  /*                                                                       */
-  /*    nameid :: The name id of the name record to return.                */
-  /*                                                                       */
-  /* <InOut>                                                               */
-  /*    name   :: The address of a string pointer.  NULL if no name is     */
-  /*              present.                                                 */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    FreeType error code.  0 means success.                             */
-  /*                                                                       */
-  static FT_Error
+  /* documentation is in sfnt.h */
+
+  FT_LOCAL_DEF( FT_Error )
   tt_face_get_name( TT_Face      face,
                     FT_UShort    nameid,
                     FT_String**  name )
@@ -469,10 +451,14 @@
                                      woff.metaOrigLength != 0 ) ) ||
          ( woff.metaLength != 0 && woff.metaOrigLength == 0 )     ||
          ( woff.privOffset == 0 && woff.privLength != 0 )         )
+    {
+      FT_ERROR(( "woff_font_open: invalid WOFF header\n" ));
       return FT_THROW( Invalid_Table );
+    }
 
-    if ( FT_ALLOC( sfnt, woff.totalSfntSize ) ||
-         FT_NEW( sfnt_stream )                )
+    /* Don't trust `totalSfntSize' before thorough checks. */
+    if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) ||
+         FT_NEW( sfnt_stream )                         )
       goto Exit;
 
     sfnt_header = sfnt;
@@ -539,6 +525,8 @@
       if ( table->Tag <= old_tag )
       {
         FT_FRAME_EXIT();
+
+        FT_ERROR(( "woff_font_open: table tags are not sorted\n" ));
         error = FT_THROW( Invalid_Table );
         goto Exit;
       }
@@ -573,6 +561,7 @@
            sfnt_offset > woff.totalSfntSize - table->OrigLength ||
            table->CompLength > table->OrigLength                )
       {
+        FT_ERROR(( "woff_font_open: invalid table offsets\n" ));
         error = FT_THROW( Invalid_Table );
         goto Exit;
       }
@@ -598,6 +587,8 @@
       if ( woff.metaOffset != woff_offset                  ||
            woff.metaOffset + woff.metaLength > woff.length )
       {
+        FT_ERROR(( "woff_font_open:"
+                   " invalid `metadata' offset or length\n" ));
         error = FT_THROW( Invalid_Table );
         goto Exit;
       }
@@ -614,6 +605,7 @@
       if ( woff.privOffset != woff_offset                  ||
            woff.privOffset + woff.privLength > woff.length )
       {
+        FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" ));
         error = FT_THROW( Invalid_Table );
         goto Exit;
       }
@@ -625,10 +617,19 @@
     if ( sfnt_offset != woff.totalSfntSize ||
          woff_offset != woff.length        )
     {
+      FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" ));
       error = FT_THROW( Invalid_Table );
       goto Exit;
     }
 
+    /* Now use `totalSfntSize'. */
+    if ( FT_REALLOC( sfnt,
+                     12 + woff.num_tables * 16UL,
+                     woff.totalSfntSize ) )
+      goto Exit;
+
+    sfnt_header = sfnt + 12;
+
     /* Write the tables. */
 
     for ( nn = 0; nn < woff.num_tables; nn++ )
@@ -669,6 +670,7 @@
           goto Exit;
         if ( output_len != table->OrigLength )
         {
+          FT_ERROR(( "woff_font_open: compressed table length mismatch\n" ));
           error = FT_THROW( Invalid_Table );
           goto Exit;
         }
@@ -839,13 +841,14 @@
   FT_LOCAL_DEF( FT_Error )
   sfnt_init_face( FT_Stream      stream,
                   TT_Face        face,
-                  FT_Int         face_index,
+                  FT_Int         face_instance_index,
                   FT_Int         num_params,
                   FT_Parameter*  params )
   {
-    FT_Error        error;
-    FT_Library      library = face->root.driver->root.library;
-    SFNT_Service    sfnt;
+    FT_Error      error;
+    FT_Library    library = face->root.driver->root.library;
+    SFNT_Service  sfnt;
+    FT_Int        face_index;
 
 
     /* for now, parameters are unused */
@@ -878,22 +881,97 @@
     /* Stream may have changed in sfnt_open_font. */
     stream = face->root.stream;
 
-    FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_index ));
+    FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_instance_index ));
 
-    if ( face_index < 0 )
-      face_index = 0;
+    face_index = FT_ABS( face_instance_index ) & 0xFFFF;
 
     if ( face_index >= face->ttc_header.count )
-      return FT_THROW( Invalid_Argument );
+    {
+      if ( face_instance_index >= 0 )
+        return FT_THROW( Invalid_Argument );
+      else
+        face_index = 0;
+    }
 
     if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) )
       return error;
 
-    /* check that we have a valid TrueType file */
+    /* check whether we have a valid TrueType file */
     error = sfnt->load_font_dir( face, stream );
     if ( error )
       return error;
 
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+    {
+      FT_ULong  fvar_len;
+
+      FT_ULong  version;
+      FT_ULong  offset;
+
+      FT_UShort  num_axes;
+      FT_UShort  axis_size;
+      FT_UShort  num_instances;
+      FT_UShort  instance_size;
+
+      FT_Int  instance_index;
+
+
+      instance_index = FT_ABS( face_instance_index ) >> 16;
+
+      /* test whether current face is a GX font with named instances */
+      if ( face->goto_table( face, TTAG_fvar, stream, &fvar_len ) ||
+           fvar_len < 20                                          ||
+           FT_READ_ULONG( version )                               ||
+           FT_READ_USHORT( offset )                               ||
+           FT_STREAM_SKIP( 2 )                                    ||
+           FT_READ_USHORT( num_axes )                             ||
+           FT_READ_USHORT( axis_size )                            ||
+           FT_READ_USHORT( num_instances )                        ||
+           FT_READ_USHORT( instance_size )                        )
+      {
+        version       = 0;
+        offset        = 0;
+        num_axes      = 0;
+        axis_size     = 0;
+        num_instances = 0;
+        instance_size = 0;
+      }
+
+      /* check that the data is bound by the table length; */
+      /* based on similar code in function `TT_Get_MM_Var' */
+      if ( version != 0x00010000UL                    ||
+           axis_size != 20                            ||
+           num_axes > 0x3FFE                          ||
+           instance_size != 4 + 4 * num_axes          ||
+           num_instances > 0x7EFF                     ||
+           offset                          +
+             axis_size * num_axes          +
+             instance_size * num_instances > fvar_len )
+        num_instances = 0;
+
+      /* we support at most 2^15 - 1 instances */
+      if ( num_instances >= ( 1U << 15 ) - 1 )
+      {
+        if ( face_instance_index >= 0 )
+          return FT_THROW( Invalid_Argument );
+        else
+          num_instances = 0;
+      }
+
+      /* instance indices in `face_instance_index' start with index 1, */
+      /* thus `>' and not `>='                                         */
+      if ( instance_index > num_instances )
+      {
+        if ( face_instance_index >= 0 )
+          return FT_THROW( Invalid_Argument );
+        else
+          num_instances = 0;
+      }
+
+      face->root.style_flags = (FT_Long)num_instances << 16;
+    }
+#endif
+
     face->root.num_faces  = face->ttc_header.count;
     face->root.face_index = face_index;
 
@@ -946,7 +1024,7 @@
   FT_LOCAL_DEF( FT_Error )
   sfnt_load_face( FT_Stream      stream,
                   TT_Face        face,
-                  FT_Int         face_index,
+                  FT_Int         face_instance_index,
                   FT_Int         num_params,
                   FT_Parameter*  params )
   {
@@ -962,7 +1040,7 @@
 
     SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
 
-    FT_UNUSED( face_index );
+    FT_UNUSED( face_instance_index );
 
 
     /* Check parameters */
@@ -1284,7 +1362,7 @@
           flags |= FT_STYLE_FLAG_ITALIC;
       }
 
-      root->style_flags = flags;
+      root->style_flags |= flags;
 
       /*********************************************************************/
       /*                                                                   */
diff --git a/src/sfnt/sfobjs.h b/src/sfnt/sfobjs.h
index 77c7d92..455f867 100644
--- a/src/sfnt/sfobjs.h
+++ b/src/sfnt/sfobjs.h
@@ -31,20 +31,25 @@
   FT_LOCAL( FT_Error )
   sfnt_init_face( FT_Stream      stream,
                   TT_Face        face,
-                  FT_Int         face_index,
+                  FT_Int         face_instance_index,
                   FT_Int         num_params,
                   FT_Parameter*  params );
 
   FT_LOCAL( FT_Error )
   sfnt_load_face( FT_Stream      stream,
                   TT_Face        face,
-                  FT_Int         face_index,
+                  FT_Int         face_instance_index,
                   FT_Int         num_params,
                   FT_Parameter*  params );
 
   FT_LOCAL( void )
   sfnt_done_face( TT_Face  face );
 
+  FT_LOCAL( FT_Error )
+  tt_face_get_name( TT_Face      face,
+                    FT_UShort    nameid,
+                    FT_String**  name );
+
 
 FT_END_HEADER
 
diff --git a/src/sfnt/ttcmap.c b/src/sfnt/ttcmap.c
index 815ee7c..2b1337f 100644
--- a/src/sfnt/ttcmap.c
+++ b/src/sfnt/ttcmap.c
@@ -51,6 +51,13 @@
 #define TT_NEXT_ULONG   FT_NEXT_ULONG
 
 
+  /* Too large glyph index return values are caught in `FT_Get_Char_Index' */
+  /* and `FT_Get_Next_Char' (the latter calls the internal `next' function */
+  /* again in this case).  To mark character code return values as invalid */
+  /* it is sufficient to set the corresponding glyph index return value to */
+  /* zero.                                                                 */
+
+
   FT_CALLBACK_DEF( FT_Error )
   tt_cmap_init( TT_CMap   cmap,
                 FT_Byte*  table )
@@ -199,7 +206,7 @@
   /*****                          FORMAT 2                             *****/
   /*****                                                               *****/
   /***** This is used for certain CJK encodings that encode text in a  *****/
-  /***** mixed 8/16 bits encoding along the following lines:           *****/
+  /***** mixed 8/16 bits encoding along the following lines.           *****/
   /*****                                                               *****/
   /***** * Certain byte values correspond to an 8-bit character code   *****/
   /*****   (typically in the range 0..127 for ASCII compatibility).    *****/
@@ -209,19 +216,19 @@
   /*****   second byte of a 2-byte character).                         *****/
   /*****                                                               *****/
   /***** The following charmap lookup and iteration functions all      *****/
-  /***** assume that the value "charcode" correspond to following:     *****/
+  /***** assume that the value `charcode' fulfills the following.      *****/
   /*****                                                               *****/
-  /*****   - For one byte characters, "charcode" is simply the         *****/
+  /*****   - For one byte characters, `charcode' is simply the         *****/
   /*****     character code.                                           *****/
   /*****                                                               *****/
-  /*****   - For two byte characters, "charcode" is the 2-byte         *****/
-  /*****     character code in big endian format.  More exactly:       *****/
+  /*****   - For two byte characters, `charcode' is the 2-byte         *****/
+  /*****     character code in big endian format.  More precisely:     *****/
   /*****                                                               *****/
   /*****       (charcode >> 8)    is the first byte value              *****/
   /*****       (charcode & 0xFF)  is the second byte value             *****/
   /*****                                                               *****/
-  /***** Note that not all values of "charcode" are valid according    *****/
-  /***** to these rules, and the function moderately check the         *****/
+  /***** Note that not all values of `charcode' are valid according    *****/
+  /***** to these rules, and the function moderately checks the        *****/
   /***** arguments.                                                    *****/
   /*****                                                               *****/
   /*************************************************************************/
@@ -249,7 +256,7 @@
   /* table, i.e., it is the corresponding sub-header index multiplied      */
   /* by 8.                                                                 */
   /*                                                                       */
-  /* Each sub-header has the following format:                             */
+  /* Each sub-header has the following format.                             */
   /*                                                                       */
   /*   NAME        OFFSET      TYPE            DESCRIPTION                 */
   /*                                                                       */
@@ -264,11 +271,11 @@
   /* according to the specification.                                       */
   /*                                                                       */
   /* If a character code is contained within a given sub-header, then      */
-  /* mapping it to a glyph index is done as follows:                       */
+  /* mapping it to a glyph index is done as follows.                       */
   /*                                                                       */
   /* * The value of `offset' is read.  This is a _byte_ distance from the  */
   /*   location of the `offset' field itself into a slice of the           */
-  /*   `glyph_ids' table.  Let's call it `slice' (it is a USHORT[] too).   */
+  /*   `glyph_ids' table.  Let's call it `slice' (it is a USHORT[], too).  */
   /*                                                                       */
   /* * The value `slice[char.lo - first]' is read.  If it is 0, there is   */
   /*   no glyph for the charcode.  Otherwise, the value of `delta' is      */
@@ -326,7 +333,7 @@
     FT_ASSERT( p == table + 518 );
 
     subs      = p;
-    glyph_ids = subs + (max_subs + 1) * 8;
+    glyph_ids = subs + ( max_subs + 1 ) * 8;
     if ( glyph_ids > valid->limit )
       FT_INVALID_TOO_SHORT;
 
@@ -436,6 +443,7 @@
       }
       result = sub;
     }
+
   Exit:
     return result;
   }
@@ -475,6 +483,7 @@
           result = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU;
       }
     }
+
     return result;
   }
 
@@ -765,7 +774,7 @@
     if ( charcode < cmap->cur_start )
       charcode = cmap->cur_start;
 
-    for ( ;; )
+    for (;;)
     {
       FT_Byte*  values = cmap->cur_values;
       FT_UInt   end    = cmap->cur_end;
@@ -973,7 +982,7 @@
           /* segment if it contains only a single character.     */
           /*                                                     */
           /* We thus omit the test here, delaying it to the      */
-          /* routines which actually access the cmap.            */
+          /* routines that actually access the cmap.             */
           else if ( n != num_segs - 1                       ||
                     !( start == 0xFFFFU && end == 0xFFFFU ) )
           {
@@ -1026,12 +1035,17 @@
                             FT_UInt32*  pcharcode,
                             FT_Bool     next )
   {
+    TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
+    FT_Byte*  limit = face->cmap_table + face->cmap_size;
+
+
     FT_UInt    num_segs2, start, end, offset;
     FT_Int     delta;
     FT_UInt    i, num_segs;
     FT_UInt32  charcode = *pcharcode;
     FT_UInt    gindex   = 0;
     FT_Byte*   p;
+    FT_Byte*   q;
 
 
     p = cmap->data + 6;
@@ -1045,65 +1059,106 @@
     if ( next )
       charcode++;
 
+    if ( charcode > 0xFFFFU )
+      return 0;
+
     /* linear search */
-    for ( ; charcode <= 0xFFFFU; charcode++ )
+    p = cmap->data + 14;               /* ends table   */
+    q = cmap->data + 16 + num_segs2;   /* starts table */
+
+    for ( i = 0; i < num_segs; i++ )
     {
-      FT_Byte*  q;
+      end   = TT_NEXT_USHORT( p );
+      start = TT_NEXT_USHORT( q );
 
-
-      p = cmap->data + 14;               /* ends table   */
-      q = cmap->data + 16 + num_segs2;   /* starts table */
-
-      for ( i = 0; i < num_segs; i++ )
+      if ( charcode < start )
       {
-        end   = TT_NEXT_USHORT( p );
-        start = TT_NEXT_USHORT( q );
-
-        if ( charcode >= start && charcode <= end )
-        {
-          p       = q - 2 + num_segs2;
-          delta   = TT_PEEK_SHORT( p );
-          p      += num_segs2;
-          offset  = TT_PEEK_USHORT( p );
-
-          /* some fonts have an incorrect last segment; */
-          /* we have to catch it                        */
-          if ( i >= num_segs - 1                  &&
-               start == 0xFFFFU && end == 0xFFFFU )
-          {
-            TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
-            FT_Byte*  limit = face->cmap_table + face->cmap_size;
-
-
-            if ( offset && p + offset + 2 > limit )
-            {
-              delta  = 1;
-              offset = 0;
-            }
-          }
-
-          if ( offset == 0xFFFFU )
-            continue;
-
-          if ( offset )
-          {
-            p += offset + ( charcode - start ) * 2;
-            gindex = TT_PEEK_USHORT( p );
-            if ( gindex != 0 )
-              gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
-          }
-          else
-            gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
-
+        if ( next )
+          charcode = start;
+        else
           break;
-        }
       }
 
-      if ( !next || gindex )
+    Again:
+      if ( charcode <= end )
+      {
+        FT_Byte*  r;
+
+
+        r       = q - 2 + num_segs2;
+        delta   = TT_PEEK_SHORT( r );
+        r      += num_segs2;
+        offset  = TT_PEEK_USHORT( r );
+
+        /* some fonts have an incorrect last segment; */
+        /* we have to catch it                        */
+        if ( i >= num_segs - 1                  &&
+             start == 0xFFFFU && end == 0xFFFFU )
+        {
+          if ( offset && r + offset + 2 > limit )
+          {
+            delta  = 1;
+            offset = 0;
+          }
+        }
+
+        if ( offset == 0xFFFFU )
+          continue;
+
+        if ( offset )
+        {
+          r += offset + ( charcode - start ) * 2;
+
+          /* if r > limit, the whole segment is invalid */
+          if ( next && r > limit )
+            continue;
+
+          gindex = TT_PEEK_USHORT( r );
+          if ( gindex )
+          {
+            gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
+            if ( gindex >= (FT_UInt)face->root.num_glyphs )
+              gindex = 0;
+          }
+        }
+        else
+        {
+          gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
+
+          if ( next && gindex >= (FT_UInt)face->root.num_glyphs )
+          {
+            /* we have an invalid glyph index; if there is an overflow, */
+            /* we can adjust `charcode', otherwise the whole segment is */
+            /* invalid                                                  */
+            gindex = 0;
+
+            if ( (FT_Int)charcode + delta < 0 &&
+                 (FT_Int)end + delta >= 0     )
+              charcode = (FT_UInt)( -delta );
+
+            else if ( (FT_Int)charcode + delta < 0x10000L &&
+                      (FT_Int)end + delta >= 0x10000L     )
+              charcode = (FT_UInt)( 0x10000L - delta );
+
+            else
+              continue;
+          }
+        }
+
+        if ( next && !gindex )
+        {
+          if ( charcode >= 0xFFFFU )
+            break;
+
+          charcode++;
+          goto Again;
+        }
+
         break;
+      }
     }
 
-    if ( next && gindex )
+    if ( next )
       *pcharcode = charcode;
 
     return gindex;
@@ -1310,7 +1365,6 @@
 
       /* if `charcode' is not in any segment, then `mid' is */
       /* the segment nearest to `charcode'                  */
-      /*                                                    */
 
       if ( charcode > end )
       {
@@ -1443,7 +1497,7 @@
   /*                                                                       */
   /*   NAME        OFFSET          TYPE             DESCRIPTION            */
   /*                                                                       */
-  /*   format       0              USHORT           must be 4              */
+  /*   format       0              USHORT           must be 6              */
   /*   length       2              USHORT           table length in bytes  */
   /*   language     4              USHORT           Mac language code      */
   /*                                                                       */
@@ -1511,6 +1565,7 @@
       p += 2 * idx;
       result = TT_PEEK_USHORT( p );
     }
+
     return result;
   }
 
@@ -1531,7 +1586,7 @@
 
 
     if ( char_code >= 0x10000UL )
-      goto Exit;
+      return 0;
 
     if ( char_code < start )
       char_code = start;
@@ -1547,10 +1602,13 @@
         result = char_code;
         break;
       }
+
+      if ( char_code >= 0xFFFFU )
+        return 0;
+
       char_code++;
     }
 
-  Exit:
     *pchar_code = result;
     return gindex;
   }
@@ -1602,7 +1660,7 @@
   /*****                                                               *****/
   /***** The purpose of this format is to easily map UTF-16 text to    *****/
   /***** glyph indices.  Basically, the `char_code' must be in one of  *****/
-  /***** the following formats:                                        *****/
+  /***** the following formats.                                        *****/
   /*****                                                               *****/
   /*****   - A 16-bit value that isn't part of the Unicode Surrogates  *****/
   /*****     Area (i.e. U+D800-U+DFFF).                                *****/
@@ -1615,7 +1673,7 @@
   /***** The `is32' table embedded in the charmap indicates whether a  *****/
   /***** given 16-bit value is in the surrogates area or not.          *****/
   /*****                                                               *****/
-  /***** So, for any given `char_code', we can assert the following:   *****/
+  /***** So, for any given `char_code', we can assert the following.   *****/
   /*****                                                               *****/
   /*****   If `char_hi == 0' then we must have `is32[char_lo] == 0'.   *****/
   /*****                                                               *****/
@@ -1770,7 +1828,10 @@
 
       if ( char_code <= end )
       {
-        result = (FT_UInt)( start_id + char_code - start );
+        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
+          return 0;
+
+        result = (FT_UInt)( start_id + ( char_code - start ) );
         break;
       }
     }
@@ -1782,8 +1843,9 @@
   tt_cmap8_char_next( TT_CMap     cmap,
                       FT_UInt32  *pchar_code )
   {
+    FT_Face    face       = cmap->cmap.charmap.face;
     FT_UInt32  result     = 0;
-    FT_UInt32  char_code  = *pchar_code + 1;
+    FT_UInt32  char_code;
     FT_UInt    gindex     = 0;
     FT_Byte*   table      = cmap->data;
     FT_Byte*   p          = table + 8204;
@@ -1791,6 +1853,11 @@
     FT_UInt32  start, end, start_id;
 
 
+    if ( *pchar_code >= 0xFFFFFFFFUL )
+      return 0;
+
+    char_code = *pchar_code + 1;
+
     p = table + 8208;
 
     for ( ; num_groups > 0; num_groups-- )
@@ -1802,18 +1869,38 @@
       if ( char_code < start )
         char_code = start;
 
+    Again:
       if ( char_code <= end )
       {
-        gindex = (FT_UInt)( char_code - start + start_id );
-        if ( gindex != 0 )
+        /* ignore invalid group */
+        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
+          continue;
+
+        gindex = (FT_UInt)( start_id + ( char_code - start ) );
+
+        /* does first element of group point to `.notdef' glyph? */
+        if ( gindex == 0 )
         {
-          result = char_code;
-          goto Exit;
+          if ( char_code >= 0xFFFFFFFFUL )
+            break;
+
+          char_code++;
+          goto Again;
         }
+
+        /* if `gindex' is invalid, the remaining values */
+        /* in this group are invalid, too               */
+        if ( gindex >= (FT_UInt)face->num_glyphs )
+        {
+          gindex = 0;
+          continue;
+        }
+
+        result = char_code;
+        break;
       }
     }
 
-  Exit:
     *pchar_code = result;
     return gindex;
   }
@@ -1930,14 +2017,20 @@
     FT_Byte*   p      = table + 12;
     FT_UInt32  start  = TT_NEXT_ULONG( p );
     FT_UInt32  count  = TT_NEXT_ULONG( p );
-    FT_UInt32  idx    = (FT_ULong)( char_code - start );
+    FT_UInt32  idx;
 
 
+    if ( char_code < start )
+      return 0;
+
+    idx = char_code - start;
+
     if ( idx < count )
     {
       p     += 2 * idx;
       result = TT_PEEK_USHORT( p );
     }
+
     return result;
   }
 
@@ -1947,7 +2040,7 @@
                        FT_UInt32  *pchar_code )
   {
     FT_Byte*   table     = cmap->data;
-    FT_UInt32  char_code = *pchar_code + 1;
+    FT_UInt32  char_code;
     FT_UInt    gindex    = 0;
     FT_Byte*   p         = table + 12;
     FT_UInt32  start     = TT_NEXT_ULONG( p );
@@ -1955,10 +2048,15 @@
     FT_UInt32  idx;
 
 
+    if ( *pchar_code >= 0xFFFFFFFFUL )
+      return 0;
+
+    char_code = *pchar_code + 1;
+
     if ( char_code < start )
       char_code = start;
 
-    idx = (FT_UInt32)( char_code - start );
+    idx = char_code - start;
     p  += 2 * idx;
 
     for ( ; idx < count; idx++ )
@@ -1966,6 +2064,10 @@
       gindex = TT_NEXT_USHORT( p );
       if ( gindex != 0 )
         break;
+
+      if ( char_code >= 0xFFFFFFFFUL )
+        return 0;
+
       char_code++;
     }
 
@@ -2134,6 +2236,7 @@
   static void
   tt_cmap12_next( TT_CMap12  cmap )
   {
+    FT_Face   face = cmap->cmap.cmap.charmap.face;
     FT_Byte*  p;
     FT_ULong  start, end, start_id, char_code;
     FT_ULong  n;
@@ -2155,18 +2258,38 @@
       if ( char_code < start )
         char_code = start;
 
-      for ( ; char_code <= end; char_code++ )
+    Again:
+      if ( char_code <= end )
       {
-        gindex = (FT_UInt)( start_id + char_code - start );
+        /* ignore invalid group */
+        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
+          continue;
 
-        if ( gindex )
+        gindex = (FT_UInt)( start_id + ( char_code - start ) );
+
+        /* does first element of group point to `.notdef' glyph? */
+        if ( gindex == 0 )
         {
-          cmap->cur_charcode = char_code;;
-          cmap->cur_gindex   = gindex;
-          cmap->cur_group    = n;
+          if ( char_code >= 0xFFFFFFFFUL )
+            goto Fail;
 
-          return;
+          char_code++;
+          goto Again;
         }
+
+        /* if `gindex' is invalid, the remaining values */
+        /* in this group are invalid, too               */
+        if ( gindex >= (FT_UInt)face->num_glyphs )
+        {
+          gindex = 0;
+          continue;
+        }
+
+        cmap->cur_charcode = char_code;
+        cmap->cur_gindex   = gindex;
+        cmap->cur_group    = n;
+
+        return;
       }
     }
 
@@ -2196,7 +2319,12 @@
     end = 0xFFFFFFFFUL;
 
     if ( next )
+    {
+      if ( char_code >= 0xFFFFFFFFUL )
+        return 0;
+
       char_code++;
+    }
 
     min = 0;
     max = num_groups;
@@ -2217,20 +2345,24 @@
       else
       {
         start_id = TT_PEEK_ULONG( p );
-        gindex = (FT_UInt)( start_id + char_code - start );
 
+        /* reject invalid glyph index */
+        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
+          gindex = 0;
+        else
+          gindex = (FT_UInt)( start_id + ( char_code - start ) );
         break;
       }
     }
 
     if ( next )
     {
+      FT_Face    face   = cmap->cmap.charmap.face;
       TT_CMap12  cmap12 = (TT_CMap12)cmap;
 
 
       /* if `char_code' is not in any group, then `mid' is */
       /* the group nearest to `char_code'                  */
-      /*                                                   */
 
       if ( char_code > end )
       {
@@ -2243,6 +2375,9 @@
       cmap12->cur_charcode = char_code;
       cmap12->cur_group    = mid;
 
+      if ( gindex >= (FT_UInt)face->num_glyphs )
+        gindex = 0;
+
       if ( !gindex )
       {
         tt_cmap12_next( cmap12 );
@@ -2253,8 +2388,7 @@
       else
         cmap12->cur_gindex = gindex;
 
-      if ( gindex )
-        *pchar_code = cmap12->cur_charcode;
+      *pchar_code = cmap12->cur_charcode;
     }
 
     return gindex;
@@ -2274,23 +2408,17 @@
                        FT_UInt32  *pchar_code )
   {
     TT_CMap12  cmap12 = (TT_CMap12)cmap;
-    FT_ULong   gindex;
+    FT_UInt    gindex;
 
 
-    if ( cmap12->cur_charcode >= 0xFFFFFFFFUL )
-      return 0;
-
     /* no need to search */
     if ( cmap12->valid && cmap12->cur_charcode == *pchar_code )
     {
       tt_cmap12_next( cmap12 );
       if ( cmap12->valid )
       {
-        gindex = cmap12->cur_gindex;
-
-        /* XXX: check cur_charcode overflow is expected */
-        if ( gindex )
-          *pchar_code = (FT_UInt32)cmap12->cur_charcode;
+        gindex      = cmap12->cur_gindex;
+        *pchar_code = (FT_UInt32)cmap12->cur_charcode;
       }
       else
         gindex = 0;
@@ -2298,8 +2426,7 @@
     else
       gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 );
 
-    /* XXX: check gindex overflow is expected */
-    return (FT_UInt32)gindex;
+    return gindex;
   }
 
 
@@ -2458,6 +2585,7 @@
   static void
   tt_cmap13_next( TT_CMap13  cmap )
   {
+    FT_Face   face = cmap->cmap.cmap.charmap.face;
     FT_Byte*  p;
     FT_ULong  start, end, glyph_id, char_code;
     FT_ULong  n;
@@ -2483,9 +2611,9 @@
       {
         gindex = (FT_UInt)glyph_id;
 
-        if ( gindex )
+        if ( gindex && gindex < (FT_UInt)face->num_glyphs )
         {
-          cmap->cur_charcode = char_code;;
+          cmap->cur_charcode = char_code;
           cmap->cur_gindex   = gindex;
           cmap->cur_group    = n;
 
@@ -2520,7 +2648,12 @@
     end = 0xFFFFFFFFUL;
 
     if ( next )
+    {
+      if ( char_code >= 0xFFFFFFFFUL )
+        return 0;
+
       char_code++;
+    }
 
     min = 0;
     max = num_groups;
@@ -2548,6 +2681,7 @@
 
     if ( next )
     {
+      FT_Face    face   = cmap->cmap.charmap.face;
       TT_CMap13  cmap13 = (TT_CMap13)cmap;
 
 
@@ -2565,6 +2699,9 @@
       cmap13->cur_charcode = char_code;
       cmap13->cur_group    = mid;
 
+      if ( gindex >= (FT_UInt)face->num_glyphs )
+        gindex = 0;
+
       if ( !gindex )
       {
         tt_cmap13_next( cmap13 );
@@ -2575,8 +2712,7 @@
       else
         cmap13->cur_gindex = gindex;
 
-      if ( gindex )
-        *pchar_code = cmap13->cur_charcode;
+      *pchar_code = cmap13->cur_charcode;
     }
 
     return gindex;
@@ -2599,18 +2735,14 @@
     FT_UInt    gindex;
 
 
-    if ( cmap13->cur_charcode >= 0xFFFFFFFFUL )
-      return 0;
-
     /* no need to search */
     if ( cmap13->valid && cmap13->cur_charcode == *pchar_code )
     {
       tt_cmap13_next( cmap13 );
       if ( cmap13->valid )
       {
-        gindex = cmap13->cur_gindex;
-        if ( gindex )
-          *pchar_code = cmap13->cur_charcode;
+        gindex      = cmap13->cur_gindex;
+        *pchar_code = cmap13->cur_charcode;
       }
       else
         gindex = 0;
@@ -2836,12 +2968,17 @@
         /* 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_Byte*  defp     = table + defOff;
+          FT_ULong  numRanges;
           FT_ULong  i;
-          FT_ULong  lastBase  = 0;
+          FT_ULong  lastBase = 0;
 
 
+          if ( defp + 4 > valid->limit )
+            FT_INVALID_TOO_SHORT;
+
+          numRanges = TT_NEXT_ULONG( defp );
+
           /* defp + numRanges * 4 > valid->limit ? */
           if ( numRanges > (FT_ULong)( valid->limit - defp ) / 4 )
             FT_INVALID_TOO_SHORT;
@@ -2865,13 +3002,18 @@
         /* 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, lastUni  = 0;
+          FT_Byte*  ndp        = table + nondefOff;
+          FT_ULong  numMappings;
+          FT_ULong  i, lastUni = 0;
 
 
-          /* numMappings * 4 > (FT_ULong)( valid->limit - ndp ) ? */
-          if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 4 )
+          if ( ndp + 4 > valid->limit )
+            FT_INVALID_TOO_SHORT;
+
+          numMappings = TT_NEXT_ULONG( ndp );
+
+          /* numMappings * 5 > (FT_ULong)( valid->limit - ndp ) ? */
+          if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 5 )
             FT_INVALID_TOO_SHORT;
 
           for ( i = 0; i < numMappings; ++i )
@@ -3316,7 +3458,7 @@
       ni   = 1;
       i    = 0;
 
-      for ( ;; )
+      for (;;)
       {
         if ( nuni > duni + dcnt )
         {
diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c
index ad2975d..c1bd7f0 100644
--- a/src/sfnt/ttload.c
+++ b/src/sfnt/ttload.c
@@ -151,7 +151,8 @@
 
   /* Here, we                                                         */
   /*                                                                  */
-  /* - check that `num_tables' is valid (and adjust it if necessary)  */
+  /* - check that `num_tables' is valid (and adjust it if necessary); */
+  /*   also return the number of valid table entries                  */
   /*                                                                  */
   /* - look for a `head' table, check its size, and parse it to check */
   /*   whether its `magic' field is correctly set                     */
@@ -167,7 +168,8 @@
   /*                                                                  */
   static FT_Error
   check_table_dir( SFNT_Header  sfnt,
-                   FT_Stream    stream )
+                   FT_Stream    stream,
+                   FT_UShort*   valid )
   {
     FT_Error   error;
     FT_UShort  nn, valid_entries = 0;
@@ -209,7 +211,10 @@
       /* we ignore invalid tables */
 
       if ( table.Offset > stream->size )
+      {
+        FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn ));
         continue;
+      }
       else if ( table.Length > stream->size - table.Offset )
       {
         /* Some tables have such a simple structure that clipping its     */
@@ -273,11 +278,11 @@
         has_meta = 1;
     }
 
-    sfnt->num_tables = valid_entries;
+    *valid = valid_entries;
 
-    if ( sfnt->num_tables == 0 )
+    if ( !valid_entries )
     {
-      FT_TRACE2(( "check_table_dir: no tables found\n" ));
+      FT_TRACE2(( "check_table_dir: no valid tables found\n" ));
       error = FT_THROW( Unknown_File_Format );
       goto Exit;
     }
@@ -333,8 +338,7 @@
     SFNT_HeaderRec  sfnt;
     FT_Error        error;
     FT_Memory       memory = stream->memory;
-    TT_TableRec*    entry;
-    FT_Int          nn;
+    FT_UShort       nn, valid_entries;
 
     static const FT_Frame_Field  offset_table_fields[] =
     {
@@ -375,85 +379,114 @@
     if ( sfnt.format_tag != TTAG_OTTO )
     {
       /* check first */
-      error = check_table_dir( &sfnt, stream );
+      error = check_table_dir( &sfnt, stream, &valid_entries );
       if ( error )
       {
         FT_TRACE2(( "tt_face_load_font_dir:"
                     " invalid table directory for TrueType\n" ));
-
         goto Exit;
       }
     }
+    else
+      valid_entries = sfnt.num_tables;
 
-    face->num_tables = sfnt.num_tables;
+    face->num_tables = valid_entries;
     face->format_tag = sfnt.format_tag;
 
     if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) )
       goto Exit;
 
-    if ( FT_STREAM_SEEK( sfnt.offset + 12 )       ||
-         FT_FRAME_ENTER( face->num_tables * 16L ) )
+    if ( FT_STREAM_SEEK( sfnt.offset + 12 )      ||
+         FT_FRAME_ENTER( sfnt.num_tables * 16L ) )
       goto Exit;
 
-    entry = face->dir_tables;
-
     FT_TRACE2(( "\n"
                 "  tag    offset    length   checksum\n"
                 "  ----------------------------------\n" ));
 
+    valid_entries = 0;
     for ( nn = 0; nn < sfnt.num_tables; nn++ )
     {
-      entry->Tag      = FT_GET_TAG4();
-      entry->CheckSum = FT_GET_ULONG();
-      entry->Offset   = FT_GET_ULONG();
-      entry->Length   = FT_GET_ULONG();
+      TT_TableRec  entry;
+      FT_UShort    i;
+      FT_Bool      duplicate;
+
+
+      entry.Tag      = FT_GET_TAG4();
+      entry.CheckSum = FT_GET_ULONG();
+      entry.Offset   = FT_GET_ULONG();
+      entry.Length   = FT_GET_ULONG();
 
       /* ignore invalid tables that can't be sanitized */
 
-      if ( entry->Offset > stream->size )
+      if ( entry.Offset > stream->size )
         continue;
-      else if ( entry->Length > stream->size - entry->Offset )
+      else if ( entry.Length > stream->size - entry.Offset )
       {
-        if ( entry->Tag == TTAG_hmtx ||
-             entry->Tag == TTAG_vmtx )
+        if ( entry.Tag == TTAG_hmtx ||
+             entry.Tag == TTAG_vmtx )
         {
 #ifdef FT_DEBUG_LEVEL_TRACE
-          FT_ULong  old_length = entry->Length;
+          FT_ULong  old_length = entry.Length;
 #endif
 
 
           /* make metrics table length a multiple of 4 */
-          entry->Length = ( stream->size - entry->Offset ) & ~3U;
+          entry.Length = ( stream->size - entry.Offset ) & ~3U;
 
           FT_TRACE2(( "  %c%c%c%c  %08lx  %08lx  %08lx"
-                      " (sanitized; original length %08lx)\n",
-                      (FT_Char)( entry->Tag >> 24 ),
-                      (FT_Char)( entry->Tag >> 16 ),
-                      (FT_Char)( entry->Tag >> 8  ),
-                      (FT_Char)( entry->Tag       ),
-                      entry->Offset,
-                      entry->Length,
-                      entry->CheckSum,
+                      " (sanitized; original length %08lx)",
+                      (FT_Char)( entry.Tag >> 24 ),
+                      (FT_Char)( entry.Tag >> 16 ),
+                      (FT_Char)( entry.Tag >> 8  ),
+                      (FT_Char)( entry.Tag       ),
+                      entry.Offset,
+                      entry.Length,
+                      entry.CheckSum,
                       old_length ));
-          entry++;
         }
         else
           continue;
       }
+#ifdef FT_DEBUG_LEVEL_TRACE
+      else
+        FT_TRACE2(( "  %c%c%c%c  %08lx  %08lx  %08lx",
+                    (FT_Char)( entry.Tag >> 24 ),
+                    (FT_Char)( entry.Tag >> 16 ),
+                    (FT_Char)( entry.Tag >> 8  ),
+                    (FT_Char)( entry.Tag       ),
+                    entry.Offset,
+                    entry.Length,
+                    entry.CheckSum ));
+#endif
+
+      /* ignore duplicate tables – the first one wins */
+      duplicate = 0;
+      for ( i = 0; i < valid_entries; i++ )
+      {
+        if ( face->dir_tables[i].Tag == entry.Tag )
+        {
+          duplicate = 1;
+          break;
+        }
+      }
+      if ( duplicate )
+      {
+        FT_TRACE2(( "  (duplicate, ignored)\n" ));
+        continue;
+      }
       else
       {
-        FT_TRACE2(( "  %c%c%c%c  %08lx  %08lx  %08lx\n",
-                    (FT_Char)( entry->Tag >> 24 ),
-                    (FT_Char)( entry->Tag >> 16 ),
-                    (FT_Char)( entry->Tag >> 8  ),
-                    (FT_Char)( entry->Tag       ),
-                    entry->Offset,
-                    entry->Length,
-                    entry->CheckSum ));
-        entry++;
+        FT_TRACE2(( "\n" ));
+
+        /* we finally have a valid entry */
+        face->dir_tables[valid_entries++] = entry;
       }
     }
 
+    /* final adjustment to number of tables */
+    face->num_tables = valid_entries;
+
     FT_FRAME_EXIT();
 
     FT_TRACE2(( "table directory loaded\n\n" ));
diff --git a/src/sfnt/ttsbit.c b/src/sfnt/ttsbit.c
index 143f276..09260b8 100644
--- a/src/sfnt/ttsbit.c
+++ b/src/sfnt/ttsbit.c
@@ -104,7 +104,8 @@
         version     = FT_NEXT_LONG( p );
         num_strikes = FT_NEXT_ULONG( p );
 
-        if ( ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00020000UL )
+        if ( ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00020000UL &&
+             ( (FT_ULong)version & 0xFFFF0000UL ) != 0x00030000UL )
         {
           error = FT_THROW( Unknown_File_Format );
           goto Exit;
@@ -247,6 +248,8 @@
     case TT_SBIT_TABLE_TYPE_CBLC:
       {
         FT_Byte*  strike;
+        FT_Char   max_before_bl;
+        FT_Char   min_after_bl;
 
 
         strike = face->sbit_table + 8 + strike_index * 48;
@@ -254,26 +257,83 @@
         metrics->x_ppem = (FT_UShort)strike[44];
         metrics->y_ppem = (FT_UShort)strike[45];
 
-        metrics->ascender  = (FT_Char)strike[16] << 6;  /* hori.ascender  */
-        metrics->descender = (FT_Char)strike[17] << 6;  /* hori.descender */
-        metrics->height    = metrics->ascender - metrics->descender;
+        metrics->ascender  = (FT_Char)strike[16] * 64;  /* hori.ascender  */
+        metrics->descender = (FT_Char)strike[17] * 64;  /* hori.descender */
+
+        /* Due to fuzzy wording in the EBLC documentation, we find both */
+        /* positive and negative values for `descender'.  Additionally, */
+        /* many fonts have both `ascender' and `descender' set to zero  */
+        /* (which is definitely wrong).  MS Windows simply ignores all  */
+        /* those values...  For these reasons we apply some heuristics  */
+        /* to get a reasonable, non-zero value for the height.          */
+
+        max_before_bl = (FT_Char)strike[24];
+        min_after_bl  = (FT_Char)strike[25];
+
+        if ( metrics->descender > 0 )
+        {
+          /* compare sign of descender with `min_after_bl' */
+          if ( min_after_bl < 0 )
+            metrics->descender = -metrics->descender;
+        }
+
+        else if ( metrics->descender == 0 )
+        {
+          if ( metrics->ascender == 0 )
+          {
+            FT_TRACE2(( "tt_face_load_strike_metrics:"
+                        " sanitizing invalid ascender and descender\n"
+                        "                            "
+                        " values for strike (%d, %d)\n",
+                        metrics->x_ppem, metrics->y_ppem ));
+
+            /* sanitize buggy ascender and descender values */
+            if ( max_before_bl || min_after_bl )
+            {
+              metrics->ascender  = max_before_bl * 64;
+              metrics->descender = min_after_bl * 64;
+            }
+            else
+            {
+              metrics->ascender  = metrics->y_ppem * 64;
+              metrics->descender = 0;
+            }
+          }
+        }
+
+#if 0
+        else
+          ; /* if we have a negative descender, simply use it */
+#endif
+
+        metrics->height = metrics->ascender - metrics->descender;
+        if ( metrics->height == 0 )
+        {
+          FT_TRACE2(( "tt_face_load_strike_metrics:"
+                      " sanitizing invalid height value\n"
+                      "                            "
+                      " for strike (%d, %d)\n",
+                      metrics->x_ppem, metrics->y_ppem ));
+          metrics->height    = metrics->y_ppem * 64;
+          metrics->descender = metrics->ascender - metrics->height;
+        }
 
         /* Is this correct? */
         metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB  */
                                           strike[18] + /* max_width      */
                                  (FT_Char)strike[23]   /* min_advance_SB */
-                                                     ) << 6;
+                                                     ) * 64;
         return FT_Err_Ok;
       }
 
     case TT_SBIT_TABLE_TYPE_SBIX:
       {
         FT_Stream       stream = face->root.stream;
-        FT_UInt         offset, upem;
-        FT_UShort       ppem, resolution;
+        FT_UInt         offset;
+        FT_UShort       upem, ppem, resolution;
         TT_HoriHeader  *hori;
         FT_ULong        table_size;
-        FT_Pos          ppem_, upem_; /* to reduce casts */
+        FT_Pos          ppem_; /* to reduce casts */
 
         FT_Error  error;
         FT_Byte*  p;
@@ -307,14 +367,16 @@
         metrics->y_ppem = ppem;
 
         ppem_ = (FT_Pos)ppem;
-        upem_ = (FT_Pos)upem;
 
-        metrics->ascender    = ppem_ * hori->Ascender * 64 / upem_;
-        metrics->descender   = ppem_ * hori->Descender * 64 / upem_;
-        metrics->height      = ppem_ * ( hori->Ascender -
-                                         hori->Descender +
-                                         hori->Line_Gap ) * 64 / upem_;
-        metrics->max_advance = ppem_ * hori->advance_Width_Max * 64 / upem_;
+        metrics->ascender =
+          FT_MulDiv( hori->Ascender, ppem_ * 64, upem );
+        metrics->descender =
+          FT_MulDiv( hori->Descender, ppem_ * 64, upem );
+        metrics->height =
+          FT_MulDiv( hori->Ascender - hori->Descender + hori->Line_Gap,
+                     ppem_ * 64, upem );
+        metrics->max_advance =
+          FT_MulDiv( hori->advance_Width_Max, ppem_ * 64, upem );
 
         return error;
       }
@@ -547,13 +609,16 @@
   tt_sbit_decoder_load_image( TT_SBitDecoder  decoder,
                               FT_UInt         glyph_index,
                               FT_Int          x_pos,
-                              FT_Int          y_pos );
+                              FT_Int          y_pos,
+                              FT_UInt         recurse_count );
 
-  typedef FT_Error  (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder  decoder,
-                                                FT_Byte*        p,
-                                                FT_Byte*        plimit,
-                                                FT_Int          x_pos,
-                                                FT_Int          y_pos );
+  typedef FT_Error  (*TT_SBitDecoder_LoadFunc)(
+                      TT_SBitDecoder  decoder,
+                      FT_Byte*        p,
+                      FT_Byte*        plimit,
+                      FT_Int          x_pos,
+                      FT_Int          y_pos,
+                      FT_UInt         recurse_count );
 
 
   static FT_Error
@@ -561,7 +626,8 @@
                                      FT_Byte*        p,
                                      FT_Byte*        limit,
                                      FT_Int          x_pos,
-                                     FT_Int          y_pos )
+                                     FT_Int          y_pos,
+                                     FT_UInt         recurse_count )
   {
     FT_Error    error = FT_Err_Ok;
     FT_Byte*    line;
@@ -569,6 +635,8 @@
     FT_UInt     bit_height, bit_width;
     FT_Bitmap*  bitmap;
 
+    FT_UNUSED( recurse_count );
+
 
     /* check that we can write the glyph into the bitmap */
     bitmap     = decoder->bitmap;
@@ -700,7 +768,8 @@
                                     FT_Byte*        p,
                                     FT_Byte*        limit,
                                     FT_Int          x_pos,
-                                    FT_Int          y_pos )
+                                    FT_Int          y_pos,
+                                    FT_UInt         recurse_count )
   {
     FT_Error    error = FT_Err_Ok;
     FT_Byte*    line;
@@ -709,6 +778,8 @@
     FT_Bitmap*  bitmap;
     FT_UShort   rval;
 
+    FT_UNUSED( recurse_count );
+
 
     /* check that we can write the glyph into the bitmap */
     bitmap     = decoder->bitmap;
@@ -738,6 +809,12 @@
       goto Exit;
     }
 
+    if ( !line_bits || !height )
+    {
+      /* nothing to do */
+      goto Exit;
+    }
+
     /* now do the blit */
 
     /* adjust `line' to point to the first byte of the bitmap */
@@ -824,7 +901,8 @@
                                  FT_Byte*        p,
                                  FT_Byte*        limit,
                                  FT_Int          x_pos,
-                                 FT_Int          y_pos )
+                                 FT_Int          y_pos,
+                                 FT_UInt         recurse_count )
   {
     FT_Error  error = FT_Err_Ok;
     FT_UInt   num_components, nn;
@@ -858,8 +936,11 @@
 
 
       /* NB: a recursive call */
-      error = tt_sbit_decoder_load_image( decoder, gindex,
-                                          x_pos + dx, y_pos + dy );
+      error = tt_sbit_decoder_load_image( decoder,
+                                          gindex,
+                                          x_pos + dx,
+                                          y_pos + dy,
+                                          recurse_count + 1 );
       if ( error )
         break;
     }
@@ -891,11 +972,14 @@
                             FT_Byte*        p,
                             FT_Byte*        limit,
                             FT_Int          x_pos,
-                            FT_Int          y_pos )
+                            FT_Int          y_pos,
+                            FT_UInt         recurse_count )
   {
     FT_Error  error = FT_Err_Ok;
     FT_ULong  png_len;
 
+    FT_UNUSED( recurse_count );
+
 
     if ( limit - p < 4 )
     {
@@ -937,7 +1021,8 @@
                                FT_ULong        glyph_start,
                                FT_ULong        glyph_size,
                                FT_Int          x_pos,
-                               FT_Int          y_pos )
+                               FT_Int          y_pos,
+                               FT_UInt         recurse_count )
   {
     FT_Error   error;
     FT_Stream  stream = decoder->stream;
@@ -947,7 +1032,8 @@
 
 
     /* seek into the EBDT table now */
-    if ( glyph_start + glyph_size > decoder->ebdt_size )
+    if ( !glyph_size                                   ||
+         glyph_start + glyph_size > decoder->ebdt_size )
     {
       error = FT_THROW( Invalid_Argument );
       goto Exit;
@@ -1063,7 +1149,7 @@
           goto Fail;
       }
 
-      error = loader( decoder, p, p_limit, x_pos, y_pos );
+      error = loader( decoder, p, p_limit, x_pos, y_pos, recurse_count );
     }
 
   Fail:
@@ -1078,13 +1164,9 @@
   tt_sbit_decoder_load_image( TT_SBitDecoder  decoder,
                               FT_UInt         glyph_index,
                               FT_Int          x_pos,
-                              FT_Int          y_pos )
+                              FT_Int          y_pos,
+                              FT_UInt         recurse_count )
   {
-    /*
-     *  First, we find the correct strike range that applies to this
-     *  glyph index.
-     */
-
     FT_Byte*  p          = decoder->eblc_base + decoder->strike_index_array;
     FT_Byte*  p_limit    = decoder->eblc_limit;
     FT_ULong  num_ranges = decoder->strike_index_count;
@@ -1092,6 +1174,17 @@
     FT_ULong  image_start = 0, image_end = 0, image_offset;
 
 
+    /* arbitrary recursion limit */
+    if ( recurse_count > 100 )
+    {
+      FT_TRACE4(( "tt_sbit_decoder_load_image:"
+                  " recursion depth exceeded\n" ));
+      goto Failure;
+    }
+
+
+    /* First, we find the correct strike range that applies to this */
+    /* glyph index.                                                 */
     for ( ; num_ranges > 0; num_ranges-- )
     {
       start = FT_NEXT_USHORT( p );
@@ -1256,7 +1349,8 @@
                                         image_start,
                                         image_end,
                                         x_pos,
-                                        y_pos );
+                                        y_pos,
+                                        recurse_count );
 
   Failure:
     return FT_THROW( Invalid_Table );
@@ -1419,6 +1513,7 @@
           error = tt_sbit_decoder_load_image( decoder,
                                               glyph_index,
                                               0,
+                                              0,
                                               0 );
           tt_sbit_decoder_done( decoder );
         }
diff --git a/src/smooth/ftgrays.c b/src/smooth/ftgrays.c
index 77b58f2..9a43c07 100644
--- a/src/smooth/ftgrays.c
+++ b/src/smooth/ftgrays.c
@@ -24,8 +24,8 @@
   /*                                                                       */
   /* - copy `src/smooth/ftgrays.c' (this file) to your current directory   */
   /*                                                                       */
-  /* - copy `include/ftimage.h' and `src/smooth/ftgrays.h' to the same     */
-  /*   directory                                                           */
+  /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
+  /*   same directory                                                      */
   /*                                                                       */
   /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in        */
   /*                                                                       */
@@ -135,8 +135,10 @@
 #include <string.h>
 #include <setjmp.h>
 #include <limits.h>
-#define FT_UINT_MAX  UINT_MAX
-#define FT_INT_MAX   INT_MAX
+#define FT_CHAR_BIT   CHAR_BIT
+#define FT_UINT_MAX   UINT_MAX
+#define FT_INT_MAX    INT_MAX
+#define FT_ULONG_MAX  ULONG_MAX
 
 #define ft_memset   memset
 
@@ -317,7 +319,6 @@
 #undef SCALED
 
 #define ONE_PIXEL       ( 1L << PIXEL_BITS )
-#define PIXEL_MASK      ( -1L << PIXEL_BITS )
 #define TRUNC( x )      ( (TCoord)( (x) >> PIXEL_BITS ) )
 #define SUBPIXELS( x )  ( (TPos)(x) << PIXEL_BITS )
 #define FLOOR( x )      ( (x) & -ONE_PIXEL )
@@ -367,6 +368,15 @@
 #endif /* __arm__ */
 
 
+  /* These macros speed up repetitive divisions by replacing them */
+  /* with multiplications and right shifts.                       */ 
+#define FT_UDIVPREP( b )                                       \
+  long  b ## _r = (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b )
+#define FT_UDIV( a, b )                                        \
+  ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >>   \
+    ( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
+
+
   /*************************************************************************/
   /*                                                                       */
   /*   TYPE DEFINITIONS                                                    */
@@ -440,11 +450,8 @@
     FT_PtrDist  max_cells;
     FT_PtrDist  num_cells;
 
-    TCoord  cx, cy;
     TPos    x,  y;
 
-    TPos    last_ey;
-
     FT_Vector   bez_stack[32 * 3 + 1];
     int         lev_stack[32];
 
@@ -677,12 +684,12 @@
     ras.cover   = 0;
     ras.ex      = ex - ras.min_ex;
     ras.ey      = ey - ras.min_ey;
-    ras.last_ey = SUBPIXELS( ey );
     ras.invalid = 0;
 
     gray_set_cell( RAS_VAR_ ex, ey );
   }
 
+#if 0
 
   /*************************************************************************/
   /*                                                                       */
@@ -758,7 +765,7 @@
 
       mod -= (int)dx;
 
-      while ( ex1 != ex2 )
+      do
       {
         delta = lift;
         mod  += rem;
@@ -773,7 +780,7 @@
         y1        += delta;
         ex1       += incr;
         gray_set_cell( RAS_VAR_ ex1, ey );
-      }
+      } while ( ex1 != ex2 );
     }
 
     delta      = y2 - y1;
@@ -796,29 +803,18 @@
     int     delta, rem, lift, incr;
 
 
-    ey1 = TRUNC( ras.last_ey );
+    ey1 = TRUNC( ras.y );
     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
-    fy1 = (TCoord)( ras.y - ras.last_ey );
+    fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) );
     fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
 
     dx = to_x - ras.x;
     dy = to_y - ras.y;
 
     /* perform vertical clipping */
-    {
-      TCoord  min, max;
-
-
-      min = ey1;
-      max = ey2;
-      if ( ey1 > ey2 )
-      {
-        min = ey2;
-        max = ey1;
-      }
-      if ( min >= ras.max_ey || max < ras.min_ey )
-        goto End;
-    }
+    if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
+         ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
+      goto End;
 
     /* everything is on a single scanline */
     if ( ey1 == ey2 )
@@ -896,7 +892,7 @@
       FT_DIV_MOD( int, p, dy, lift, rem );
       mod -= (int)dy;
 
-      while ( ey1 != ey2 )
+      do
       {
         delta = lift;
         mod  += rem;
@@ -914,7 +910,7 @@
 
         ey1 += incr;
         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
-      }
+      } while ( ey1 != ey2 );
     }
 
     gray_render_scanline( RAS_VAR_ ey1, x,
@@ -924,9 +920,145 @@
   End:
     ras.x       = to_x;
     ras.y       = to_y;
-    ras.last_ey = SUBPIXELS( ey2 );
   }
 
+#else
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Render a straight line across multiple cells in any direction.        */
+  /*                                                                       */
+  static void
+  gray_render_line( RAS_ARG_ TPos  to_x,
+                             TPos  to_y )
+  {
+    TPos    dx, dy, fx1, fy1, fx2, fy2;
+    TCoord  ex1, ex2, ey1, ey2;
+
+
+    ex1 = TRUNC( ras.x );
+    ex2 = TRUNC( to_x );
+    ey1 = TRUNC( ras.y );
+    ey2 = TRUNC( to_y );
+
+    /* perform vertical clipping */
+    if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
+         ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
+      goto End;
+
+    dx = to_x - ras.x;
+    dy = to_y - ras.y;
+
+    fx1 = ras.x - SUBPIXELS( ex1 );
+    fy1 = ras.y - SUBPIXELS( ey1 );
+
+    if ( ex1 == ex2 && ey1 == ey2 )       /* inside one cell */
+      ;
+    else if ( dy == 0 ) /* ex1 != ex2 */  /* any horizontal line */
+    {
+      ex1 = ex2;
+      gray_set_cell( RAS_VAR_ ex1, ey1 );
+    }
+    else if ( dx == 0 )
+    {
+      if ( dy > 0 )                       /* vertical line up */
+        do
+        {
+          fy2 = ONE_PIXEL;
+          ras.cover += ( fy2 - fy1 );
+          ras.area  += ( fy2 - fy1 ) * fx1 * 2;
+          fy1 = 0;
+          ey1++;
+          gray_set_cell( RAS_VAR_ ex1, ey1 );
+        } while ( ey1 != ey2 );
+      else                                /* vertical line down */
+        do
+        {
+          fy2 = 0;
+          ras.cover += ( fy2 - fy1 );
+          ras.area  += ( fy2 - fy1 ) * fx1 * 2;
+          fy1 = ONE_PIXEL;
+          ey1--;
+          gray_set_cell( RAS_VAR_ ex1, ey1 );
+        } while ( ey1 != ey2 );
+    }
+    else                                  /* any other line */
+    {
+      TArea  prod = dx * fy1 - dy * fx1;
+      FT_UDIVPREP( dx );
+      FT_UDIVPREP( dy );
+
+
+      /* The fundamental value `prod' determines which side and the  */
+      /* exact coordinate where the line exits current cell.  It is  */
+      /* also easily updated when moving from one cell to the next.  */
+      do
+      {
+        if      ( prod                                   <= 0 &&
+                  prod - dx * ONE_PIXEL                  >  0 ) /* left */
+        {
+          fx2 = 0;
+          fy2 = (TPos)FT_UDIV( -prod, -dx );
+          prod -= dy * ONE_PIXEL;
+          ras.cover += ( fy2 - fy1 );
+          ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
+          fx1 = ONE_PIXEL;
+          fy1 = fy2;
+          ex1--;
+        }
+        else if ( prod - dx * ONE_PIXEL                  <= 0 &&
+                  prod - dx * ONE_PIXEL + dy * ONE_PIXEL >  0 ) /* up */
+        {
+          prod -= dx * ONE_PIXEL;
+          fx2 = (TPos)FT_UDIV( -prod, dy );
+          fy2 = ONE_PIXEL;
+          ras.cover += ( fy2 - fy1 );
+          ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
+          fx1 = fx2;
+          fy1 = 0;
+          ey1++;
+        }
+        else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
+                  prod                  + dy * ONE_PIXEL >= 0 ) /* right */
+        {
+          prod += dy * ONE_PIXEL;
+          fx2 = ONE_PIXEL;
+          fy2 = (TPos)FT_UDIV( prod, dx );
+          ras.cover += ( fy2 - fy1 );
+          ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
+          fx1 = 0;
+          fy1 = fy2;
+          ex1++;
+        }
+        else /* ( prod                  + dy * ONE_PIXEL <  0 &&
+                  prod                                   >  0 )    down */
+        {
+          fx2 = (TPos)FT_UDIV( prod, -dy );
+          fy2 = 0;
+          prod += dx * ONE_PIXEL;
+          ras.cover += ( fy2 - fy1 );
+          ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
+          fx1 = fx2;
+          fy1 = ONE_PIXEL;
+          ey1--;
+        }
+
+        gray_set_cell( RAS_VAR_ ex1, ey1 );
+      } while ( ex1 != ex2 || ey1 != ey2 );
+    }
+
+    fx2 = to_x - SUBPIXELS( ex2 );
+    fy2 = to_y - SUBPIXELS( ey2 );
+
+    ras.cover += ( fy2 - fy1 );
+    ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
+
+  End:
+    ras.x       = to_x;
+    ras.y       = to_y;
+  }
+
+#endif
 
   static void
   gray_split_conic( FT_Vector*  base )
@@ -1847,7 +1979,7 @@
       bands[0].max = max;
       band         = bands;
 
-      while ( band >= bands )
+      do
       {
         TPos  bottom, top, middle;
         int   error;
@@ -1923,7 +2055,7 @@
         band[0].min = middle;
         band[0].max = top;
         band++;
-      }
+      } while ( band >= bands );
     }
 
     if ( ras.band_shoot > 8 && ras.band_size > 16 )
diff --git a/src/smooth/ftspic.h b/src/smooth/ftspic.h
index 99b9f0e..071afcf 100644
--- a/src/smooth/ftspic.h
+++ b/src/smooth/ftspic.h
@@ -20,10 +20,11 @@
 #define __FTSPIC_H__
 
 
-FT_BEGIN_HEADER
-
 #include FT_INTERNAL_PIC_H
 
+
+FT_BEGIN_HEADER
+
 #ifndef FT_CONFIG_OPTION_PIC
 
 #define FT_GRAYS_RASTER_GET  ft_grays_raster
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c
index 08b30c9..1ba71f0 100644
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -117,8 +117,8 @@
 
   FT_DEFINE_SERVICE_PROPERTIESREC(
     tt_service_properties,
-    (FT_Properties_SetFunc)tt_property_set,
-    (FT_Properties_GetFunc)tt_property_get )
+    (FT_Properties_SetFunc)tt_property_set,     /* set_property */
+    (FT_Properties_GetFunc)tt_property_get )    /* get_property */
 
 
   /*************************************************************************/
@@ -417,13 +417,14 @@
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
   FT_DEFINE_SERVICE_MULTIMASTERSREC(
     tt_service_gx_multi_masters,
-    (FT_Get_MM_Func)        NULL,
-    (FT_Set_MM_Design_Func) NULL,
-    (FT_Set_MM_Blend_Func)  TT_Set_MM_Blend,
-    (FT_Get_MM_Var_Func)    TT_Get_MM_Var,
-    (FT_Set_Var_Design_Func)TT_Set_Var_Design )
+    (FT_Get_MM_Func)        NULL,                   /* get_mm         */
+    (FT_Set_MM_Design_Func) NULL,                   /* set_mm_design  */
+    (FT_Set_MM_Blend_Func)  TT_Set_MM_Blend,        /* set_mm_blend   */
+    (FT_Get_MM_Var_Func)    TT_Get_MM_Var,          /* get_mm_var     */
+    (FT_Set_Var_Design_Func)TT_Set_Var_Design )     /* set_var_design */
 #endif
 
+
   static const FT_Service_TrueTypeEngineRec  tt_service_truetype_engine =
   {
 #ifdef TT_USE_BYTECODE_INTERPRETER
@@ -441,9 +442,11 @@
 #endif /* TT_USE_BYTECODE_INTERPRETER */
   };
 
+
   FT_DEFINE_SERVICE_TTGLYFREC(
     tt_service_truetype_glyf,
-    (TT_Glyf_GetLocationFunc)tt_face_get_location )
+    (TT_Glyf_GetLocationFunc)tt_face_get_location )    /* get_location */
+
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
   FT_DEFINE_SERVICEDESCREC5(
@@ -534,31 +537,31 @@
       0x10000L,        /* driver version == 1.0                 */
       0x20000L,        /* driver requires FreeType 2.0 or above */
 
-      (void*)0,        /* driver specific interface */
+      0,    /* module-specific interface */
 
-      tt_driver_init,
-      tt_driver_done,
-      tt_get_interface,
+      tt_driver_init,           /* FT_Module_Constructor  module_init   */
+      tt_driver_done,           /* FT_Module_Destructor   module_done   */
+      tt_get_interface,         /* FT_Module_Requester    get_interface */
 
     sizeof ( TT_FaceRec ),
     sizeof ( TT_SizeRec ),
     sizeof ( FT_GlyphSlotRec ),
 
-    tt_face_init,
-    tt_face_done,
-    tt_size_init,
-    tt_size_done,
-    tt_slot_init,
-    0,                       /* FT_Slot_DoneFunc */
+    tt_face_init,               /* FT_Face_InitFunc  init_face */
+    tt_face_done,               /* FT_Face_DoneFunc  done_face */
+    tt_size_init,               /* FT_Size_InitFunc  init_size */
+    tt_size_done,               /* FT_Size_DoneFunc  done_size */
+    tt_slot_init,               /* FT_Slot_InitFunc  init_slot */
+    0,                          /* FT_Slot_DoneFunc  done_slot */
 
-    tt_glyph_load,
+    tt_glyph_load,              /* FT_Slot_LoadFunc  load_glyph */
 
-    tt_get_kerning,
-    0,                       /* FT_Face_AttachFunc */
-    tt_get_advances,
+    tt_get_kerning,             /* FT_Face_GetKerningFunc   get_kerning  */
+    0,                          /* FT_Face_AttachFunc       attach_file  */
+    tt_get_advances,            /* FT_Face_GetAdvancesFunc  get_advances */
 
-    tt_size_request,
-    TT_SIZE_SELECT
+    tt_size_request,            /* FT_Size_RequestFunc  request_size */
+    TT_SIZE_SELECT              /* FT_Size_SelectFunc   select_size  */
   )
 
 
diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c
index e1acd69..d94fc92 100644
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -24,6 +24,7 @@
 #include FT_TRUETYPE_TAGS_H
 #include FT_OUTLINE_H
 #include FT_TRUETYPE_DRIVER_H
+#include FT_LIST_H
 
 #include "ttgload.h"
 #include "ttpload.h"
@@ -120,7 +121,7 @@
   tt_get_metrics( TT_Loader  loader,
                   FT_UInt    glyph_index )
   {
-    TT_Face    face   = (TT_Face)loader->face;
+    TT_Face    face   = loader->face;
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
 #endif
@@ -182,7 +183,7 @@
   tt_get_metrics_incr_overrides( TT_Loader  loader,
                                  FT_UInt    glyph_index )
   {
-    TT_Face  face = (TT_Face)loader->face;
+    TT_Face  face = loader->face;
 
     FT_Short   left_bearing = 0, top_bearing = 0;
     FT_UShort  advance_width = 0, advance_height = 0;
@@ -250,29 +251,6 @@
 
   /*************************************************************************/
   /*                                                                       */
-  /* Translates an array of coordinates.                                   */
-  /*                                                                       */
-  static void
-  translate_array( FT_UInt     n,
-                   FT_Vector*  coords,
-                   FT_Pos      delta_x,
-                   FT_Pos      delta_y )
-  {
-    FT_UInt  k;
-
-
-    if ( delta_x )
-      for ( k = 0; k < n; k++ )
-        coords[k].x += delta_x;
-
-    if ( delta_y )
-      for ( k = 0; k < n; k++ )
-        coords[k].y += delta_y;
-  }
-
-
-  /*************************************************************************/
-  /*                                                                       */
   /* The following functions are used by default with TrueType fonts.      */
   /* However, they can be replaced by alternatives if we need to support   */
   /* TrueType-compressed formats (like MicroType) in the future.           */
@@ -656,20 +634,20 @@
 
       if ( subglyph->flags & WE_HAVE_A_SCALE )
       {
-        xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2;
+        xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
         yy = xx;
       }
       else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
       {
-        xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2;
-        yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2;
+        xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
+        yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
       }
       else if ( subglyph->flags & WE_HAVE_A_2X2 )
       {
-        xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2;
-        yx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2;
-        xy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2;
-        yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2;
+        xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
+        yx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
+        xy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
+        yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
       }
 
       subglyph->transform.xx = xx;
@@ -682,6 +660,7 @@
     } while ( subglyph->flags & MORE_COMPONENTS );
 
     gloader->current.num_subglyphs = num_subglyphs;
+    FT_TRACE5(( "  %d components\n", num_subglyphs ));
 
 #ifdef TT_USE_BYTECODE_INTERPRETER
 
@@ -754,7 +733,7 @@
                  FT_Bool    is_composite )
   {
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-    TT_Face    face   = (TT_Face)loader->face;
+    TT_Face    face   = loader->face;
     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
 #endif
 
@@ -781,7 +760,7 @@
       FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points );
 
     /* Reset graphics state. */
-    loader->exec->GS = ((TT_Size)loader->size)->GS;
+    loader->exec->GS = loader->size->GS;
 
     /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
     /*      completely refer to the (already) hinted subglyphs.     */
@@ -794,10 +773,8 @@
     }
     else
     {
-      loader->exec->metrics.x_scale =
-        ((TT_Size)loader->size)->metrics.x_scale;
-      loader->exec->metrics.y_scale =
-        ((TT_Size)loader->size)->metrics.y_scale;
+      loader->exec->metrics.x_scale = loader->size->metrics.x_scale;
+      loader->exec->metrics.y_scale = loader->size->metrics.y_scale;
     }
 #endif
 
@@ -897,13 +874,13 @@
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
 
-    if ( ((TT_Face)loader->face)->doblend )
+    if ( loader->face->doblend )
     {
       /* Deltas apply to the unscaled data. */
-      error = TT_Vary_Apply_Glyph_Deltas( (TT_Face)(loader->face),
-                                           loader->glyph_index,
-                                           outline,
-                                           (FT_UInt)n_points );
+      error = TT_Vary_Apply_Glyph_Deltas( loader->face,
+                                          loader->glyph_index,
+                                          outline,
+                                          (FT_UInt)n_points );
       if ( error )
         return error;
     }
@@ -920,7 +897,7 @@
 
     {
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-      TT_Face    face   = (TT_Face)loader->face;
+      TT_Face    face   = loader->face;
       TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
 
       FT_String*  family         = face->root.family_name;
@@ -953,9 +930,9 @@
         if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
              x_scale_factor != 1000                         )
         {
-          x_scale = FT_MulDiv( ((TT_Size)loader->size)->metrics.x_scale,
+          x_scale = FT_MulDiv( loader->size->metrics.x_scale,
                                (FT_Long)x_scale_factor, 1000 );
-          y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+          y_scale = loader->size->metrics.y_scale;
 
           /* compensate for any scaling by de/emboldening; */
           /* the amount was determined via experimentation */
@@ -975,8 +952,8 @@
         /* scale the glyph */
         if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
         {
-          x_scale = ((TT_Size)loader->size)->metrics.x_scale;
-          y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+          x_scale = loader->size->metrics.x_scale;
+          y_scale = loader->size->metrics.y_scale;
 
           do_scale = TRUE;
         }
@@ -1023,30 +1000,29 @@
                                   FT_UInt      start_point,
                                   FT_UInt      num_base_points )
   {
-    FT_GlyphLoader  gloader    = loader->gloader;
-    FT_Vector*      base_vec   = gloader->base.outline.points;
-    FT_UInt         num_points = (FT_UInt)gloader->base.outline.n_points;
+    FT_GlyphLoader  gloader = loader->gloader;
+    FT_Outline      current;
     FT_Bool         have_scale;
     FT_Pos          x, y;
 
 
+    current.points   = gloader->base.outline.points +
+                         num_base_points;
+    current.n_points = gloader->base.outline.n_points -
+                         (short)num_base_points;
+
     have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE     |
                                               WE_HAVE_AN_XY_SCALE |
                                               WE_HAVE_A_2X2       ) );
 
     /* perform the transform required for this subglyph */
     if ( have_scale )
-    {
-      FT_UInt  i;
-
-
-      for ( i = num_base_points; i < num_points; i++ )
-        FT_Vector_Transform( base_vec + i, &subglyph->transform );
-    }
+      FT_Outline_Transform( &current, &subglyph->transform );
 
     /* get offset */
     if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
     {
+      FT_UInt     num_points = (FT_UInt)gloader->base.outline.n_points;
       FT_UInt     k = (FT_UInt)subglyph->arg1;
       FT_UInt     l = (FT_UInt)subglyph->arg2;
       FT_Vector*  p1;
@@ -1135,8 +1111,8 @@
 
       if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
       {
-        FT_Fixed  x_scale = ((TT_Size)loader->size)->metrics.x_scale;
-        FT_Fixed  y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+        FT_Fixed  x_scale = loader->size->metrics.x_scale;
+        FT_Fixed  y_scale = loader->size->metrics.y_scale;
 
 
         x = FT_MulFix( x, x_scale );
@@ -1151,9 +1127,7 @@
     }
 
     if ( x || y )
-      translate_array( num_points - num_base_points,
-                       base_vec + num_base_points,
-                       x, y );
+      FT_Outline_Translate( &current, x, y );
 
     return FT_Err_Ok;
   }
@@ -1215,7 +1189,7 @@
       FT_TRACE5(( "  Instructions size = %d\n", n_ins ));
 
       /* check it */
-      max_ins = ((TT_Face)loader->face)->max_profile.maxSizeOfInstructions;
+      max_ins = loader->face->max_profile.maxSizeOfInstructions;
       if ( n_ins > max_ins )
       {
         /* don't trust `maxSizeOfInstructions'; */
@@ -1412,7 +1386,7 @@
     FT_Error        error        = FT_Err_Ok;
     FT_Fixed        x_scale, y_scale;
     FT_ULong        offset;
-    TT_Face         face         = (TT_Face)loader->face;
+    TT_Face         face         = loader->face;
     FT_GlyphLoader  gloader      = loader->gloader;
     FT_Bool         opened_frame = 0;
 
@@ -1423,6 +1397,11 @@
 #endif
 
 
+#ifdef FT_DEBUG_LEVEL_TRACE
+    if ( recurse_count )
+      FT_TRACE5(( "  nesting level: %d\n", recurse_count ));
+#endif
+
     /* some fonts have an incorrect value of `maxComponentDepth', */
     /* thus we allow depth 1 to catch the majority of them        */
     if ( recurse_count > 1                                   &&
@@ -1445,8 +1424,8 @@
 
     if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
     {
-      x_scale = ((TT_Size)loader->size)->metrics.x_scale;
-      y_scale = ((TT_Size)loader->size)->metrics.y_scale;
+      x_scale = loader->size->metrics.x_scale;
+      y_scale = loader->size->metrics.y_scale;
     }
     else
     {
@@ -1552,7 +1531,7 @@
 
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
 
-      if ( ((TT_Face)(loader->face))->doblend )
+      if ( loader->face->doblend )
       {
         /* a small outline structure with four elements for */
         /* communication with `TT_Vary_Apply_Glyph_Deltas'  */
@@ -1579,10 +1558,10 @@
         outline.contours   = contours;
 
         /* this must be done before scaling */
-        error = TT_Vary_Apply_Glyph_Deltas( (TT_Face)(loader->face),
-                                             glyph_index,
-                                             &outline,
-                                             outline.n_points );
+        error = TT_Vary_Apply_Glyph_Deltas( loader->face,
+                                            glyph_index,
+                                            &outline,
+                                            (FT_UInt)outline.n_points );
         if ( error )
           goto Exit;
 
@@ -1655,11 +1634,40 @@
     /* otherwise, load a composite! */
     else if ( loader->n_contours == -1 )
     {
+      FT_Memory  memory = face->root.memory;
+
       FT_UInt   start_point;
       FT_UInt   start_contour;
       FT_ULong  ins_pos;  /* position of composite instructions, if any */
 
 
+      /*
+       * We store the glyph index directly in the `node->data' pointer,
+       * following the glib solution (cf. macro `GUINT_TO_POINTER') with a
+       * double cast to make this portable.  Note, however, that this needs
+       * pointers with a width of at least 32 bits.
+       */
+
+      /* check whether we already have a composite glyph with this index */
+      if ( FT_List_Find( &loader->composites,
+                         (void*)(unsigned long)glyph_index ) )
+      {
+        FT_TRACE1(( "TT_Load_Composite_Glyph:"
+                    " infinite recursion detected\n" ));
+        error = FT_THROW( Invalid_Composite );
+        goto Exit;
+      }
+      else
+      {
+        FT_ListNode  node = NULL;
+
+
+        if ( FT_NEW( node ) )
+          goto Exit;
+        node->data = (void*)(unsigned long)glyph_index;
+        FT_List_Add( &loader->composites, node );
+      }
+
       start_point   = (FT_UInt)gloader->base.outline.n_points;
       start_contour = (FT_UInt)gloader->base.outline.n_contours;
 
@@ -1679,7 +1687,7 @@
 
       if ( face->doblend )
       {
-        FT_UInt      i, limit;
+        short        i, limit;
         FT_SubGlyph  subglyph;
 
         FT_Outline  outline;
@@ -1687,14 +1695,12 @@
         char*       tags     = NULL;
         short*      contours = NULL;
 
-        FT_Memory  memory = face->root.memory;
 
-
-        limit = gloader->current.num_subglyphs;
+        limit = (short)gloader->current.num_subglyphs;
 
         /* construct an outline structure for              */
         /* communication with `TT_Vary_Apply_Glyph_Deltas' */
-        outline.n_points   = gloader->current.num_subglyphs + 4;
+        outline.n_points   = (short)( gloader->current.num_subglyphs + 4 );
         outline.n_contours = outline.n_points;
 
         if ( FT_NEW_ARRAY( points, outline.n_points )   ||
@@ -1702,7 +1708,7 @@
              FT_NEW_ARRAY( contours, outline.n_points ) )
           goto Exit1;
 
-        subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs;
+        subglyph = gloader->current.subglyphs;
 
         for ( i = 0; i < limit; i++, subglyph++ )
         {
@@ -1748,10 +1754,10 @@
                          face,
                          glyph_index,
                          &outline,
-                         outline.n_points ) ) != 0 )
+                         (FT_UInt)outline.n_points ) ) != 0 )
           goto Exit1;
 
-        subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs;
+        subglyph = gloader->current.subglyphs;
 
         for ( i = 0; i < limit; i++, subglyph++ )
         {
@@ -1935,7 +1941,7 @@
   compute_glyph_metrics( TT_Loader  loader,
                          FT_UInt    glyph_index )
   {
-    TT_Face    face   = (TT_Face)loader->face;
+    TT_Face    face   = loader->face;
 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
 #endif
@@ -1943,7 +1949,7 @@
     FT_BBox       bbox;
     FT_Fixed      y_scale;
     TT_GlyphSlot  glyph = loader->glyph;
-    TT_Size       size  = (TT_Size)loader->size;
+    TT_Size       size  = loader->size;
 
 
     y_scale = 0x10000L;
@@ -1964,8 +1970,10 @@
     glyph->metrics.horiAdvance  = loader->pp2.x - loader->pp1.x;
 
     /* adjust advance width to the value contained in the hdmx table */
-    if ( !face->postscript.isFixedPitch  &&
-         IS_HINTED( loader->load_flags ) )
+    /* unless FT_LOAD_COMPUTE_METRICS is set                         */
+    if ( !face->postscript.isFixedPitch                    &&
+         IS_HINTED( loader->load_flags )                   &&
+         !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) )
     {
       FT_Byte*  widthp;
 
@@ -1988,7 +1996,7 @@
              ( ( ignore_x_mode && loader->exec->compatible_widths ) ||
                 !ignore_x_mode                                      ||
                 SPH_OPTION_BITMAP_WIDTHS                            ) )
-          glyph->metrics.horiAdvance = *widthp << 6;
+          glyph->metrics.horiAdvance = *widthp * 64;
       }
       else
 
@@ -1996,7 +2004,7 @@
 
       {
         if ( widthp )
-          glyph->metrics.horiAdvance = *widthp << 6;
+          glyph->metrics.horiAdvance = *widthp * 64;
       }
     }
 
@@ -2136,16 +2144,16 @@
       glyph->outline.n_points   = 0;
       glyph->outline.n_contours = 0;
 
-      glyph->metrics.width  = (FT_Pos)metrics.width  << 6;
-      glyph->metrics.height = (FT_Pos)metrics.height << 6;
+      glyph->metrics.width  = (FT_Pos)metrics.width  * 64;
+      glyph->metrics.height = (FT_Pos)metrics.height * 64;
 
-      glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
-      glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
-      glyph->metrics.horiAdvance  = (FT_Pos)metrics.horiAdvance  << 6;
+      glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX * 64;
+      glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY * 64;
+      glyph->metrics.horiAdvance  = (FT_Pos)metrics.horiAdvance  * 64;
 
-      glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
-      glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
-      glyph->metrics.vertAdvance  = (FT_Pos)metrics.vertAdvance  << 6;
+      glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX * 64;
+      glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY * 64;
+      glyph->metrics.vertAdvance  = (FT_Pos)metrics.vertAdvance  * 64;
 
       glyph->format = FT_GLYPH_FORMAT_BITMAP;
 
@@ -2414,15 +2422,28 @@
 
     loader->load_flags = (FT_ULong)load_flags;
 
-    loader->face   = (FT_Face)face;
-    loader->size   = (FT_Size)size;
+    loader->face   = face;
+    loader->size   = size;
     loader->glyph  = (FT_GlyphSlot)glyph;
     loader->stream = stream;
 
+    loader->composites.head = NULL;
+    loader->composites.tail = NULL;
+
     return FT_Err_Ok;
   }
 
 
+  static void
+  tt_loader_done( TT_Loader  loader )
+  {
+    FT_List_Finalize( &loader->composites,
+                      NULL,
+                      loader->face->root.memory,
+                      NULL );
+  }
+
+
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
@@ -2479,6 +2500,7 @@
           /* for the bbox we need the header only */
           (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE );
           (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE );
+          tt_loader_done( &loader );
           glyph->linearHoriAdvance = loader.linear;
           glyph->linearVertAdvance = loader.vadvance;
 
@@ -2574,6 +2596,8 @@
       error = compute_glyph_metrics( &loader, glyph_index );
     }
 
+    tt_loader_done( &loader );
+
     /* Set the `high precision' bit flag.                           */
     /* This is _critical_ to get correct output for monochrome      */
     /* TrueType glyphs at all sizes using the bytecode interpreter. */
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 2b12483..5d4384e 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -112,6 +112,8 @@
   /* <Input>                                                               */
   /*    stream    :: The data stream.                                      */
   /*                                                                       */
+  /*    size      :: The size of the table holding the data.               */
+  /*                                                                       */
   /* <Output>                                                              */
   /*    point_cnt :: The number of points read.  A zero value means that   */
   /*                 all points in the glyph will be affected, without     */
@@ -123,6 +125,7 @@
   /*                                                                       */
   static FT_UShort*
   ft_var_readpackedpoints( FT_Stream  stream,
+                           FT_ULong   size,
                            FT_UInt   *point_cnt )
   {
     FT_UShort *points = NULL;
@@ -149,6 +152,12 @@
       n  |= FT_GET_BYTE();
     }
 
+    if ( n > size )
+    {
+      FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" ));
+      return NULL;
+    }
+
     if ( FT_NEW_ARRAY( points, n ) )
       return NULL;
 
@@ -212,6 +221,8 @@
   /* <Input>                                                               */
   /*    stream    :: The data stream.                                      */
   /*                                                                       */
+  /*    size      :: The size of the table holding the data.               */
+  /*                                                                       */
   /*    delta_cnt :: The number of deltas to be read.                      */
   /*                                                                       */
   /* <Return>                                                              */
@@ -222,6 +233,7 @@
   /*                                                                       */
   static FT_Short*
   ft_var_readpackeddeltas( FT_Stream  stream,
+                           FT_ULong   size,
                            FT_UInt    delta_cnt )
   {
     FT_Short  *deltas = NULL;
@@ -233,6 +245,12 @@
     FT_UNUSED( error );
 
 
+    if ( delta_cnt > size )
+    {
+      FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" ));
+      return NULL;
+    }
+
     if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
       return NULL;
 
@@ -341,7 +359,8 @@
       FT_TRACE5(( "  axis %d:\n", i ));
 
       segment->pairCount = FT_GET_USHORT();
-      if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
+      if ( (FT_ULong)segment->pairCount * 4 > table_len                ||
+           FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
       {
         /* Failure.  Free everything we have done so far.  We must do */
         /* it right now since loading the `avar' table is optional.   */
@@ -357,8 +376,8 @@
       for ( j = 0; j < segment->pairCount; j++ )
       {
         /* convert to Fixed */
-        segment->correspondence[j].fromCoord = FT_GET_SHORT() << 2;
-        segment->correspondence[j].toCoord   = FT_GET_SHORT() << 2;
+        segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4;
+        segment->correspondence[j].toCoord   = FT_GET_SHORT() * 4;
 
         FT_TRACE5(( "    mapping %.4f to %.4f\n",
                     segment->correspondence[j].fromCoord / 65536.0,
@@ -447,10 +466,6 @@
     if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
       goto Exit;
 
-    blend->tuplecount  = gvar_head.globalCoordCount;
-    blend->gv_glyphcnt = gvar_head.glyphCount;
-    offsetToData       = gvar_start + gvar_head.offsetToData;
-
     if ( gvar_head.version != 0x00010000L )
     {
       FT_TRACE1(( "bad table version\n" ));
@@ -458,8 +473,6 @@
       goto Exit;
     }
 
-    FT_TRACE2(( "loaded\n" ));
-
     if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
     {
       FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n"
@@ -468,6 +481,33 @@
       goto Exit;
     }
 
+    /* rough sanity check, ignoring offsets */
+    if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount >
+           table_len / 2 )
+    {
+      FT_TRACE1(( "ft_var_load_gvar:"
+                  " invalid number of global coordinates\n" ));
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
+
+    /* rough sanity check: offsets can be either 2 or 4 bytes, */
+    /* and a single variation needs at least 4 bytes per glyph */
+    if ( (FT_ULong)gvar_head.glyphCount *
+           ( ( gvar_head.flags & 1 ) ? 8 : 6 ) > table_len )
+    {
+      FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" ));
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
+
+    FT_TRACE2(( "loaded\n" ));
+
+    blend->gvar_size   = table_len;
+    blend->tuplecount  = gvar_head.globalCoordCount;
+    blend->gv_glyphcnt = gvar_head.glyphCount;
+    offsetToData       = gvar_start + gvar_head.offsetToData;
+
     FT_TRACE5(( "gvar: there are %d shared coordinates:\n",
                 blend->tuplecount ));
 
@@ -514,7 +554,7 @@
         for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; j++ )
         {
           blend->tuplecoords[i * gvar_head.axisCount + j] =
-            FT_GET_SHORT() << 2;                /* convert to FT_Fixed */
+            FT_GET_SHORT() * 4;                 /* convert to FT_Fixed */
           FT_TRACE5(( "%.4f ",
             blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
         }
@@ -698,7 +738,8 @@
   /*              TT_Get_MM_Var initializes the blend structure.           */
   /*                                                                       */
   /* <Output>                                                              */
-  /*    master :: The `fvar' data (must be freed by caller).               */
+  /*    master :: The `fvar' data (must be freed by caller).  Can be NULL, */
+  /*              which makes this function simply load MM support.        */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0 means success.                             */
@@ -1352,13 +1393,25 @@
       goto FExit;
 
     tupleCount   = FT_GET_USHORT();
-    offsetToData = table_start + FT_GET_USHORT();
+    offsetToData = FT_GET_USHORT();
 
-    /* The documentation implies there are flags packed into the        */
-    /* tuplecount, but John Jenkins says that shared points don't apply */
-    /* to `cvar', and no other flags are defined.                       */
+    /* rough sanity test */
+    if ( offsetToData + tupleCount * 4 > table_len )
+    {
+      FT_TRACE2(( "tt_face_vary_cvt:"
+                  " invalid CVT variation array header\n" ));
 
-    FT_TRACE5(( "cvar: there are %d tuples:\n", tupleCount ));
+      error = FT_THROW( Invalid_Table );
+      goto FExit;
+    }
+
+    offsetToData += table_start;
+
+    /* The documentation implies there are flags packed into              */
+    /* `tupleCount', but John Jenkins says that shared points don't apply */
+    /* to `cvar', and no other flags are defined.                         */
+
+    FT_TRACE5(( "cvar: there are %d tuples:\n", tupleCount & 0xFFF ));
 
     for ( i = 0; i < ( tupleCount & 0xFFF ); i++ )
     {
@@ -1378,7 +1431,7 @@
       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
       {
         for ( j = 0; j < blend->num_axis; j++ )
-          tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from        */
+          tuple_coords[j] = FT_GET_SHORT() * 4;  /* convert from        */
                                                  /* short frac to fixed */
       }
       else
@@ -1396,9 +1449,9 @@
       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
       {
         for ( j = 0; j < blend->num_axis; j++ )
-          im_start_coords[j] = FT_GET_SHORT() << 2;
+          im_start_coords[j] = FT_GET_SHORT() * 4;
         for ( j = 0; j < blend->num_axis; j++ )
-          im_end_coords[j] = FT_GET_SHORT() << 2;
+          im_end_coords[j] = FT_GET_SHORT() * 4;
       }
 
       apply = ft_var_apply_tuple( blend,
@@ -1420,8 +1473,11 @@
 
       FT_Stream_SeekSet( stream, offsetToData );
 
-      localpoints = ft_var_readpackedpoints( stream, &point_count );
+      localpoints = ft_var_readpackedpoints( stream,
+                                             table_len,
+                                             &point_count );
       deltas      = ft_var_readpackeddeltas( stream,
+                                             table_len,
                                              point_count == 0 ? face->cvt_size
                                                               : point_count );
       if ( localpoints == NULL || deltas == NULL )
@@ -1649,13 +1705,13 @@
   {
     FT_Vector*  out_points;
 
-    FT_UInt  first_point;
-    FT_UInt  end_point;
+    FT_Int  first_point;
+    FT_Int  end_point;
 
-    FT_UInt  first_delta;
-    FT_UInt  cur_delta;
+    FT_Int  first_delta;
+    FT_Int  cur_delta;
 
-    FT_UInt   point;
+    FT_Int    point;
     FT_Short  contour;
 
 
@@ -1818,7 +1874,19 @@
       goto Fail2;
 
     tupleCount   = FT_GET_USHORT();
-    offsetToData = glyph_start + FT_GET_USHORT();
+    offsetToData = FT_GET_USHORT();
+
+    /* rough sanity test */
+    if ( offsetToData + tupleCount * 4 > blend->gvar_size )
+    {
+      FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+                  " invalid glyph variation array header\n" ));
+
+      error = FT_THROW( Invalid_Table );
+      goto Fail2;
+    }
+
+    offsetToData += glyph_start;
 
     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
     {
@@ -1826,13 +1894,16 @@
 
       FT_Stream_SeekSet( stream, offsetToData );
 
-      sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
+      sharedpoints = ft_var_readpackedpoints( stream,
+                                              blend->gvar_size,
+                                              &spoint_count );
       offsetToData = FT_Stream_FTell( stream );
 
       FT_Stream_SeekSet( stream, here );
     }
 
-    FT_TRACE5(( "gvar: there are %d tuples:\n", tupleCount ));
+    FT_TRACE5(( "gvar: there are %d tuples:\n",
+                tupleCount & GX_TC_TUPLE_COUNT_MASK ));
 
     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
     {
@@ -1849,11 +1920,14 @@
       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
       {
         for ( j = 0; j < blend->num_axis; j++ )
-          tuple_coords[j] = FT_GET_SHORT() << 2;  /* convert from        */
+          tuple_coords[j] = FT_GET_SHORT() * 4;   /* convert from        */
                                                   /* short frac to fixed */
       }
       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
       {
+        FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+                    " invalid tuple index\n" ));
+
         error = FT_THROW( Invalid_Table );
         goto Fail2;
       }
@@ -1866,9 +1940,9 @@
       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
       {
         for ( j = 0; j < blend->num_axis; j++ )
-          im_start_coords[j] = FT_GET_SHORT() << 2;
+          im_start_coords[j] = FT_GET_SHORT() * 4;
         for ( j = 0; j < blend->num_axis; j++ )
-          im_end_coords[j] = FT_GET_SHORT() << 2;
+          im_end_coords[j] = FT_GET_SHORT() * 4;
       }
 
       apply = ft_var_apply_tuple( blend,
@@ -1889,7 +1963,9 @@
       {
         FT_Stream_SeekSet( stream, offsetToData );
 
-        localpoints = ft_var_readpackedpoints( stream, &point_count );
+        localpoints = ft_var_readpackedpoints( stream,
+                                               blend->gvar_size,
+                                               &point_count );
         points      = localpoints;
       }
       else
@@ -1899,9 +1975,11 @@
       }
 
       deltas_x = ft_var_readpackeddeltas( stream,
+                                          blend->gvar_size,
                                           point_count == 0 ? n_points
                                                            : point_count );
       deltas_y = ft_var_readpackeddeltas( stream,
+                                          blend->gvar_size,
                                           point_count == 0 ? n_points
                                                            : point_count );
 
@@ -1949,6 +2027,9 @@
 #endif
       }
 
+      else if ( localpoints == NULL )
+        ; /* failure, ignore it */
+
       else
       {
 #ifdef FT_DEBUG_LEVEL_TRACE
@@ -2020,6 +2101,8 @@
     FT_TRACE5(( "\n" ));
 
   Fail2:
+    if ( sharedpoints != ALL_POINTS )
+      FT_FREE( sharedpoints );
     FT_FREE( tuple_coords );
     FT_FREE( im_start_coords );
     FT_FREE( im_end_coords );
diff --git a/src/truetype/ttgxvar.h b/src/truetype/ttgxvar.h
index 060d4d6..dd1411f 100644
--- a/src/truetype/ttgxvar.h
+++ b/src/truetype/ttgxvar.h
@@ -95,6 +95,8 @@
     FT_UInt         gv_glyphcnt;
     FT_ULong*       glyphoffsets;
 
+    FT_ULong        gvar_size;
+
   } GX_BlendRec;
 
 
diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
index 089f604..1c1d7de 100644
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -45,15 +45,6 @@
 #define FT_COMPONENT  trace_ttinterp
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* In order to detect infinite loops in the code, we set up a counter    */
-  /* within the run loop.  A single stroke of interpretation is now        */
-  /* limited to a maximum number of opcodes defined below.                 */
-  /*                                                                       */
-#define MAX_RUNNABLE_OPCODES  1000000L
-
-
 #define SUBPIXEL_HINTING                                                     \
           ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
             TT_INTERPRETER_VERSION_38 )
@@ -88,13 +79,6 @@
 #define BOUNDSL( x, n )  ( (FT_ULong)(x) >= (FT_ULong)(n) )
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* This macro computes (a*2^14)/b and complements TT_MulFix14.           */
-  /*                                                                       */
-#define TT_DivFix14( a, b )  FT_DivFix( a, (b) << 2 )
-
-
 #undef  SUCCESS
 #define SUCCESS  0
 
@@ -2580,26 +2564,23 @@
              FT_F26Dot6      Vy,
              FT_UnitVector*  R )
   {
-    FT_F26Dot6  W;
+    FT_Vector V;
 
 
-    if ( FT_ABS( Vx ) < 0x4000L && FT_ABS( Vy ) < 0x4000L )
+    if ( Vx == 0 && Vy == 0 )
     {
-      if ( Vx == 0 && Vy == 0 )
-      {
-        /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
-        /*      to normalize the vector (0,0).  Return immediately. */
-        return SUCCESS;
-      }
-
-      Vx *= 0x4000;
-      Vy *= 0x4000;
+      /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
+      /*      to normalize the vector (0,0).  Return immediately. */
+      return SUCCESS;
     }
 
-    W = FT_Hypot( Vx, Vy );
+    V.x = Vx;
+    V.y = Vy;
 
-    R->x = (FT_F2Dot14)TT_DivFix14( Vx, W );
-    R->y = (FT_F2Dot14)TT_DivFix14( Vy, W );
+    FT_Vector_NormLen( &V );
+
+    R->x = (FT_F2Dot14)( V.x / 4 );
+    R->y = (FT_F2Dot14)( V.y / 4 );
 
     return SUCCESS;
   }
@@ -5157,11 +5138,11 @@
   Ins_INSTCTRL( TT_ExecContext  exc,
                 FT_Long*        args )
   {
-    FT_Long  K, L, Kf;
+    FT_ULong  K, L, Kf;
 
 
-    K = args[1];
-    L = args[0];
+    K = (FT_ULong)args[1];
+    L = (FT_ULong)args[0];
 
     /* selector values cannot be `OR'ed;                 */
     /* they are indices starting with index 1, not flags */
@@ -6505,8 +6486,6 @@
     dx = exc->zp0.cur[b0].x - exc->zp1.cur[a0].x;
     dy = exc->zp0.cur[b0].y - exc->zp1.cur[a0].y;
 
-    exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
-
     discriminant = FT_MulDiv( dax, -dby, 0x40 ) +
                    FT_MulDiv( day, dbx, 0x40 );
     dotproduct   = FT_MulDiv( dax, dbx, 0x40 ) +
@@ -6543,6 +6522,8 @@
                                 exc->zp0.cur[b0].y +
                                 exc->zp0.cur[b1].y ) / 4;
     }
+
+    exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
   }
 
 
@@ -7575,7 +7556,7 @@
                               ? 2
                               : 12 - ( *opcode_name[exc->opcode] - '0' ),
                               "#" ));
-        for ( n = 0; n < cnt; n++ )
+        for ( n = 1; n <= cnt; n++ )
           FT_TRACE7(( " %d", exc->stack[exc->top - n] ));
         FT_TRACE6(( "\n" ));
       }
@@ -8240,7 +8221,7 @@
 
       /* increment instruction counter and check if we didn't */
       /* run this program for too long (e.g. infinite loops). */
-      if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
+      if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES )
         return FT_THROW( Execution_Too_Long );
 
     LSuiteLabel_:
diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c
index 202aa04..b0d9f28 100644
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -191,7 +191,7 @@
   {
     FT_Error   error;
     FT_UInt32  checksum = 0;
-    int        i;
+    FT_UInt    i;
 
 
     if ( FT_FRAME_ENTER( length ) )
@@ -200,8 +200,8 @@
     for ( ; length > 3; length -= 4 )
       checksum += (FT_UInt32)FT_GET_ULONG();
 
-    for ( i = 3; length > 0; length --, i-- )
-      checksum += (FT_UInt32)( FT_GET_BYTE() << ( i * 8 ) );
+    for ( i = 3; length > 0; length--, i-- )
+      checksum += (FT_UInt32)FT_GET_BYTE() << ( i * 8 );
 
     FT_FRAME_EXIT();
 
@@ -490,7 +490,10 @@
   /* <Input>                                                               */
   /*    stream     :: The source font stream.                              */
   /*                                                                       */
-  /*    face_index :: The index of the font face in the resource.          */
+  /*    face_index :: The index of the TrueType font, if we are opening a  */
+  /*                  collection, in bits 0-15.  The numbered instance     */
+  /*                  index~+~1 of a GX (sub)font, if applicable, in bits  */
+  /*                  16-30.                                               */
   /*                                                                       */
   /*    num_params :: Number of additional generic parameters.  Ignored.   */
   /*                                                                       */
@@ -599,7 +602,7 @@
         ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE;
       }
 
-#else
+#else /* !FT_CONFIG_OPTION_INCREMENTAL */
 
       if ( !error )
         error = tt_face_load_loca( face, stream );
@@ -623,10 +626,56 @@
         ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE;
       }
 
-#endif
+#endif /* !FT_CONFIG_OPTION_INCREMENTAL */
 
     }
 
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+
+    {
+      FT_Int  instance_index = face_index >> 16;
+
+
+      if ( FT_HAS_MULTIPLE_MASTERS( ttface ) &&
+           instance_index > 0                )
+      {
+        error = TT_Get_MM_Var( face, NULL );
+        if ( error )
+          goto Exit;
+
+        if ( face->blend->mmvar->namedstyle )
+        {
+          FT_Memory  memory = ttface->memory;
+
+          FT_Var_Named_Style*  named_style;
+          FT_String*           style_name;
+
+
+          /* in `face_index', the instance index starts with value 1 */
+          named_style = face->blend->mmvar->namedstyle + instance_index - 1;
+          error = sfnt->get_name( face,
+                                  (FT_UShort)named_style->strid,
+                                  &style_name );
+          if ( error )
+            goto Exit;
+
+          /* set style name; if already set, replace it */
+          if ( face->root.style_name )
+            FT_FREE( face->root.style_name );
+          face->root.style_name = style_name;
+
+          /* finally, select the named instance */
+          error = TT_Set_Var_Design( face,
+                                     face->blend->mmvar->num_axis,
+                                     named_style->coords );
+          if ( error )
+            goto Exit;
+        }
+      }
+    }
+
+#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
+
 #if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING    ) && \
     !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER )
 
@@ -1029,7 +1078,15 @@
     }
 
     /* Fine, now run the font program! */
+
+    /* In case of an error while executing `fpgm', we intentionally don't */
+    /* clean up immediately – bugs in the `fpgm' are so fundamental that  */
+    /* all following hinting calls should fail.  Additionally, `fpgm' is  */
+    /* to be executed just once; calling it again is completely useless   */
+    /* and might even lead to extremely slow behaviour if it is malformed */
+    /* (containing an infinite loop, for example).                        */
     error = tt_size_run_fpgm( size, pedantic );
+    return error;
 
   Exit:
     if ( error )
diff --git a/src/truetype/ttobjs.h b/src/truetype/ttobjs.h
index 7ac4123..9396089 100644
--- a/src/truetype/ttobjs.h
+++ b/src/truetype/ttobjs.h
@@ -42,17 +42,6 @@
   /*************************************************************************/
   /*                                                                       */
   /* <Type>                                                                */
-  /*    TT_Instance                                                        */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A handle to a TrueType size object.                                */
-  /*                                                                       */
-  typedef struct TT_SizeRec_*  TT_Size;
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Type>                                                                */
   /*    TT_GlyphSlot                                                       */
   /*                                                                       */
   /* <Description>                                                         */
diff --git a/src/truetype/ttpic.h b/src/truetype/ttpic.h
index 48ba4aa..076ae56 100644
--- a/src/truetype/ttpic.h
+++ b/src/truetype/ttpic.h
@@ -20,7 +20,8 @@
 #define __TTPIC_H__
 
 
-FT_BEGIN_HEADER
+#include FT_INTERNAL_PIC_H
+
 
 #ifndef FT_CONFIG_OPTION_PIC
 
@@ -37,6 +38,8 @@
 #include FT_SERVICE_PROPERTIES_H
 
 
+FT_BEGIN_HEADER
+
   typedef struct  TTModulePIC_
   {
     FT_ServiceDescRec*          tt_services;
@@ -68,13 +71,12 @@
   FT_Error
   tt_driver_class_pic_init( FT_Library  library );
 
+FT_END_HEADER
+
 #endif /* FT_CONFIG_OPTION_PIC */
 
  /* */
 
-
-FT_END_HEADER
-
 #endif /* __TTPIC_H__ */
 
 
diff --git a/src/truetype/ttpload.c b/src/truetype/ttpload.c
index fb338bd..9bf67f9 100644
--- a/src/truetype/ttpload.c
+++ b/src/truetype/ttpload.c
@@ -124,8 +124,9 @@
         TT_Table  entry = face->dir_tables;
         TT_Table  limit = entry + face->num_tables;
 
-        FT_Long   pos  = (FT_Long)FT_STREAM_POS();
-        FT_Long   dist = 0x7FFFFFFFL;
+        FT_Long  pos   = (FT_Long)FT_STREAM_POS();
+        FT_Long  dist  = 0x7FFFFFFFL;
+        FT_Bool  found = 0;
 
 
         /* compute the distance to next table in font file */
@@ -135,10 +136,13 @@
 
 
           if ( diff > 0 && diff < dist )
-            dist = diff;
+          {
+            dist  = diff;
+            found = 1;
+          }
         }
 
-        if ( entry == limit )
+        if ( !found )
         {
           /* `loca' is the last table */
           dist = (FT_Long)stream->size - pos;
@@ -152,6 +156,14 @@
           FT_TRACE2(( "adjusting num_locations to %d\n",
                       face->num_locations ));
         }
+        else
+        {
+          face->root.num_glyphs = face->num_locations
+                                    ? (FT_Long)face->num_locations - 1 : 0;
+
+          FT_TRACE2(( "adjusting num_glyphs to %d\n",
+                      face->root.num_glyphs ));
+        }
       }
     }
 
@@ -214,7 +226,8 @@
     if ( pos1 > face->glyf_len )
     {
       FT_TRACE1(( "tt_face_get_location:"
-                  " too large offset=0x%08lx found for gid=0x%04lx,"
+                  " too large offset=0x%08lx found for gid=0x%04lx,\n"
+                  "                     "
                   " exceeding the end of glyf table (0x%08lx)\n",
                   pos1, gindex, face->glyf_len ));
       *asize = 0;
@@ -224,7 +237,8 @@
     if ( pos2 > face->glyf_len )
     {
       FT_TRACE1(( "tt_face_get_location:"
-                  " too large offset=0x%08lx found for gid=0x%04lx,"
+                  " too large offset=0x%08lx found for gid=0x%04lx,\n"
+                  "                     "
                   " truncate at the end of glyf table (0x%08lx)\n",
                   pos2, gindex + 1, face->glyf_len ));
       pos2 = face->glyf_len;
diff --git a/src/truetype/ttsubpix.c b/src/truetype/ttsubpix.c
index dbda4d9..0d391e9 100644
--- a/src/truetype/ttsubpix.c
+++ b/src/truetype/ttsubpix.c
@@ -903,7 +903,7 @@
   sph_set_tweaks( TT_Loader  loader,
                   FT_UInt    glyph_index )
   {
-    TT_Face     face   = (TT_Face)loader->face;
+    TT_Face     face   = loader->face;
     FT_String*  family = face->root.family_name;
     FT_UInt     ppem   = loader->size->metrics.x_ppem;
     FT_String*  style  = face->root.style_name;