shithub: freetype+ttf2subf

Download patch

ref: 766f529a3109870f5921ff812e9b7832263c0fbc
parent: 8a1b5c0c6da164a1a021eb24e996d2adf26f98bb
author: Ewald Hew <[email protected]>
date: Sun Sep 24 18:40:07 EDT 2017

Rename files.

Replace the `cf2' file name prefix with `ps' as the Adobe engine
will be used for both PostScript Types 1 and 2 (CFF) instead of just
CFF.

s/cf2/ps/ for all following.

* src/psaux/cf2*: Rename files.
* src/psaux/*: Update includes.

* src/psaux/Jamfile (_sources), src/psaux/rules.mk (PSAUX_DRC_SRC,
PSAUX_DRV_H): Update file references.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
 2017-09-24  Ewald Hew  <[email protected]>
 
+	[psaux] Rename files.
+
+	Replace the `cf2' file name prefix with `ps' as the Adobe engine
+	will be used for both PostScript Types 1 and 2 (CFF) instead of just
+	CFF.
+
+	s/cf2/ps/ for all following.
+
+	* src/psaux/cf2*: Rename files.
+	* src/psaux/*: Update includes.
+
+	* src/psaux/Jamfile (_sources), src/psaux/rules.mk (PSAUX_DRC_SRC,
+	PSAUX_DRV_H): Update file references.
+
+2017-09-24  Ewald Hew  <[email protected]>
+
 	[psaux] Minor fix.
 
 	Use `MultiMasters' service in `psaux' instead of a call to `cff'. 
--- a/src/psaux/Jamfile
+++ b/src/psaux/Jamfile
@@ -22,15 +22,15 @@
                psobjs
                t1cmap
                t1decode
-               cf2arrst
-               cf2blues
-               cf2error
-               cf2font
-               cf2ft
-               cf2hints
-               cf2intrp
-               cf2read
-               cf2stack
+               psarrst
+               psblues
+               pserror
+               psfont
+               psft
+               pshints
+               psintrp
+               psread
+               psstack
                ;
   }
   else
--- a/src/psaux/cf2arrst.c
+++ /dev/null
@@ -1,241 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2arrst.c                                                             */
-/*                                                                         */
-/*    Adobe's code for Array Stacks (body).                                */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include FT_INTERNAL_DEBUG_H
-
-#include "cf2glue.h"
-#include "cf2arrst.h"
-
-#include "cf2error.h"
-
-
-  /*
-   * CF2_ArrStack uses an error pointer, to enable shared errors.
-   * Shared errors are necessary when multiple objects allow the program
-   * to continue after detecting errors.  Only the first error should be
-   * recorded.
-   */
-
-  FT_LOCAL_DEF( void )
-  cf2_arrstack_init( CF2_ArrStack  arrstack,
-                     FT_Memory     memory,
-                     FT_Error*     error,
-                     size_t        sizeItem )
-  {
-    FT_ASSERT( arrstack );
-
-    /* initialize the structure */
-    arrstack->memory    = memory;
-    arrstack->error     = error;
-    arrstack->sizeItem  = sizeItem;
-    arrstack->allocated = 0;
-    arrstack->chunk     = 10;    /* chunks of 10 items */
-    arrstack->count     = 0;
-    arrstack->totalSize = 0;
-    arrstack->ptr       = NULL;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_arrstack_finalize( CF2_ArrStack  arrstack )
-  {
-    FT_Memory  memory = arrstack->memory;     /* for FT_FREE */
-
-
-    FT_ASSERT( arrstack );
-
-    arrstack->allocated = 0;
-    arrstack->count     = 0;
-    arrstack->totalSize = 0;
-
-    /* free the data buffer */
-    FT_FREE( arrstack->ptr );
-  }
-
-
-  /* allocate or reallocate the buffer size; */
-  /* return false on memory error */
-  static FT_Bool
-  cf2_arrstack_setNumElements( CF2_ArrStack  arrstack,
-                               size_t        numElements )
-  {
-    FT_ASSERT( arrstack );
-
-    {
-      FT_Error   error  = FT_Err_Ok;        /* for FT_REALLOC */
-      FT_Memory  memory = arrstack->memory; /* for FT_REALLOC */
-
-      size_t  newSize = numElements * arrstack->sizeItem;
-
-
-      if ( numElements > FT_LONG_MAX / arrstack->sizeItem )
-        goto exit;
-
-
-      FT_ASSERT( newSize > 0 );   /* avoid realloc with zero size */
-
-      if ( !FT_REALLOC( arrstack->ptr, arrstack->totalSize, newSize ) )
-      {
-        arrstack->allocated = numElements;
-        arrstack->totalSize = newSize;
-
-        if ( arrstack->count > numElements )
-        {
-          /* we truncated the list! */
-          CF2_SET_ERROR( arrstack->error, Stack_Overflow );
-          arrstack->count = numElements;
-          return FALSE;
-        }
-
-        return TRUE;     /* success */
-      }
-    }
-
-  exit:
-    /* if there's not already an error, store this one */
-    CF2_SET_ERROR( arrstack->error, Out_Of_Memory );
-
-    return FALSE;
-  }
-
-
-  /* set the count, ensuring allocation is sufficient */
-  FT_LOCAL_DEF( void )
-  cf2_arrstack_setCount( CF2_ArrStack  arrstack,
-                         size_t        numElements )
-  {
-    FT_ASSERT( arrstack );
-
-    if ( numElements > arrstack->allocated )
-    {
-      /* expand the allocation first */
-      if ( !cf2_arrstack_setNumElements( arrstack, numElements ) )
-        return;
-    }
-
-    arrstack->count = numElements;
-  }
-
-
-  /* clear the count */
-  FT_LOCAL_DEF( void )
-  cf2_arrstack_clear( CF2_ArrStack  arrstack )
-  {
-    FT_ASSERT( arrstack );
-
-    arrstack->count = 0;
-  }
-
-
-  /* current number of items */
-  FT_LOCAL_DEF( size_t )
-  cf2_arrstack_size( const CF2_ArrStack  arrstack )
-  {
-    FT_ASSERT( arrstack );
-
-    return arrstack->count;
-  }
-
-
-  FT_LOCAL_DEF( void* )
-  cf2_arrstack_getBuffer( const CF2_ArrStack  arrstack )
-  {
-    FT_ASSERT( arrstack );
-
-    return arrstack->ptr;
-  }
-
-
-  /* return pointer to the given element */
-  FT_LOCAL_DEF( void* )
-  cf2_arrstack_getPointer( const CF2_ArrStack  arrstack,
-                           size_t              idx )
-  {
-    void*  newPtr;
-
-
-    FT_ASSERT( arrstack );
-
-    if ( idx >= arrstack->count )
-    {
-      /* overflow */
-      CF2_SET_ERROR( arrstack->error, Stack_Overflow );
-      idx = 0;    /* choose safe default */
-    }
-
-    newPtr = (FT_Byte*)arrstack->ptr + idx * arrstack->sizeItem;
-
-    return newPtr;
-  }
-
-
-  /* push (append) an element at the end of the list;         */
-  /* return false on memory error                             */
-  /* TODO: should there be a length param for extra checking? */
-  FT_LOCAL_DEF( void )
-  cf2_arrstack_push( CF2_ArrStack  arrstack,
-                     const void*   ptr )
-  {
-    FT_ASSERT( arrstack );
-
-    if ( arrstack->count == arrstack->allocated )
-    {
-      /* grow the buffer by one chunk */
-      if ( !cf2_arrstack_setNumElements(
-             arrstack, arrstack->allocated + arrstack->chunk ) )
-      {
-        /* on error, ignore the push */
-        return;
-      }
-    }
-
-    FT_ASSERT( ptr );
-
-    {
-      size_t  offset = arrstack->count * arrstack->sizeItem;
-      void*   newPtr = (FT_Byte*)arrstack->ptr + offset;
-
-
-      FT_MEM_COPY( newPtr, ptr, arrstack->sizeItem );
-      arrstack->count += 1;
-    }
-  }
-
-
-/* END */
--- a/src/psaux/cf2arrst.h
+++ /dev/null
@@ -1,100 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2arrst.h                                                             */
-/*                                                                         */
-/*    Adobe's code for Array Stacks (specification).                       */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2ARRST_H_
-#define CF2ARRST_H_
-
-
-#include "cf2error.h"
-
-
-FT_BEGIN_HEADER
-
-
-  /* need to define the struct here (not opaque) so it can be allocated by */
-  /* clients                                                               */
-  typedef struct  CF2_ArrStackRec_
-  {
-    FT_Memory  memory;
-    FT_Error*  error;
-
-    size_t  sizeItem;       /* bytes per element             */
-    size_t  allocated;      /* items allocated               */
-    size_t  chunk;          /* allocation increment in items */
-    size_t  count;          /* number of elements allocated  */
-    size_t  totalSize;      /* total bytes allocated         */
-
-    void*  ptr;             /* ptr to data                   */
-
-  } CF2_ArrStackRec, *CF2_ArrStack;
-
-
-  FT_LOCAL( void )
-  cf2_arrstack_init( CF2_ArrStack  arrstack,
-                     FT_Memory     memory,
-                     FT_Error*     error,
-                     size_t        sizeItem );
-  FT_LOCAL( void )
-  cf2_arrstack_finalize( CF2_ArrStack  arrstack );
-
-  FT_LOCAL( void )
-  cf2_arrstack_setCount( CF2_ArrStack  arrstack,
-                         size_t        numElements );
-  FT_LOCAL( void )
-  cf2_arrstack_clear( CF2_ArrStack  arrstack );
-  FT_LOCAL( size_t )
-  cf2_arrstack_size( const CF2_ArrStack  arrstack );
-
-  FT_LOCAL( void* )
-  cf2_arrstack_getBuffer( const CF2_ArrStack  arrstack );
-  FT_LOCAL( void* )
-  cf2_arrstack_getPointer( const CF2_ArrStack  arrstack,
-                           size_t              idx );
-
-  FT_LOCAL( void )
-  cf2_arrstack_push( CF2_ArrStack  arrstack,
-                     const void*   ptr );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2ARRST_H_ */
-
-
-/* END */
--- a/src/psaux/cf2blues.c
+++ /dev/null
@@ -1,582 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2blues.c                                                             */
-/*                                                                         */
-/*    Adobe's code for handling Blue Zones (body).                         */
-/*                                                                         */
-/*  Copyright 2009-2014 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include FT_INTERNAL_DEBUG_H
-
-#include "cf2blues.h"
-#include "cf2hints.h"
-#include "cf2font.h"
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* 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_cf2blues
-
-
-  /*
-   * For blue values, the FreeType parser produces an array of integers,
-   * while the Adobe CFF engine produces an array of fixed.
-   * Define a macro to convert FreeType to fixed.
-   */
-#define cf2_blueToFixed( x )  cf2_intToFixed( x )
-
-
-  FT_LOCAL_DEF( void )
-  cf2_blues_init( CF2_Blues  blues,
-                  CF2_Font   font )
-  {
-    /* pointer to parsed font object */
-    CFF_Decoder*  decoder = font->decoder;
-
-    CF2_Fixed  zoneHeight;
-    CF2_Fixed  maxZoneHeight = 0;
-    CF2_Fixed  csUnitsPerPixel;
-
-    size_t  numBlueValues;
-    size_t  numOtherBlues;
-    size_t  numFamilyBlues;
-    size_t  numFamilyOtherBlues;
-
-    FT_Pos*  blueValues;
-    FT_Pos*  otherBlues;
-    FT_Pos*  familyBlues;
-    FT_Pos*  familyOtherBlues;
-
-    size_t     i;
-    CF2_Fixed  emBoxBottom, emBoxTop;
-
-#if 0
-    CF2_Int  unitsPerEm = font->unitsPerEm;
-
-
-    if ( unitsPerEm == 0 )
-      unitsPerEm = 1000;
-#endif
-
-    FT_ZERO( blues );
-    blues->scale = font->innerTransform.d;
-
-    cf2_getBlueMetrics( decoder,
-                        &blues->blueScale,
-                        &blues->blueShift,
-                        &blues->blueFuzz );
-
-    cf2_getBlueValues( decoder, &numBlueValues, &blueValues );
-    cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues );
-    cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues );
-    cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues );
-
-    /*
-     * synthetic em box hint heuristic
-     *
-     * Apply this when ideographic dictionary (LanguageGroup 1) has no
-     * real alignment zones.  Adobe tools generate dummy zones at -250 and
-     * 1100 for a 1000 unit em.  Fonts with ICF-based alignment zones
-     * should not enable the heuristic.  When the heuristic is enabled,
-     * the font's blue zones are ignored.
-     *
-     */
-
-    /* get em box from OS/2 typoAscender/Descender                      */
-    /* TODO: FreeType does not parse these metrics.  Skip them for now. */
-#if 0
-    FCM_getHorizontalLineMetrics( &e,
-                                  font->font,
-                                  &ascender,
-                                  &descender,
-                                  &linegap );
-    if ( ascender - descender == unitsPerEm )
-    {
-      emBoxBottom = cf2_intToFixed( descender );
-      emBoxTop    = cf2_intToFixed( ascender );
-    }
-    else
-#endif
-    {
-      emBoxBottom = CF2_ICF_Bottom;
-      emBoxTop    = CF2_ICF_Top;
-    }
-
-    if ( cf2_getLanguageGroup( decoder ) == 1                   &&
-         ( numBlueValues == 0                                 ||
-           ( numBlueValues == 4                             &&
-             cf2_blueToFixed( blueValues[0] ) < emBoxBottom &&
-             cf2_blueToFixed( blueValues[1] ) < emBoxBottom &&
-             cf2_blueToFixed( blueValues[2] ) > emBoxTop    &&
-             cf2_blueToFixed( blueValues[3] ) > emBoxTop    ) ) )
-    {
-      /*
-       * Construct hint edges suitable for synthetic ghost hints at top
-       * and bottom of em box.  +-CF2_MIN_COUNTER allows for unhinted
-       * features above or below the last hinted edge.  This also gives a
-       * net 1 pixel boost to the height of ideographic glyphs.
-       *
-       * Note: Adjust synthetic hints outward by epsilon (0x.0001) to
-       *       avoid interference.  E.g., some fonts have real hints at
-       *       880 and -120.
-       */
-
-      blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON;
-      blues->emBoxBottomEdge.dsCoord = cf2_fixedRound(
-                                         FT_MulFix(
-                                           blues->emBoxBottomEdge.csCoord,
-                                           blues->scale ) ) -
-                                       CF2_MIN_COUNTER;
-      blues->emBoxBottomEdge.scale   = blues->scale;
-      blues->emBoxBottomEdge.flags   = CF2_GhostBottom |
-                                       CF2_Locked |
-                                       CF2_Synthetic;
-
-      blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON +
-                                    2 * font->darkenY;
-      blues->emBoxTopEdge.dsCoord = cf2_fixedRound(
-                                      FT_MulFix(
-                                        blues->emBoxTopEdge.csCoord,
-                                        blues->scale ) ) +
-                                    CF2_MIN_COUNTER;
-      blues->emBoxTopEdge.scale   = blues->scale;
-      blues->emBoxTopEdge.flags   = CF2_GhostTop |
-                                    CF2_Locked |
-                                    CF2_Synthetic;
-
-      blues->doEmBoxHints = TRUE;    /* enable the heuristic */
-
-      return;
-    }
-
-    /* copy `BlueValues' and `OtherBlues' to a combined array of top and */
-    /* bottom zones                                                      */
-    for ( i = 0; i < numBlueValues; i += 2 )
-    {
-      blues->zone[blues->count].csBottomEdge =
-        cf2_blueToFixed( blueValues[i] );
-      blues->zone[blues->count].csTopEdge =
-        cf2_blueToFixed( blueValues[i + 1] );
-
-      zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge,
-                              blues->zone[blues->count].csBottomEdge );
-
-      if ( zoneHeight < 0 )
-      {
-        FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
-        continue;   /* reject this zone */
-      }
-
-      if ( zoneHeight > maxZoneHeight )
-      {
-        /* take maximum before darkening adjustment      */
-        /* so overshoot suppression point doesn't change */
-        maxZoneHeight = zoneHeight;
-      }
-
-      /* adjust both edges of top zone upward by twice darkening amount */
-      if ( i != 0 )
-      {
-        blues->zone[blues->count].csTopEdge    += 2 * font->darkenY;
-        blues->zone[blues->count].csBottomEdge += 2 * font->darkenY;
-      }
-
-      /* first `BlueValue' is bottom zone; others are top */
-      if ( i == 0 )
-      {
-        blues->zone[blues->count].bottomZone =
-          TRUE;
-        blues->zone[blues->count].csFlatEdge =
-          blues->zone[blues->count].csTopEdge;
-      }
-      else
-      {
-        blues->zone[blues->count].bottomZone =
-          FALSE;
-        blues->zone[blues->count].csFlatEdge =
-          blues->zone[blues->count].csBottomEdge;
-      }
-
-      blues->count += 1;
-    }
-
-    for ( i = 0; i < numOtherBlues; i += 2 )
-    {
-      blues->zone[blues->count].csBottomEdge =
-        cf2_blueToFixed( otherBlues[i] );
-      blues->zone[blues->count].csTopEdge =
-        cf2_blueToFixed( otherBlues[i + 1] );
-
-      zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge,
-                              blues->zone[blues->count].csBottomEdge );
-
-      if ( zoneHeight < 0 )
-      {
-        FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
-        continue;   /* reject this zone */
-      }
-
-      if ( zoneHeight > maxZoneHeight )
-      {
-        /* take maximum before darkening adjustment      */
-        /* so overshoot suppression point doesn't change */
-        maxZoneHeight = zoneHeight;
-      }
-
-      /* Note: bottom zones are not adjusted for darkening amount */
-
-      /* all OtherBlues are bottom zone */
-      blues->zone[blues->count].bottomZone =
-        TRUE;
-      blues->zone[blues->count].csFlatEdge =
-        blues->zone[blues->count].csTopEdge;
-
-      blues->count += 1;
-    }
-
-    /* Adjust for FamilyBlues */
-
-    /* Search for the nearest flat edge in `FamilyBlues' or                */
-    /* `FamilyOtherBlues'.  According to the Black Book, any matching edge */
-    /* must be within one device pixel                                     */
-
-    csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale );
-
-    /* loop on all zones in this font */
-    for ( i = 0; i < blues->count; i++ )
-    {
-      size_t     j;
-      CF2_Fixed  minDiff;
-      CF2_Fixed  flatFamilyEdge, diff;
-      /* value for this font */
-      CF2_Fixed  flatEdge = blues->zone[i].csFlatEdge;
-
-
-      if ( blues->zone[i].bottomZone )
-      {
-        /* In a bottom zone, the top edge is the flat edge.             */
-        /* Search `FamilyOtherBlues' for bottom zones; look for closest */
-        /* Family edge that is within the one pixel threshold.          */
-
-        minDiff = CF2_FIXED_MAX;
-
-        for ( j = 0; j < numFamilyOtherBlues; j += 2 )
-        {
-          /* top edge */
-          flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] );
-
-          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );
-
-          if ( diff < minDiff && diff < csUnitsPerPixel )
-          {
-            blues->zone[i].csFlatEdge = flatFamilyEdge;
-            minDiff                   = diff;
-
-            if ( diff == 0 )
-              break;
-          }
-        }
-
-        /* check the first member of FamilyBlues, which is a bottom zone */
-        if ( numFamilyBlues >= 2 )
-        {
-          /* top edge */
-          flatFamilyEdge = cf2_blueToFixed( familyBlues[1] );
-
-          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );
-
-          if ( diff < minDiff && diff < csUnitsPerPixel )
-            blues->zone[i].csFlatEdge = flatFamilyEdge;
-        }
-      }
-      else
-      {
-        /* In a top zone, the bottom edge is the flat edge.                */
-        /* Search `FamilyBlues' for top zones; skip first zone, which is a */
-        /* bottom zone; look for closest Family edge that is within the    */
-        /* one pixel threshold                                             */
-
-        minDiff = CF2_FIXED_MAX;
-
-        for ( j = 2; j < numFamilyBlues; j += 2 )
-        {
-          /* bottom edge */
-          flatFamilyEdge = cf2_blueToFixed( familyBlues[j] );
-
-          /* adjust edges of top zone upward by twice darkening amount */
-          flatFamilyEdge += 2 * font->darkenY;      /* bottom edge */
-
-          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );
-
-          if ( diff < minDiff && diff < csUnitsPerPixel )
-          {
-            blues->zone[i].csFlatEdge = flatFamilyEdge;
-            minDiff                   = diff;
-
-            if ( diff == 0 )
-              break;
-          }
-        }
-      }
-    }
-
-    /* TODO: enforce separation of zones, including BlueFuzz */
-
-    /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */
-    /* `bcsetup.c'.                                               */
-
-    if ( maxZoneHeight > 0 )
-    {
-      if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ),
-                                         maxZoneHeight ) )
-      {
-        /* clamp at maximum scale */
-        blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ),
-                                      maxZoneHeight );
-      }
-
-      /*
-       * TODO: Revisit the bug fix for 613448.  The minimum scale
-       *       requirement catches a number of library fonts.  For
-       *       example, with default BlueScale (.039625) and 0.4 minimum,
-       *       the test below catches any font with maxZoneHeight < 10.1.
-       *       There are library fonts ranging from 2 to 10 that get
-       *       caught, including e.g., Eurostile LT Std Medium with
-       *       maxZoneHeight of 6.
-       *
-       */
-#if 0
-      if ( blueScale < .4 / maxZoneHeight )
-      {
-        tetraphilia_assert( 0 );
-        /* clamp at minimum scale, per bug 0613448 fix */
-        blueScale = .4 / maxZoneHeight;
-      }
-#endif
-
-    }
-
-    /*
-     * Suppress overshoot and boost blue zones at small sizes.  Boost
-     * amount varies linearly from 0.5 pixel near 0 to 0 pixel at
-     * blueScale cutoff.
-     * Note: This boost amount is different from the coretype heuristic.
-     *
-     */
-
-    if ( blues->scale < blues->blueScale )
-    {
-      blues->suppressOvershoot = TRUE;
-
-      /* Change rounding threshold for `dsFlatEdge'.                    */
-      /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */
-      /*       10ppem Arial                                             */
-
-      blues->boost = cf2_doubleToFixed( .6 ) -
-                       FT_MulDiv( cf2_doubleToFixed ( .6 ),
-                                  blues->scale,
-                                  blues->blueScale );
-      if ( blues->boost > 0x7FFF )
-      {
-        /* boost must remain less than 0.5, or baseline could go negative */
-        blues->boost = 0x7FFF;
-      }
-    }
-
-    /* boost and darkening have similar effects; don't do both */
-    if ( font->stemDarkened )
-      blues->boost = 0;
-
-    /* set device space alignment for each zone;    */
-    /* apply boost amount before rounding flat edge */
-
-    for ( i = 0; i < blues->count; i++ )
-    {
-      if ( blues->zone[i].bottomZone )
-        blues->zone[i].dsFlatEdge = cf2_fixedRound(
-                                      FT_MulFix(
-                                        blues->zone[i].csFlatEdge,
-                                        blues->scale ) -
-                                      blues->boost );
-      else
-        blues->zone[i].dsFlatEdge = cf2_fixedRound(
-                                      FT_MulFix(
-                                        blues->zone[i].csFlatEdge,
-                                        blues->scale ) +
-                                      blues->boost );
-    }
-  }
-
-
-  /*
-   * Check whether `stemHint' is captured by one of the blue zones.
-   *
-   * Zero, one or both edges may be valid; only valid edges can be
-   * captured.  For compatibility with CoolType, search top and bottom
-   * zones in the same pass (see `BlueLock').  If a hint is captured,
-   * return true and position the edge(s) in one of 3 ways:
-   *
-   *  1) If `BlueScale' suppresses overshoot, position the captured edge
-   *     at the flat edge of the zone.
-   *  2) If overshoot is not suppressed and `BlueShift' requires
-   *     overshoot, position the captured edge a minimum of 1 device pixel
-   *     from the flat edge.
-   *  3) If overshoot is not suppressed or required, position the captured
-   *     edge at the nearest device pixel.
-   *
-   */
-  FT_LOCAL_DEF( FT_Bool )
-  cf2_blues_capture( const CF2_Blues  blues,
-                     CF2_Hint         bottomHintEdge,
-                     CF2_Hint         topHintEdge )
-  {
-    /* TODO: validate? */
-    CF2_Fixed  csFuzz = blues->blueFuzz;
-
-    /* new position of captured edge */
-    CF2_Fixed  dsNew;
-
-    /* amount that hint is moved when positioned */
-    CF2_Fixed  dsMove = 0;
-
-    FT_Bool   captured = FALSE;
-    CF2_UInt  i;
-
-
-    /* assert edge flags are consistent */
-    FT_ASSERT( !cf2_hint_isTop( bottomHintEdge ) &&
-               !cf2_hint_isBottom( topHintEdge ) );
-
-    /* TODO: search once without blue fuzz for compatibility with coretype? */
-    for ( i = 0; i < blues->count; i++ )
-    {
-      if ( blues->zone[i].bottomZone           &&
-           cf2_hint_isBottom( bottomHintEdge ) )
-      {
-        if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <=
-               bottomHintEdge->csCoord                           &&
-             bottomHintEdge->csCoord <=
-               ADD_INT32( blues->zone[i].csTopEdge, csFuzz )     )
-        {
-          /* bottom edge captured by bottom zone */
-
-          if ( blues->suppressOvershoot )
-            dsNew = blues->zone[i].dsFlatEdge;
-
-          else if ( SUB_INT32( blues->zone[i].csTopEdge,
-                               bottomHintEdge->csCoord ) >=
-                      blues->blueShift )
-          {
-            /* guarantee minimum of 1 pixel overshoot */
-            dsNew = FT_MIN(
-                      cf2_fixedRound( bottomHintEdge->dsCoord ),
-                      blues->zone[i].dsFlatEdge - cf2_intToFixed( 1 ) );
-          }
-
-          else
-          {
-            /* simply round captured edge */
-            dsNew = cf2_fixedRound( bottomHintEdge->dsCoord );
-          }
-
-          dsMove   = SUB_INT32( dsNew, bottomHintEdge->dsCoord );
-          captured = TRUE;
-
-          break;
-        }
-      }
-
-      if ( !blues->zone[i].bottomZone && cf2_hint_isTop( topHintEdge ) )
-      {
-        if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <=
-               topHintEdge->csCoord                              &&
-             topHintEdge->csCoord <=
-               ADD_INT32( blues->zone[i].csTopEdge, csFuzz )     )
-        {
-          /* top edge captured by top zone */
-
-          if ( blues->suppressOvershoot )
-            dsNew = blues->zone[i].dsFlatEdge;
-
-          else if ( SUB_INT32( topHintEdge->csCoord,
-                               blues->zone[i].csBottomEdge ) >=
-                      blues->blueShift )
-          {
-            /* guarantee minimum of 1 pixel overshoot */
-            dsNew = FT_MAX(
-                      cf2_fixedRound( topHintEdge->dsCoord ),
-                      blues->zone[i].dsFlatEdge + cf2_intToFixed( 1 ) );
-          }
-
-          else
-          {
-            /* simply round captured edge */
-            dsNew = cf2_fixedRound( topHintEdge->dsCoord );
-          }
-
-          dsMove   = SUB_INT32( dsNew, topHintEdge->dsCoord );
-          captured = TRUE;
-
-          break;
-        }
-      }
-    }
-
-    if ( captured )
-    {
-      /* move both edges and flag them `locked' */
-      if ( cf2_hint_isValid( bottomHintEdge ) )
-      {
-        bottomHintEdge->dsCoord = ADD_INT32( bottomHintEdge->dsCoord,
-                                             dsMove );
-        cf2_hint_lock( bottomHintEdge );
-      }
-
-      if ( cf2_hint_isValid( topHintEdge ) )
-      {
-        topHintEdge->dsCoord = ADD_INT32( topHintEdge->dsCoord, dsMove );
-        cf2_hint_lock( topHintEdge );
-      }
-    }
-
-    return captured;
-  }
-
-
-/* END */
--- a/src/psaux/cf2blues.h
+++ /dev/null
@@ -1,185 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2blues.h                                                             */
-/*                                                                         */
-/*    Adobe's code for handling Blue Zones (specification).                */
-/*                                                                         */
-/*  Copyright 2009-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-  /*
-   * A `CF2_Blues' object stores the blue zones (horizontal alignment
-   * zones) of a font.  These are specified in the CFF private dictionary
-   * by `BlueValues', `OtherBlues', `FamilyBlues', and `FamilyOtherBlues'.
-   * Each zone is defined by a top and bottom edge in character space.
-   * Further, each zone is either a top zone or a bottom zone, as recorded
-   * by `bottomZone'.
-   *
-   * The maximum number of `BlueValues' and `FamilyBlues' is 7 each.
-   * However, these are combined to produce a total of 7 zones.
-   * Similarly, the maximum number of `OtherBlues' and `FamilyOtherBlues'
-   * is 5 and these are combined to produce an additional 5 zones.
-   *
-   * Blue zones are used to `capture' hints and force them to a common
-   * alignment point.  This alignment is recorded in device space in
-   * `dsFlatEdge'.  Except for this value, a `CF2_Blues' object could be
-   * constructed independently of scaling.  Construction may occur once
-   * the matrix is known.  Other features implemented in the Capture
-   * method are overshoot suppression, overshoot enforcement, and Blue
-   * Boost.
-   *
-   * Capture is determined by `BlueValues' and `OtherBlues', but the
-   * alignment point may be adjusted to the scaled flat edge of
-   * `FamilyBlues' or `FamilyOtherBlues'.  No alignment is done to the
-   * curved edge of a zone.
-   *
-   */
-
-
-#ifndef CF2BLUES_H_
-#define CF2BLUES_H_
-
-
-#include "cf2glue.h"
-
-
-FT_BEGIN_HEADER
-
-
-  /*
-   * `CF2_Hint' is shared by `cf2hints.h' and
-   * `cf2blues.h', but `cf2blues.h' depends on
-   * `cf2hints.h', so define it here.  Note: The typedef is in
-   * `cf2glue.h'.
-   *
-   */
-  enum
-  {
-    CF2_GhostBottom = 0x1,  /* a single bottom edge           */
-    CF2_GhostTop    = 0x2,  /* a single top edge              */
-    CF2_PairBottom  = 0x4,  /* the bottom edge of a stem hint */
-    CF2_PairTop     = 0x8,  /* the top edge of a stem hint    */
-    CF2_Locked      = 0x10, /* this edge has been aligned     */
-                            /* by a blue zone                 */
-    CF2_Synthetic   = 0x20  /* this edge was synthesized      */
-  };
-
-
-  /*
-   * Default value for OS/2 typoAscender/Descender when their difference
-   * is not equal to `unitsPerEm'.  The default is based on -250 and 1100
-   * in `CF2_Blues', assuming 1000 units per em here.
-   *
-   */
-  enum
-  {
-    CF2_ICF_Top    = cf2_intToFixed(  880 ),
-    CF2_ICF_Bottom = cf2_intToFixed( -120 )
-  };
-
-
-  /*
-   * Constant used for hint adjustment and for synthetic em box hint
-   * placement.
-   */
-#define CF2_MIN_COUNTER  cf2_doubleToFixed( 0.5 )
-
-
-  /* shared typedef is in cf2glue.h */
-  struct  CF2_HintRec_
-  {
-    CF2_UInt  flags;  /* attributes of the edge            */
-    size_t    index;  /* index in original stem hint array */
-                      /* (if not synthetic)                */
-    CF2_Fixed  csCoord;
-    CF2_Fixed  dsCoord;
-    CF2_Fixed  scale;
-  };
-
-
-  typedef struct  CF2_BlueRec_
-  {
-    CF2_Fixed  csBottomEdge;
-    CF2_Fixed  csTopEdge;
-    CF2_Fixed  csFlatEdge; /* may be from either local or Family zones */
-    CF2_Fixed  dsFlatEdge; /* top edge of bottom zone or bottom edge   */
-                           /* of top zone (rounded)                    */
-    FT_Bool  bottomZone;
-
-  } CF2_BlueRec;
-
-
-  /* max total blue zones is 12 */
-  enum
-  {
-    CF2_MAX_BLUES      = 7,
-    CF2_MAX_OTHERBLUES = 5
-  };
-
-
-  typedef struct  CF2_BluesRec_
-  {
-    CF2_Fixed  scale;
-    CF2_UInt   count;
-    FT_Bool    suppressOvershoot;
-    FT_Bool    doEmBoxHints;
-
-    CF2_Fixed  blueScale;
-    CF2_Fixed  blueShift;
-    CF2_Fixed  blueFuzz;
-
-    CF2_Fixed  boost;
-
-    CF2_HintRec  emBoxTopEdge;
-    CF2_HintRec  emBoxBottomEdge;
-
-    CF2_BlueRec  zone[CF2_MAX_BLUES + CF2_MAX_OTHERBLUES];
-
-  } CF2_BluesRec, *CF2_Blues;
-
-
-  FT_LOCAL( void )
-  cf2_blues_init( CF2_Blues  blues,
-                  CF2_Font   font );
-  FT_LOCAL( FT_Bool )
-  cf2_blues_capture( const CF2_Blues  blues,
-                     CF2_Hint         bottomHintEdge,
-                     CF2_Hint         topHintEdge );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2BLUES_H_ */
-
-
-/* END */
--- a/src/psaux/cf2error.c
+++ /dev/null
@@ -1,52 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2error.c                                                             */
-/*                                                                         */
-/*    Adobe's code for error handling (body).                              */
-/*                                                                         */
-/*  Copyright 2006-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include "cf2error.h"
-
-
-  FT_LOCAL_DEF( void )
-  cf2_setError( FT_Error*  error,
-                FT_Error   value )
-  {
-    if ( error && !*error )
-      *error = value;
-  }
-
-
-/* END */
--- a/src/psaux/cf2error.h
+++ /dev/null
@@ -1,119 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2error.h                                                             */
-/*                                                                         */
-/*    Adobe's code for error handling (specification).                     */
-/*                                                                         */
-/*  Copyright 2006-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2ERROR_H_
-#define CF2ERROR_H_
-
-
-#include FT_MODULE_ERRORS_H
-
-#undef FTERRORS_H_
-
-#undef  FT_ERR_PREFIX
-#define FT_ERR_PREFIX  CF2_Err_
-#define FT_ERR_BASE    FT_Mod_Err_CF2
-
-
-#include FT_ERRORS_H
-#include "cf2ft.h"
-
-
-FT_BEGIN_HEADER
-
-
-  /*
-   * A poor-man error facility.
-   *
-   * This code being written in vanilla C, doesn't have the luxury of a
-   * language-supported exception mechanism such as the one available in
-   * Java.  Instead, we are stuck with using error codes that must be
-   * carefully managed and preserved.  However, it is convenient for us to
-   * model our error mechanism on a Java-like exception mechanism.
-   * When we assign an error code we are thus `throwing' an error.
-   *
-   * The preservation of an error code is done by coding convention.
-   * Upon a function call if the error code is anything other than
-   * `FT_Err_Ok', which is guaranteed to be zero, we
-   * will return without altering that error.  This will allow the
-   * error to propagate and be handled at the appropriate location in
-   * the code.
-   *
-   * This allows a style of code where the error code is initialized
-   * up front and a block of calls are made with the error code only
-   * being checked after the block.  If a new error occurs, the original
-   * error will be preserved and a functional no-op should result in any
-   * subsequent function that has an initial error code not equal to
-   * `FT_Err_Ok'.
-   *
-   * Errors are encoded by calling the `FT_THROW' macro.  For example,
-   *
-   * {
-   *   FT_Error  e;
-   *
-   *
-   *   ...
-   *   e = FT_THROW( Out_Of_Memory );
-   * }
-   *
-   */
-
-
-  /* Set error code to a particular value. */
-  FT_LOCAL( void )
-  cf2_setError( FT_Error*  error,
-                FT_Error   value );
-
-
-  /*
-   * A macro that conditionally sets an error code.
-   *
-   * This macro will first check whether `error' is set;
-   * if not, it will set it to `e'.
-   *
-  */
-#define CF2_SET_ERROR( error, e )              \
-          cf2_setError( error, FT_THROW( e ) )
-
-
-FT_END_HEADER
-
-
-#endif /* CF2ERROR_H_ */
-
-
-/* END */
--- a/src/psaux/cf2fixed.h
+++ /dev/null
@@ -1,95 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2fixed.h                                                             */
-/*                                                                         */
-/*    Adobe's code for Fixed Point Mathematics (specification only).       */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2FIXED_H_
-#define CF2FIXED_H_
-
-
-FT_BEGIN_HEADER
-
-
-  /* rasterizer integer and fixed point arithmetic must be 32-bit */
-
-#define   CF2_Fixed  CF2_F16Dot16
-  typedef FT_Int32   CF2_Frac;   /* 2.30 fixed point */
-
-
-#define CF2_FIXED_MAX      ( (CF2_Fixed)0x7FFFFFFFL )
-#define CF2_FIXED_MIN      ( (CF2_Fixed)0x80000000L )
-#define CF2_FIXED_ONE      ( (CF2_Fixed)0x10000L )
-#define CF2_FIXED_EPSILON  ( (CF2_Fixed)0x0001 )
-
-  /* in C 89, left and right shift of negative numbers is  */
-  /* implementation specific behaviour in the general case */
-
-#define cf2_intToFixed( i )                                              \
-          ( (CF2_Fixed)( (FT_UInt32)(i) << 16 ) )
-#define cf2_fixedToInt( x )                                              \
-          ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
-#define cf2_fixedRound( x )                                              \
-          ( (CF2_Fixed)( ( (FT_UInt32)(x) + 0x8000U ) & 0xFFFF0000UL ) )
-#define cf2_doubleToFixed( f )                                           \
-          ( (CF2_Fixed)( (f) * 65536.0 + 0.5 ) )
-#define cf2_fixedAbs( x )                                                \
-          ( (x) < 0 ? NEG_INT32( x ) : (x) )
-#define cf2_fixedFloor( x )                                              \
-          ( (CF2_Fixed)( (FT_UInt32)(x) & 0xFFFF0000UL ) )
-#define cf2_fixedFraction( x )                                           \
-          ( (x) - cf2_fixedFloor( x ) )
-#define cf2_fracToFixed( x )                                             \
-          ( (x) < 0 ? -( ( -(x) + 0x2000 ) >> 14 )                       \
-                    :  ( (  (x) + 0x2000 ) >> 14 ) )
-
-
-  /* signed numeric types */
-  typedef enum  CF2_NumberType_
-  {
-    CF2_NumberFixed,    /* 16.16 */
-    CF2_NumberFrac,     /*  2.30 */
-    CF2_NumberInt       /* 32.0  */
-
-  } CF2_NumberType;
-
-
-FT_END_HEADER
-
-
-#endif /* CF2FIXED_H_ */
-
-
-/* END */
--- a/src/psaux/cf2font.c
+++ /dev/null
@@ -1,563 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2font.c                                                              */
-/*                                                                         */
-/*    Adobe's code for font instances (body).                              */
-/*                                                                         */
-/*  Copyright 2007-2014 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include <ft2build.h>
-#include FT_INTERNAL_CALC_H
-
-#include "cf2ft.h"
-
-#include "cf2glue.h"
-#include "cf2font.h"
-#include "cf2error.h"
-#include "cf2intrp.h"
-
-
-  /* Compute a stem darkening amount in character space. */
-  static void
-  cf2_computeDarkening( CF2_Fixed   emRatio,
-                        CF2_Fixed   ppem,
-                        CF2_Fixed   stemWidth,
-                        CF2_Fixed*  darkenAmount,
-                        CF2_Fixed   boldenAmount,
-                        FT_Bool     stemDarkened,
-                        FT_Int*     darkenParams )
-  {
-    /*
-     * Total darkening amount is computed in 1000 unit character space
-     * using the modified 5 part curve as Adobe's Avalon rasterizer.
-     * The darkening amount is smaller for thicker stems.
-     * It becomes zero when the stem is thicker than 2.333 pixels.
-     *
-     * By default, we use
-     *
-     *   darkenAmount = 0.4 pixels   if scaledStem <= 0.5 pixels,
-     *   darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels,
-     *   darkenAmount = 0 pixel      if scaledStem >= 2.333 pixels,
-     *
-     * and piecewise linear in-between:
-     *
-     *
-     *   darkening
-     *       ^
-     *       |
-     *       |      (x1,y1)
-     *       |--------+
-     *       |         \
-     *       |          \
-     *       |           \          (x3,y3)
-     *       |            +----------+
-     *       |        (x2,y2)         \
-     *       |                         \
-     *       |                          \
-     *       |                           +-----------------
-     *       |                         (x4,y4)
-     *       +--------------------------------------------->   stem
-     *                                                       thickness
-     *
-     *
-     * This corresponds to the following values for the
-     * `darkening-parameters' property:
-     *
-     *   (x1, y1) = (500, 400)
-     *   (x2, y2) = (1000, 275)
-     *   (x3, y3) = (1667, 275)
-     *   (x4, y4) = (2333, 0)
-     *
-     */
-
-    /* Internal calculations are done in units per thousand for */
-    /* convenience. The x axis is scaled stem width in          */
-    /* thousandths of a pixel. That is, 1000 is 1 pixel.        */
-    /* The y axis is darkening amount in thousandths of a pixel.*/
-    /* In the code, below, dividing by ppem and                 */
-    /* adjusting for emRatio converts darkenAmount to character */
-    /* space (font units).                                      */
-    CF2_Fixed  stemWidthPer1000, scaledStem;
-    FT_Int     logBase2;
-
-
-    *darkenAmount = 0;
-
-    if ( boldenAmount == 0 && !stemDarkened )
-      return;
-
-    /* protect against range problems and divide by zero */
-    if ( emRatio < cf2_doubleToFixed( .01 ) )
-      return;
-
-    if ( stemDarkened )
-    {
-      FT_Int  x1 = darkenParams[0];
-      FT_Int  y1 = darkenParams[1];
-      FT_Int  x2 = darkenParams[2];
-      FT_Int  y2 = darkenParams[3];
-      FT_Int  x3 = darkenParams[4];
-      FT_Int  y3 = darkenParams[5];
-      FT_Int  x4 = darkenParams[6];
-      FT_Int  y4 = darkenParams[7];
-
-
-      /* convert from true character space to 1000 unit character space; */
-      /* add synthetic emboldening effect                                */
-
-      /* `stemWidthPer1000' will not overflow for a legitimate font      */
-
-      stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio );
-
-      /* `scaledStem' can easily overflow, so we must clamp its maximum  */
-      /* value; the test doesn't need to be precise, but must be         */
-      /* conservative.  The clamp value (default 2333) where             */
-      /* `darkenAmount' is zero is well below the overflow value of      */
-      /* 32767.                                                          */
-      /*                                                                 */
-      /* FT_MSB computes the integer part of the base 2 logarithm.  The  */
-      /* number of bits for the product is 1 or 2 more than the sum of   */
-      /* logarithms; remembering that the 16 lowest bits of the fraction */
-      /* are dropped this is correct to within a factor of almost 4.     */
-      /* For example, 0x80.0000 * 0x80.0000 = 0x4000.0000 is 23+23 and   */
-      /* is flagged as possible overflow because 0xFF.FFFF * 0xFF.FFFF = */
-      /* 0xFFFF.FE00 is also 23+23.                                      */
-
-      logBase2 = FT_MSB( (FT_UInt32)stemWidthPer1000 ) +
-                   FT_MSB( (FT_UInt32)ppem );
-
-      if ( logBase2 >= 46 )
-        /* possible overflow */
-        scaledStem = cf2_intToFixed( x4 );
-      else
-        scaledStem = FT_MulFix( stemWidthPer1000, ppem );
-
-      /* now apply the darkening parameters */
-
-      if ( scaledStem < cf2_intToFixed( x1 ) )
-        *darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem );
-
-      else if ( scaledStem < cf2_intToFixed( x2 ) )
-      {
-        FT_Int  xdelta = x2 - x1;
-        FT_Int  ydelta = y2 - y1;
-        FT_Int  x      = stemWidthPer1000 -
-                           FT_DivFix( cf2_intToFixed( x1 ), ppem );
-
-
-        if ( !xdelta )
-          goto Try_x3;
-
-        *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
-                          FT_DivFix( cf2_intToFixed( y1 ), ppem );
-      }
-
-      else if ( scaledStem < cf2_intToFixed( x3 ) )
-      {
-      Try_x3:
-        {
-          FT_Int  xdelta = x3 - x2;
-          FT_Int  ydelta = y3 - y2;
-          FT_Int  x      = stemWidthPer1000 -
-                             FT_DivFix( cf2_intToFixed( x2 ), ppem );
-
-
-          if ( !xdelta )
-            goto Try_x4;
-
-          *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
-                            FT_DivFix( cf2_intToFixed( y2 ), ppem );
-        }
-      }
-
-      else if ( scaledStem < cf2_intToFixed( x4 ) )
-      {
-      Try_x4:
-        {
-          FT_Int  xdelta = x4 - x3;
-          FT_Int  ydelta = y4 - y3;
-          FT_Int  x      = stemWidthPer1000 -
-                             FT_DivFix( cf2_intToFixed( x3 ), ppem );
-
-
-          if ( !xdelta )
-            goto Use_y4;
-
-          *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
-                            FT_DivFix( cf2_intToFixed( y3 ), ppem );
-        }
-      }
-
-      else
-      {
-      Use_y4:
-        *darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem );
-      }
-
-      /* use half the amount on each side and convert back to true */
-      /* character space                                           */
-      *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio );
-    }
-
-    /* add synthetic emboldening effect in character space */
-    *darkenAmount += boldenAmount / 2;
-  }
-
-
-  /* set up values for the current FontDict and matrix; */
-  /* called for each glyph to be rendered               */
-
-  /* caller's transform is adjusted for subpixel positioning */
-  static void
-  cf2_font_setup( CF2_Font           font,
-                  const CF2_Matrix*  transform )
-  {
-    /* pointer to parsed font object */
-    CFF_Decoder*  decoder = font->decoder;
-
-    FT_Bool  needExtraSetup = FALSE;
-
-    CFF_VStoreRec*  vstore;
-    FT_Bool         hasVariations = FALSE;
-
-    /* character space units */
-    CF2_Fixed  boldenX = font->syntheticEmboldeningAmountX;
-    CF2_Fixed  boldenY = font->syntheticEmboldeningAmountY;
-
-    CFF_SubFont  subFont;
-    CF2_Fixed    ppem;
-
-    CF2_UInt   lenNormalizedV = 0;
-    FT_Fixed*  normalizedV    = NULL;
-
-    FT_Service_CFFLoad  cffload = (FT_Service_CFFLoad)font->cffload;
-
-    /* clear previous error */
-    font->error = FT_Err_Ok;
-
-    /* if a CID fontDict has changed, we need to recompute some cached */
-    /* data                                                            */
-    subFont = cf2_getSubfont( decoder );
-    if ( font->lastSubfont != subFont )
-    {
-      font->lastSubfont = subFont;
-      needExtraSetup    = TRUE;
-    }
-
-    /* check for variation vectors */
-    vstore        = cf2_getVStore( decoder );
-    hasVariations = ( vstore->dataCount != 0 );
-
-    if ( hasVariations )
-    {
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-      /* check whether Private DICT in this subfont needs to be reparsed */
-      font->error = cf2_getNormalizedVector( decoder,
-                                             &lenNormalizedV,
-                                             &normalizedV );
-      if ( font->error )
-        return;
-
-      if ( cffload->blend_check_vector( &subFont->blend,
-                                        subFont->private_dict.vsindex,
-                                        lenNormalizedV,
-                                        normalizedV ) )
-      {
-        /* blend has changed, reparse */
-        cffload->load_private_dict( decoder->cff,
-                                    subFont,
-                                    lenNormalizedV,
-                                    normalizedV );
-        needExtraSetup = TRUE;
-      }
-#endif
-
-      /* copy from subfont */
-      font->blend.font = subFont->blend.font;
-
-      /* clear state of charstring blend */
-      font->blend.usedBV = FALSE;
-
-      /* initialize value for charstring */
-      font->vsindex = subFont->private_dict.vsindex;
-
-      /* store vector inputs for blends in charstring */
-      font->lenNDV = lenNormalizedV;
-      font->NDV    = normalizedV;
-    }
-
-    /* if ppem has changed, we need to recompute some cached data         */
-    /* note: because of CID font matrix concatenation, ppem and transform */
-    /*       do not necessarily track.                                    */
-    ppem = cf2_getPpemY( decoder );
-    if ( font->ppem != ppem )
-    {
-      font->ppem     = ppem;
-      needExtraSetup = TRUE;
-    }
-
-    /* copy hinted flag on each call */
-    font->hinted = (FT_Bool)( font->renderingFlags & CF2_FlagsHinted );
-
-    /* determine if transform has changed;       */
-    /* include Fontmatrix but ignore translation */
-    if ( ft_memcmp( transform,
-                    &font->currentTransform,
-                    4 * sizeof ( CF2_Fixed ) ) != 0 )
-    {
-      /* save `key' information for `cache of one' matrix data; */
-      /* save client transform, without the translation         */
-      font->currentTransform    = *transform;
-      font->currentTransform.tx =
-      font->currentTransform.ty = cf2_intToFixed( 0 );
-
-      /* TODO: FreeType transform is simple scalar; for now, use identity */
-      /*       for outer                                                  */
-      font->innerTransform   = *transform;
-      font->outerTransform.a =
-      font->outerTransform.d = cf2_intToFixed( 1 );
-      font->outerTransform.b =
-      font->outerTransform.c = cf2_intToFixed( 0 );
-
-      needExtraSetup = TRUE;
-    }
-
-    /*
-     * font->darkened is set to true if there is a stem darkening request or
-     * the font is synthetic emboldened.
-     * font->darkened controls whether to adjust blue zones, winding order,
-     * and hinting.
-     *
-     */
-    if ( font->stemDarkened != ( font->renderingFlags & CF2_FlagsDarkened ) )
-    {
-      font->stemDarkened =
-        (FT_Bool)( font->renderingFlags & CF2_FlagsDarkened );
-
-      /* blue zones depend on darkened flag */
-      needExtraSetup = TRUE;
-    }
-
-    /* recompute variables that are dependent on transform or FontDict or */
-    /* darken flag                                                        */
-    if ( needExtraSetup )
-    {
-      /* StdVW is found in the private dictionary;                       */
-      /* recompute darkening amounts whenever private dictionary or      */
-      /* transform change                                                */
-      /* Note: a rendering flag turns darkening on or off, so we want to */
-      /*       store the `on' amounts;                                   */
-      /*       darkening amount is computed in character space           */
-      /* TODO: testing size-dependent darkening here;                    */
-      /*       what to do for rotations?                                 */
-
-      CF2_Fixed  emRatio;
-      CF2_Fixed  stdHW;
-      CF2_Int    unitsPerEm = font->unitsPerEm;
-
-
-      if ( unitsPerEm == 0 )
-        unitsPerEm = 1000;
-
-      ppem = FT_MAX( cf2_intToFixed( 4 ),
-                     font->ppem ); /* use minimum ppem of 4 */
-
-#if 0
-      /* since vstem is measured in the x-direction, we use the `a' member */
-      /* of the fontMatrix                                                 */
-      emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->a );
-#endif
-
-      /* Freetype does not preserve the fontMatrix when parsing; use */
-      /* unitsPerEm instead.                                         */
-      /* TODO: check precision of this                               */
-      emRatio     = cf2_intToFixed( 1000 ) / unitsPerEm;
-      font->stdVW = cf2_getStdVW( decoder );
-
-      if ( font->stdVW <= 0 )
-        font->stdVW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
-
-      if ( boldenX > 0 )
-      {
-        /* Ensure that boldenX is at least 1 pixel for synthetic bold font */
-        /* (similar to what Avalon does)                                   */
-        boldenX = FT_MAX( boldenX,
-                          FT_DivFix( cf2_intToFixed( unitsPerEm ), ppem ) );
-
-        /* Synthetic emboldening adds at least 1 pixel to darkenX, while */
-        /* stem darkening adds at most half pixel.  Since the purpose of */
-        /* stem darkening (readability at small sizes) is met with       */
-        /* synthetic emboldening, no need to add stem darkening for a    */
-        /* synthetic bold font.                                          */
-        cf2_computeDarkening( emRatio,
-                              ppem,
-                              font->stdVW,
-                              &font->darkenX,
-                              boldenX,
-                              FALSE,
-                              font->darkenParams );
-      }
-      else
-        cf2_computeDarkening( emRatio,
-                              ppem,
-                              font->stdVW,
-                              &font->darkenX,
-                              0,
-                              font->stemDarkened,
-                              font->darkenParams );
-
-#if 0
-      /* since hstem is measured in the y-direction, we use the `d' member */
-      /* of the fontMatrix                                                 */
-      /* TODO: use the same units per em as above; check this              */
-      emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->d );
-#endif
-
-      /* set the default stem width, because it must be the same for all */
-      /* family members;                                                 */
-      /* choose a constant for StdHW that depends on font contrast       */
-      stdHW = cf2_getStdHW( decoder );
-
-      if ( stdHW > 0 && font->stdVW > MUL_INT32( 2, stdHW ) )
-        font->stdHW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
-      else
-      {
-        /* low contrast font gets less hstem darkening */
-        font->stdHW = FT_DivFix( cf2_intToFixed( 110 ), emRatio );
-      }
-
-      cf2_computeDarkening( emRatio,
-                            ppem,
-                            font->stdHW,
-                            &font->darkenY,
-                            boldenY,
-                            font->stemDarkened,
-                            font->darkenParams );
-
-      if ( font->darkenX != 0 || font->darkenY != 0 )
-        font->darkened = TRUE;
-      else
-        font->darkened = FALSE;
-
-      font->reverseWinding = FALSE; /* initial expectation is CCW */
-
-      /* compute blue zones for this instance */
-      cf2_blues_init( &font->blues, font );
-
-    } /* needExtraSetup */
-  }
-
-
-  /* equivalent to AdobeGetOutline */
-  FT_LOCAL_DEF( FT_Error )
-  cf2_getGlyphOutline( CF2_Font           font,
-                       CF2_Buffer         charstring,
-                       const CF2_Matrix*  transform,
-                       CF2_F16Dot16*      glyphWidth )
-  {
-    FT_Error  lastError = FT_Err_Ok;
-
-    FT_Vector  translation;
-
-#if 0
-    FT_Vector  advancePoint;
-#endif
-
-    CF2_Fixed  advWidth = 0;
-    FT_Bool    needWinding;
-
-
-    /* Note: use both integer and fraction for outlines.  This allows bbox */
-    /*       to come out directly.                                         */
-
-    translation.x = transform->tx;
-    translation.y = transform->ty;
-
-    /* set up values based on transform */
-    cf2_font_setup( font, transform );
-    if ( font->error )
-      goto exit;                      /* setup encountered an error */
-
-    /* reset darken direction */
-    font->reverseWinding = FALSE;
-
-    /* winding order only affects darkening */
-    needWinding = font->darkened;
-
-    while ( 1 )
-    {
-      /* reset output buffer */
-      cf2_outline_reset( &font->outline );
-
-      /* build the outline, passing the full translation */
-      cf2_interpT2CharString( font,
-                              charstring,
-                              (CF2_OutlineCallbacks)&font->outline,
-                              &translation,
-                              FALSE,
-                              0,
-                              0,
-                              &advWidth );
-
-      if ( font->error )
-        goto exit;
-
-      if ( !needWinding )
-        break;
-
-      /* check winding order */
-      if ( font->outline.root.windingMomentum >= 0 ) /* CFF is CCW */
-        break;
-
-      /* invert darkening and render again                            */
-      /* TODO: this should be a parameter to getOutline-computeOffset */
-      font->reverseWinding = TRUE;
-
-      needWinding = FALSE;    /* exit after next iteration */
-    }
-
-    /* finish storing client outline */
-    cf2_outline_close( &font->outline );
-
-  exit:
-    /* FreeType just wants the advance width; there is no translation */
-    *glyphWidth = advWidth;
-
-    /* free resources and collect errors from objects we've used */
-    cf2_setError( &font->error, lastError );
-
-    return font->error;
-  }
-
-
-/* END */
--- a/src/psaux/cf2font.h
+++ /dev/null
@@ -1,133 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2font.h                                                              */
-/*                                                                         */
-/*    Adobe's code for font instances (specification).                     */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2FONT_H_
-#define CF2FONT_H_
-
-
-#include FT_SERVICE_CFF_TABLE_LOAD_H
-
-#include "cf2ft.h"
-#include "cf2blues.h"
-
-
-FT_BEGIN_HEADER
-
-
-#define CF2_OPERAND_STACK_SIZE  48
-#define CF2_MAX_SUBR            16 /* maximum subroutine nesting;         */
-                                   /* only 10 are allowed but there exist */
-                                   /* fonts like `HiraKakuProN-W3.ttf'    */
-                                   /* (Hiragino Kaku Gothic ProN W3;      */
-                                   /* 8.2d6e1; 2014-12-19) that exceed    */
-                                   /* this limit                          */
-#define CF2_STORAGE_SIZE        32
-
-
-  /* typedef is in `cf2glue.h' */
-  struct  CF2_FontRec_
-  {
-    FT_Memory  memory;
-    FT_Error   error;     /* shared error for this instance */
-
-    FT_Bool             isCFF2;
-    CF2_RenderingFlags  renderingFlags;
-
-    /* variables that depend on Transform:  */
-    /* the following have zero translation; */
-    /* inner * outer = font * original      */
-
-    CF2_Matrix  currentTransform;  /* original client matrix           */
-    CF2_Matrix  innerTransform;    /* for hinting; erect, scaled       */
-    CF2_Matrix  outerTransform;    /* post hinting; includes rotations */
-    CF2_Fixed   ppem;              /* transform-dependent              */
-
-    /* variation data */
-    CFF_BlendRec  blend;            /* cached charstring blend vector  */
-    CF2_UInt      vsindex;          /* current vsindex                 */
-    CF2_UInt      lenNDV;           /* current length NDV or zero      */
-    FT_Fixed*     NDV;              /* ptr to current NDV or NULL      */
-
-    CF2_Int  unitsPerEm;
-
-    CF2_Fixed  syntheticEmboldeningAmountX;   /* character space units */
-    CF2_Fixed  syntheticEmboldeningAmountY;   /* character space units */
-
-    /* FreeType related members */
-    CF2_OutlineRec  outline;       /* freetype glyph outline functions */
-    CFF_Decoder*    decoder;
-    CFF_SubFont     lastSubfont;              /* FreeType parsed data; */
-                                              /* top font or subfont   */
-
-    /* these flags can vary from one call to the next */
-    FT_Bool  hinted;
-    FT_Bool  darkened;       /* true if stemDarkened or synthetic bold */
-                             /* i.e. darkenX != 0 || darkenY != 0      */
-    FT_Bool  stemDarkened;
-
-    FT_Int  darkenParams[8];              /* 1000 unit character space */
-
-    /* variables that depend on both FontDict and Transform */
-    CF2_Fixed  stdVW;     /* in character space; depends on dict entry */
-    CF2_Fixed  stdHW;     /* in character space; depends on dict entry */
-    CF2_Fixed  darkenX;                    /* character space units    */
-    CF2_Fixed  darkenY;                    /* depends on transform     */
-                                           /* and private dict (StdVW) */
-    FT_Bool  reverseWinding;               /* darken assuming          */
-                                           /* counterclockwise winding */
-
-    CF2_BluesRec  blues;                         /* computed zone data */
-
-    FT_Service_CFFLoad  cffload;                  /* Pointer to cff functions */
-  };
-
-
-  FT_LOCAL( FT_Error )
-  cf2_getGlyphOutline( CF2_Font           font,
-                       CF2_Buffer         charstring,
-                       const CF2_Matrix*  transform,
-                       CF2_F16Dot16*      glyphWidth );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2FONT_H_ */
-
-
-/* END */
--- a/src/psaux/cf2ft.c
+++ /dev/null
@@ -1,768 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2ft.c                                                                */
-/*                                                                         */
-/*    FreeType Glue Component to Adobe's Interpreter (body).               */
-/*                                                                         */
-/*  Copyright 2013-2014 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include FT_INTERNAL_DEBUG_H
-
-#include "cf2font.h"
-#include "cf2error.h"
-
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-#include FT_MULTIPLE_MASTERS_H
-#include FT_SERVICE_MULTIPLE_MASTERS_H
-#endif
-
-#include FT_SERVICE_CFF_TABLE_LOAD_H
-
-#define CF2_MAX_SIZE  cf2_intToFixed( 2000 )    /* max ppem */
-
-
-  /*
-   * This check should avoid most internal overflow cases.  Clients should
-   * generally respond to `Glyph_Too_Big' by getting a glyph outline
-   * at EM size, scaling it and filling it as a graphics operation.
-   *
-   */
-  static FT_Error
-  cf2_checkTransform( const CF2_Matrix*  transform,
-                      CF2_Int            unitsPerEm )
-  {
-    CF2_Fixed  maxScale;
-
-
-    FT_ASSERT( unitsPerEm > 0 );
-
-    if ( transform->a <= 0 || transform->d <= 0 )
-      return FT_THROW( Invalid_Size_Handle );
-
-    FT_ASSERT( transform->b == 0 && transform->c == 0 );
-    FT_ASSERT( transform->tx == 0 && transform->ty == 0 );
-
-    if ( unitsPerEm > 0x7FFF )
-      return FT_THROW( Glyph_Too_Big );
-
-    maxScale = FT_DivFix( CF2_MAX_SIZE, cf2_intToFixed( unitsPerEm ) );
-
-    if ( transform->a > maxScale || transform->d > maxScale )
-      return FT_THROW( Glyph_Too_Big );
-
-    return FT_Err_Ok;
-  }
-
-
-  static void
-  cf2_setGlyphWidth( CF2_Outline  outline,
-                     CF2_Fixed    width )
-  {
-    CFF_Decoder*  decoder = outline->decoder;
-
-
-    FT_ASSERT( decoder );
-
-    decoder->glyph_width = cf2_fixedToInt( width );
-  }
-
-
-  /* Clean up font instance. */
-  static void
-  cf2_free_instance( void*  ptr )
-  {
-    CF2_Font  font = (CF2_Font)ptr;
-
-
-    if ( font )
-    {
-      FT_Memory  memory = font->memory;
-
-
-      FT_FREE( font->blend.lastNDV );
-      FT_FREE( font->blend.BV );
-    }
-  }
-
-
-  /********************************************/
-  /*                                          */
-  /* functions for handling client outline;   */
-  /* FreeType uses coordinates in 26.6 format */
-  /*                                          */
-  /********************************************/
-
-  static void
-  cf2_builder_moveTo( CF2_OutlineCallbacks      callbacks,
-                      const CF2_CallbackParams  params )
-  {
-    /* downcast the object pointer */
-    CF2_Outline   outline = (CF2_Outline)callbacks;
-    CFF_Builder*  builder;
-
-    (void)params;        /* only used in debug mode */
-
-
-    FT_ASSERT( outline && outline->decoder );
-    FT_ASSERT( params->op == CF2_PathOpMoveTo );
-
-    builder = &outline->decoder->builder;
-
-    /* note: two successive moves simply close the contour twice */
-    cff_builder_close_contour( builder );
-    builder->path_begun = 0;
-  }
-
-
-  static void
-  cf2_builder_lineTo( CF2_OutlineCallbacks      callbacks,
-                      const CF2_CallbackParams  params )
-  {
-    FT_Error  error;
-
-    /* downcast the object pointer */
-    CF2_Outline   outline = (CF2_Outline)callbacks;
-    CFF_Builder*  builder;
-
-
-    FT_ASSERT( outline && outline->decoder );
-    FT_ASSERT( params->op == CF2_PathOpLineTo );
-
-    builder = &outline->decoder->builder;
-
-    if ( !builder->path_begun )
-    {
-      /* record the move before the line; also check points and set */
-      /* `path_begun'                                               */
-      error = cff_builder_start_point( builder,
-                                       params->pt0.x,
-                                       params->pt0.y );
-      if ( error )
-      {
-        if ( !*callbacks->error )
-          *callbacks->error =  error;
-        return;
-      }
-    }
-
-    /* `cff_builder_add_point1' includes a check_points call for one point */
-    error = cff_builder_add_point1( builder,
-                                    params->pt1.x,
-                                    params->pt1.y );
-    if ( error )
-    {
-      if ( !*callbacks->error )
-        *callbacks->error =  error;
-      return;
-    }
-  }
-
-
-  static void
-  cf2_builder_cubeTo( CF2_OutlineCallbacks      callbacks,
-                      const CF2_CallbackParams  params )
-  {
-    FT_Error  error;
-
-    /* downcast the object pointer */
-    CF2_Outline   outline = (CF2_Outline)callbacks;
-    CFF_Builder*  builder;
-
-
-    FT_ASSERT( outline && outline->decoder );
-    FT_ASSERT( params->op == CF2_PathOpCubeTo );
-
-    builder = &outline->decoder->builder;
-
-    if ( !builder->path_begun )
-    {
-      /* record the move before the line; also check points and set */
-      /* `path_begun'                                               */
-      error = cff_builder_start_point( builder,
-                                       params->pt0.x,
-                                       params->pt0.y );
-      if ( error )
-      {
-        if ( !*callbacks->error )
-          *callbacks->error =  error;
-        return;
-      }
-    }
-
-    /* prepare room for 3 points: 2 off-curve, 1 on-curve */
-    error = cff_check_points( builder, 3 );
-    if ( error )
-    {
-      if ( !*callbacks->error )
-        *callbacks->error =  error;
-      return;
-    }
-
-    cff_builder_add_point( builder,
-                           params->pt1.x,
-                           params->pt1.y, 0 );
-    cff_builder_add_point( builder,
-                           params->pt2.x,
-                           params->pt2.y, 0 );
-    cff_builder_add_point( builder,
-                           params->pt3.x,
-                           params->pt3.y, 1 );
-  }
-
-
-  static void
-  cf2_outline_init( CF2_Outline  outline,
-                    FT_Memory    memory,
-                    FT_Error*    error )
-  {
-    FT_ZERO( outline );
-
-    outline->root.memory = memory;
-    outline->root.error  = error;
-
-    outline->root.moveTo = cf2_builder_moveTo;
-    outline->root.lineTo = cf2_builder_lineTo;
-    outline->root.cubeTo = cf2_builder_cubeTo;
-  }
-
-
-  /* get scaling and hint flag from GlyphSlot */
-  static void
-  cf2_getScaleAndHintFlag( CFF_Decoder*  decoder,
-                           CF2_Fixed*    x_scale,
-                           CF2_Fixed*    y_scale,
-                           FT_Bool*      hinted,
-                           FT_Bool*      scaled )
-  {
-    FT_ASSERT( decoder && decoder->builder.glyph );
-
-    /* note: FreeType scale includes a factor of 64 */
-    *hinted = decoder->builder.glyph->hint;
-    *scaled = decoder->builder.glyph->scaled;
-
-    if ( *hinted )
-    {
-      *x_scale = ADD_INT32( decoder->builder.glyph->x_scale, 32 ) / 64;
-      *y_scale = ADD_INT32( decoder->builder.glyph->y_scale, 32 ) / 64;
-    }
-    else
-    {
-      /* for unhinted outlines, `cff_slot_load' does the scaling, */
-      /* thus render at `unity' scale                             */
-
-      *x_scale = 0x0400;   /* 1/64 as 16.16 */
-      *y_scale = 0x0400;
-    }
-  }
-
-
-  /* get units per em from `FT_Face' */
-  /* TODO: should handle font matrix concatenation? */
-  static FT_UShort
-  cf2_getUnitsPerEm( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->builder.face );
-    FT_ASSERT( decoder->builder.face->root.units_per_EM );
-
-    return decoder->builder.face->root.units_per_EM;
-  }
-
-
-  /* Main entry point: Render one glyph. */
-  FT_LOCAL_DEF( FT_Error )
-  cf2_decoder_parse_charstrings( CFF_Decoder*  decoder,
-                                 FT_Byte*      charstring_base,
-                                 FT_ULong      charstring_len )
-  {
-    FT_Memory  memory;
-    FT_Error   error = FT_Err_Ok;
-    CF2_Font   font;
-
-
-    FT_ASSERT( decoder && decoder->cff );
-
-    memory = decoder->builder.memory;
-
-    /* CF2 data is saved here across glyphs */
-    font = (CF2_Font)decoder->cff->cf2_instance.data;
-
-    /* on first glyph, allocate instance structure */
-    if ( !decoder->cff->cf2_instance.data )
-    {
-      decoder->cff->cf2_instance.finalizer =
-        (FT_Generic_Finalizer)cf2_free_instance;
-
-      if ( FT_ALLOC( decoder->cff->cf2_instance.data,
-                     sizeof ( CF2_FontRec ) ) )
-        return FT_THROW( Out_Of_Memory );
-
-      font = (CF2_Font)decoder->cff->cf2_instance.data;
-
-      font->memory = memory;
-      font->cffload = (FT_Service_CFFLoad)decoder->cff->cffload;
-
-      /* initialize a client outline, to be shared by each glyph rendered */
-      cf2_outline_init( &font->outline, font->memory, &font->error );
-    }
-
-    /* save decoder; it is a stack variable and will be different on each */
-    /* call                                                               */
-    font->decoder         = decoder;
-    font->outline.decoder = decoder;
-
-    {
-      /* build parameters for Adobe engine */
-
-      CFF_Builder*  builder = &decoder->builder;
-      CFF_Driver    driver  = (CFF_Driver)FT_FACE_DRIVER( builder->face );
-
-      FT_Bool  no_stem_darkening_driver =
-                 driver->no_stem_darkening;
-      FT_Char  no_stem_darkening_font =
-                 builder->face->root.internal->no_stem_darkening;
-
-      /* local error */
-      FT_Error       error2 = FT_Err_Ok;
-      CF2_BufferRec  buf;
-      CF2_Matrix     transform;
-      CF2_F16Dot16   glyphWidth;
-
-      FT_Bool  hinted;
-      FT_Bool  scaled;
-
-
-      /* FreeType has already looked up the GID; convert to         */
-      /* `RegionBuffer', assuming that the input has been validated */
-      FT_ASSERT( charstring_base + charstring_len >= charstring_base );
-
-      FT_ZERO( &buf );
-      buf.start =
-      buf.ptr   = charstring_base;
-      buf.end   = charstring_base + charstring_len;
-
-      FT_ZERO( &transform );
-
-      cf2_getScaleAndHintFlag( decoder,
-                               &transform.a,
-                               &transform.d,
-                               &hinted,
-                               &scaled );
-
-      /* copy isCFF2 boolean from TT_Face to CF2_Font */
-      font->isCFF2 = builder->face->is_cff2;
-
-      font->renderingFlags = 0;
-      if ( hinted )
-        font->renderingFlags |= CF2_FlagsHinted;
-      if ( scaled && ( !no_stem_darkening_font        ||
-                       ( no_stem_darkening_font < 0 &&
-                         !no_stem_darkening_driver  ) ) )
-        font->renderingFlags |= CF2_FlagsDarkened;
-
-      font->darkenParams[0] = driver->darken_params[0];
-      font->darkenParams[1] = driver->darken_params[1];
-      font->darkenParams[2] = driver->darken_params[2];
-      font->darkenParams[3] = driver->darken_params[3];
-      font->darkenParams[4] = driver->darken_params[4];
-      font->darkenParams[5] = driver->darken_params[5];
-      font->darkenParams[6] = driver->darken_params[6];
-      font->darkenParams[7] = driver->darken_params[7];
-
-      /* now get an outline for this glyph;      */
-      /* also get units per em to validate scale */
-      font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder );
-
-      if ( scaled )
-      {
-        error2 = cf2_checkTransform( &transform, font->unitsPerEm );
-        if ( error2 )
-          return error2;
-      }
-
-      error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth );
-      if ( error2 )
-        return FT_ERR( Invalid_File_Format );
-
-      cf2_setGlyphWidth( &font->outline, glyphWidth );
-
-      return FT_Err_Ok;
-    }
-  }
-
-
-  /* get pointer to current FreeType subfont (based on current glyphID) */
-  FT_LOCAL_DEF( CFF_SubFont )
-  cf2_getSubfont( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    return decoder->current_subfont;
-  }
-
-
-  /* get pointer to VStore structure */
-  FT_LOCAL_DEF( CFF_VStore )
-  cf2_getVStore( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->cff );
-
-    return &decoder->cff->vstore;
-  }
-
-
-  /* get maxstack value from CFF2 Top DICT */
-  FT_LOCAL_DEF( FT_UInt )
-  cf2_getMaxstack( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->cff );
-
-    return decoder->cff->top_font.font_dict.maxstack;
-  }
-
-
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-  /* Get normalized design vector for current render request; */
-  /* return pointer and length.                               */
-  /*                                                          */
-  /* Note: Uses FT_Fixed not CF2_Fixed for the vector.        */
-  FT_LOCAL_DEF( FT_Error )
-  cf2_getNormalizedVector( CFF_Decoder*  decoder,
-                           CF2_UInt     *len,
-                           FT_Fixed*    *vec )
-  {
-    TT_Face  face;
-    FT_Service_MultiMasters  mm;
-
-    FT_ASSERT( decoder && decoder->builder.face );
-    FT_ASSERT( vec && len );
-    
-    face = decoder->builder.face;
-    mm = (FT_Service_MultiMasters)face->mm;
-    
-    return mm->get_var_blend( FT_FACE( face ), len, NULL, vec, NULL );
-  }
-#endif
-
-
-  /* get `y_ppem' from `CFF_Size' */
-  FT_LOCAL_DEF( CF2_Fixed )
-  cf2_getPpemY( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder                          &&
-               decoder->builder.face            &&
-               decoder->builder.face->root.size );
-
-    /*
-     * Note that `y_ppem' can be zero if there wasn't a call to
-     * `FT_Set_Char_Size' or something similar.  However, this isn't a
-     * problem since we come to this place in the code only if
-     * FT_LOAD_NO_SCALE is set (the other case gets caught by
-     * `cf2_checkTransform').  The ppem value is needed to compute the stem
-     * darkening, which is disabled for getting the unscaled outline.
-     *
-     */
-    return cf2_intToFixed(
-             decoder->builder.face->root.size->metrics.y_ppem );
-  }
-
-
-  /* get standard stem widths for the current subfont; */
-  /* FreeType stores these as integer font units       */
-  /* (note: variable names seem swapped)               */
-  FT_LOCAL_DEF( CF2_Fixed )
-  cf2_getStdVW( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    return cf2_intToFixed(
-             decoder->current_subfont->private_dict.standard_height );
-  }
-
-
-  FT_LOCAL_DEF( CF2_Fixed )
-  cf2_getStdHW( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    return cf2_intToFixed(
-             decoder->current_subfont->private_dict.standard_width );
-  }
-
-
-  /* note: FreeType stores 1000 times the actual value for `BlueScale' */
-  FT_LOCAL_DEF( void )
-  cf2_getBlueMetrics( CFF_Decoder*  decoder,
-                      CF2_Fixed*    blueScale,
-                      CF2_Fixed*    blueShift,
-                      CF2_Fixed*    blueFuzz )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    *blueScale = FT_DivFix(
-                   decoder->current_subfont->private_dict.blue_scale,
-                   cf2_intToFixed( 1000 ) );
-    *blueShift = cf2_intToFixed(
-                   decoder->current_subfont->private_dict.blue_shift );
-    *blueFuzz  = cf2_intToFixed(
-                   decoder->current_subfont->private_dict.blue_fuzz );
-  }
-
-
-  /* get blue values counts and arrays; the FreeType parser has validated */
-  /* the counts and verified that each is an even number                  */
-  FT_LOCAL_DEF( void )
-  cf2_getBlueValues( CFF_Decoder*  decoder,
-                     size_t*       count,
-                     FT_Pos*      *data )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    *count = decoder->current_subfont->private_dict.num_blue_values;
-    *data  = (FT_Pos*)
-               &decoder->current_subfont->private_dict.blue_values;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_getOtherBlues( CFF_Decoder*  decoder,
-                     size_t*       count,
-                     FT_Pos*      *data )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    *count = decoder->current_subfont->private_dict.num_other_blues;
-    *data  = (FT_Pos*)
-               &decoder->current_subfont->private_dict.other_blues;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_getFamilyBlues( CFF_Decoder*  decoder,
-                      size_t*       count,
-                      FT_Pos*      *data )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    *count = decoder->current_subfont->private_dict.num_family_blues;
-    *data  = (FT_Pos*)
-               &decoder->current_subfont->private_dict.family_blues;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_getFamilyOtherBlues( CFF_Decoder*  decoder,
-                           size_t*       count,
-                           FT_Pos*      *data )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    *count = decoder->current_subfont->private_dict.num_family_other_blues;
-    *data  = (FT_Pos*)
-               &decoder->current_subfont->private_dict.family_other_blues;
-  }
-
-
-  FT_LOCAL_DEF( CF2_Int )
-  cf2_getLanguageGroup( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    return decoder->current_subfont->private_dict.language_group;
-  }
-
-
-  /* convert unbiased subroutine index to `CF2_Buffer' and */
-  /* return 0 on success                                   */
-  FT_LOCAL_DEF( CF2_Int )
-  cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
-                              CF2_Int       subrNum,
-                              CF2_Buffer    buf )
-  {
-    CF2_UInt  idx;
-
-
-    FT_ASSERT( decoder );
-
-    FT_ZERO( buf );
-
-    idx = (CF2_UInt)( subrNum + decoder->globals_bias );
-    if ( idx >= decoder->num_globals )
-      return TRUE;     /* error */
-
-    FT_ASSERT( decoder->globals );
-
-    buf->start =
-    buf->ptr   = decoder->globals[idx];
-    buf->end   = decoder->globals[idx + 1];
-
-    return FALSE;      /* success */
-  }
-
-
-  /* convert AdobeStandardEncoding code to CF2_Buffer; */
-  /* used for seac component                           */
-  FT_LOCAL_DEF( FT_Error )
-  cf2_getSeacComponent( CFF_Decoder*  decoder,
-                        CF2_Int       code,
-                        CF2_Buffer    buf )
-  {
-    CF2_Int   gid;
-    FT_Byte*  charstring;
-    FT_ULong  len;
-    FT_Error  error;
-
-
-    FT_ASSERT( decoder );
-
-    FT_ZERO( buf );
-
-#ifdef FT_CONFIG_OPTION_INCREMENTAL
-    /* Incremental fonts don't necessarily have valid charsets.        */
-    /* They use the character code, not the glyph index, in this case. */
-    if ( decoder->builder.face->root.internal->incremental_interface )
-      gid = code;
-    else
-#endif /* FT_CONFIG_OPTION_INCREMENTAL */
-    {
-      gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code );
-      if ( gid < 0 )
-        return FT_THROW( Invalid_Glyph_Format );
-    }
-
-    error = decoder->get_glyph_callback( decoder->builder.face,
-                                         (CF2_UInt)gid,
-                                         &charstring,
-                                         &len );
-    /* TODO: for now, just pass the FreeType error through */
-    if ( error )
-      return error;
-
-    /* assume input has been validated */
-    FT_ASSERT( charstring + len >= charstring );
-
-    buf->start = charstring;
-    buf->end   = charstring + len;
-    buf->ptr   = buf->start;
-
-    return FT_Err_Ok;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_freeSeacComponent( CFF_Decoder*  decoder,
-                         CF2_Buffer    buf )
-  {
-    FT_ASSERT( decoder );
-
-    decoder->free_glyph_callback( decoder->builder.face,
-                                  (FT_Byte**)&buf->start,
-                                  (FT_ULong)( buf->end - buf->start ) );
-  }
-
-
-  FT_LOCAL_DEF( CF2_Int )
-  cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
-                             CF2_Int       subrNum,
-                             CF2_Buffer    buf )
-  {
-    CF2_UInt  idx;
-
-
-    FT_ASSERT( decoder );
-
-    FT_ZERO( buf );
-
-    idx = (CF2_UInt)( subrNum + decoder->locals_bias );
-    if ( idx >= decoder->num_locals )
-      return TRUE;     /* error */
-
-    FT_ASSERT( decoder->locals );
-
-    buf->start =
-    buf->ptr   = decoder->locals[idx];
-    buf->end   = decoder->locals[idx + 1];
-
-    return FALSE;      /* success */
-  }
-
-
-  FT_LOCAL_DEF( CF2_Fixed )
-  cf2_getDefaultWidthX( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    return cf2_intToFixed(
-             decoder->current_subfont->private_dict.default_width );
-  }
-
-
-  FT_LOCAL_DEF( CF2_Fixed )
-  cf2_getNominalWidthX( CFF_Decoder*  decoder )
-  {
-    FT_ASSERT( decoder && decoder->current_subfont );
-
-    return cf2_intToFixed(
-             decoder->current_subfont->private_dict.nominal_width );
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_outline_reset( CF2_Outline  outline )
-  {
-    CFF_Decoder*  decoder = outline->decoder;
-
-
-    FT_ASSERT( decoder );
-
-    outline->root.windingMomentum = 0;
-
-    FT_GlyphLoader_Rewind( decoder->builder.loader );
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_outline_close( CF2_Outline  outline )
-  {
-    CFF_Decoder*  decoder = outline->decoder;
-
-
-    FT_ASSERT( decoder );
-
-    cff_builder_close_contour( &decoder->builder );
-
-    FT_GlyphLoader_Add( decoder->builder.loader );
-  }
-
-
-/* END */
--- a/src/psaux/cf2ft.h
+++ /dev/null
@@ -1,159 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2ft.h                                                                */
-/*                                                                         */
-/*    FreeType Glue Component to Adobe's Interpreter (specification).      */
-/*                                                                         */
-/*  Copyright 2013 Adobe Systems Incorporated.                             */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2FT_H_
-#define CF2FT_H_
-
-
-#include "cf2types.h"
-
-
-  /* TODO: disable asserts for now */
-#define CF2_NDEBUG
-
-
-#include FT_SYSTEM_H
-
-#include "cf2glue.h"
-#include FT_INTERNAL_POSTSCRIPT_AUX_H    /* for CFF_Decoder */
-
-
-FT_BEGIN_HEADER
-
-
-  FT_LOCAL( FT_Error )
-  cf2_decoder_parse_charstrings( CFF_Decoder*  decoder,
-                                 FT_Byte*      charstring_base,
-                                 FT_ULong      charstring_len );
-
-  FT_LOCAL( CFF_SubFont )
-  cf2_getSubfont( CFF_Decoder*  decoder );
-
-  FT_LOCAL( CFF_VStore )
-  cf2_getVStore( CFF_Decoder*  decoder );
-
-  FT_LOCAL( FT_UInt )
-  cf2_getMaxstack( CFF_Decoder*  decoder );
-
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-  FT_LOCAL( FT_Error )
-  cf2_getNormalizedVector( CFF_Decoder*  decoder,
-                           CF2_UInt     *len,
-                           FT_Fixed*    *vec );
-#endif
-
-  FT_LOCAL( CF2_Fixed )
-  cf2_getPpemY( CFF_Decoder*  decoder );
-  FT_LOCAL( CF2_Fixed )
-  cf2_getStdVW( CFF_Decoder*  decoder );
-  FT_LOCAL( CF2_Fixed )
-  cf2_getStdHW( CFF_Decoder*  decoder );
-
-  FT_LOCAL( void )
-  cf2_getBlueMetrics( CFF_Decoder*  decoder,
-                      CF2_Fixed*    blueScale,
-                      CF2_Fixed*    blueShift,
-                      CF2_Fixed*    blueFuzz );
-  FT_LOCAL( void )
-  cf2_getBlueValues( CFF_Decoder*  decoder,
-                     size_t*       count,
-                     FT_Pos*      *data );
-  FT_LOCAL( void )
-  cf2_getOtherBlues( CFF_Decoder*  decoder,
-                     size_t*       count,
-                     FT_Pos*      *data );
-  FT_LOCAL( void )
-  cf2_getFamilyBlues( CFF_Decoder*  decoder,
-                      size_t*       count,
-                      FT_Pos*      *data );
-  FT_LOCAL( void )
-  cf2_getFamilyOtherBlues( CFF_Decoder*  decoder,
-                           size_t*       count,
-                           FT_Pos*      *data );
-
-  FT_LOCAL( CF2_Int )
-  cf2_getLanguageGroup( CFF_Decoder*  decoder );
-
-  FT_LOCAL( CF2_Int )
-  cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
-                              CF2_Int       subrNum,
-                              CF2_Buffer    buf );
-  FT_LOCAL( FT_Error )
-  cf2_getSeacComponent( CFF_Decoder*  decoder,
-                        CF2_Int       code,
-                        CF2_Buffer    buf );
-  FT_LOCAL( void )
-  cf2_freeSeacComponent( CFF_Decoder*  decoder,
-                         CF2_Buffer    buf );
-  FT_LOCAL( CF2_Int )
-  cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
-                             CF2_Int       subrNum,
-                             CF2_Buffer    buf );
-
-  FT_LOCAL( CF2_Fixed )
-  cf2_getDefaultWidthX( CFF_Decoder*  decoder );
-  FT_LOCAL( CF2_Fixed )
-  cf2_getNominalWidthX( CFF_Decoder*  decoder );
-
-
-  /*
-   * FreeType client outline
-   *
-   * process output from the charstring interpreter
-   */
-  typedef struct  CF2_OutlineRec_
-  {
-    CF2_OutlineCallbacksRec  root;        /* base class must be first */
-    CFF_Decoder*             decoder;
-
-  } CF2_OutlineRec, *CF2_Outline;
-
-
-  FT_LOCAL( void )
-  cf2_outline_reset( CF2_Outline  outline );
-  FT_LOCAL( void )
-  cf2_outline_close( CF2_Outline  outline );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2FT_H_ */
-
-
-/* END */
--- a/src/psaux/cf2glue.h
+++ /dev/null
@@ -1,144 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2glue.h                                                              */
-/*                                                                         */
-/*    Adobe's code for shared stuff (specification only).                  */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2GLUE_H_
-#define CF2GLUE_H_
-
-
-/* common includes for other modules */
-#include "cf2error.h"
-#include "cf2fixed.h"
-#include "cf2arrst.h"
-#include "cf2read.h"
-
-
-FT_BEGIN_HEADER
-
-
-  /* rendering parameters */
-
-  /* apply hints to rendered glyphs */
-#define CF2_FlagsHinted    1
-  /* for testing */
-#define CF2_FlagsDarkened  2
-
-  /* type for holding the flags */
-  typedef CF2_Int  CF2_RenderingFlags;
-
-
-  /* elements of a glyph outline */
-  typedef enum  CF2_PathOp_
-  {
-    CF2_PathOpMoveTo = 1,     /* change the current point */
-    CF2_PathOpLineTo = 2,     /* line                     */
-    CF2_PathOpQuadTo = 3,     /* quadratic curve          */
-    CF2_PathOpCubeTo = 4      /* cubic curve              */
-
-  } CF2_PathOp;
-
-
-  /* a matrix of fixed point values */
-  typedef struct  CF2_Matrix_
-  {
-    CF2_F16Dot16  a;
-    CF2_F16Dot16  b;
-    CF2_F16Dot16  c;
-    CF2_F16Dot16  d;
-    CF2_F16Dot16  tx;
-    CF2_F16Dot16  ty;
-
-  } CF2_Matrix;
-
-
-  /* these typedefs are needed by more than one header file */
-  /* and gcc compiler doesn't allow redefinition            */
-  typedef struct CF2_FontRec_  CF2_FontRec, *CF2_Font;
-  typedef struct CF2_HintRec_  CF2_HintRec, *CF2_Hint;
-
-
-  /* A common structure for all callback parameters.                       */
-  /*                                                                       */
-  /* Some members may be unused.  For example, `pt0' is not used for       */
-  /* `moveTo' and `pt3' is not used for `quadTo'.  The initial point `pt0' */
-  /* is included for each path element for generality; curve conversions   */
-  /* need it.  The `op' parameter allows one function to handle multiple   */
-  /* element types.                                                        */
-
-  typedef struct  CF2_CallbackParamsRec_
-  {
-    FT_Vector  pt0;
-    FT_Vector  pt1;
-    FT_Vector  pt2;
-    FT_Vector  pt3;
-
-    CF2_Int  op;
-
-  } CF2_CallbackParamsRec, *CF2_CallbackParams;
-
-
-  /* forward reference */
-  typedef struct CF2_OutlineCallbacksRec_  CF2_OutlineCallbacksRec,
-                                           *CF2_OutlineCallbacks;
-
-  /* callback function pointers */
-  typedef void
-  (*CF2_Callback_Type)( CF2_OutlineCallbacks      callbacks,
-                        const CF2_CallbackParams  params );
-
-
-  struct  CF2_OutlineCallbacksRec_
-  {
-    CF2_Callback_Type  moveTo;
-    CF2_Callback_Type  lineTo;
-    CF2_Callback_Type  quadTo;
-    CF2_Callback_Type  cubeTo;
-
-    CF2_Int  windingMomentum;    /* for winding order detection */
-
-    FT_Memory  memory;
-    FT_Error*  error;
-  };
-
-
-FT_END_HEADER
-
-
-#endif /* CF2GLUE_H_ */
-
-
-/* END */
--- a/src/psaux/cf2hints.c
+++ /dev/null
@@ -1,1875 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2hints.c                                                             */
-/*                                                                         */
-/*    Adobe's code for handling CFF hints (body).                          */
-/*                                                                         */
-/*  Copyright 2007-2014 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include FT_INTERNAL_DEBUG_H
-
-#include "cf2glue.h"
-#include "cf2font.h"
-#include "cf2hints.h"
-#include "cf2intrp.h"
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* 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_cf2hints
-
-
-  typedef struct  CF2_HintMoveRec_
-  {
-    size_t     j;          /* index of upper hint map edge   */
-    CF2_Fixed  moveUp;     /* adjustment to optimum position */
-
-  } CF2_HintMoveRec, *CF2_HintMove;
-
-
-  /* Compute angular momentum for winding order detection.  It is called */
-  /* for all lines and curves, but not necessarily in element order.     */
-  static CF2_Int
-  cf2_getWindingMomentum( CF2_Fixed  x1,
-                          CF2_Fixed  y1,
-                          CF2_Fixed  x2,
-                          CF2_Fixed  y2 )
-  {
-    /* cross product of pt1 position from origin with pt2 position from  */
-    /* pt1; we reduce the precision so that the result fits into 32 bits */
-
-    return ( x1 >> 16 ) * ( SUB_INT32( y2, y1 ) >> 16 ) -
-           ( y1 >> 16 ) * ( SUB_INT32( x2, x1 ) >> 16 );
-  }
-
-
-  /*
-   * Construct from a StemHint; this is used as a parameter to
-   * `cf2_blues_capture'.
-   * `hintOrigin' is the character space displacement of a seac accent.
-   * Adjust stem hint for darkening here.
-   *
-   */
-  static void
-  cf2_hint_init( CF2_Hint            hint,
-                 const CF2_ArrStack  stemHintArray,
-                 size_t              indexStemHint,
-                 const CF2_Font      font,
-                 CF2_Fixed           hintOrigin,
-                 CF2_Fixed           scale,
-                 FT_Bool             bottom )
-  {
-    CF2_Fixed               width;
-    const CF2_StemHintRec*  stemHint;
-
-
-    FT_ZERO( hint );
-
-    stemHint = (const CF2_StemHintRec*)cf2_arrstack_getPointer(
-                                         stemHintArray,
-                                         indexStemHint );
-
-    width = SUB_INT32( stemHint->max, stemHint->min );
-
-    if ( width == cf2_intToFixed( -21 ) )
-    {
-      /* ghost bottom */
-
-      if ( bottom )
-      {
-        hint->csCoord = stemHint->max;
-        hint->flags   = CF2_GhostBottom;
-      }
-      else
-        hint->flags = 0;
-    }
-
-    else if ( width == cf2_intToFixed( -20 ) )
-    {
-      /* ghost top */
-
-      if ( bottom )
-        hint->flags = 0;
-      else
-      {
-        hint->csCoord = stemHint->min;
-        hint->flags   = CF2_GhostTop;
-      }
-    }
-
-    else if ( width < 0 )
-    {
-      /* inverted pair */
-
-      /*
-       * Hints with negative widths were produced by an early version of a
-       * non-Adobe font tool.  The Type 2 spec allows edge (ghost) hints
-       * with negative widths, but says
-       *
-       *   All other negative widths have undefined meaning.
-       *
-       * CoolType has a silent workaround that negates the hint width; for
-       * permissive mode, we do the same here.
-       *
-       * Note: Such fonts cannot use ghost hints, but should otherwise work.
-       * Note: Some poor hints in our faux fonts can produce negative
-       *       widths at some blends.  For example, see a light weight of
-       *       `u' in ASerifMM.
-       *
-       */
-      if ( bottom )
-      {
-        hint->csCoord = stemHint->max;
-        hint->flags   = CF2_PairBottom;
-      }
-      else
-      {
-        hint->csCoord = stemHint->min;
-        hint->flags   = CF2_PairTop;
-      }
-    }
-
-    else
-    {
-      /* normal pair */
-
-      if ( bottom )
-      {
-        hint->csCoord = stemHint->min;
-        hint->flags   = CF2_PairBottom;
-      }
-      else
-      {
-        hint->csCoord = stemHint->max;
-        hint->flags   = CF2_PairTop;
-      }
-    }
-
-    /* Now that ghost hints have been detected, adjust this edge for      */
-    /* darkening.  Bottoms are not changed; tops are incremented by twice */
-    /* `darkenY'.                                                         */
-    if ( cf2_hint_isTop( hint ) )
-      hint->csCoord = ADD_INT32( hint->csCoord, 2 * font->darkenY );
-
-    hint->csCoord = ADD_INT32( hint->csCoord, hintOrigin );
-    hint->scale   = scale;
-    hint->index   = indexStemHint;   /* index in original stem hint array */
-
-    /* if original stem hint has been used, use the same position */
-    if ( hint->flags != 0 && stemHint->used )
-    {
-      if ( cf2_hint_isTop( hint ) )
-        hint->dsCoord = stemHint->maxDS;
-      else
-        hint->dsCoord = stemHint->minDS;
-
-      cf2_hint_lock( hint );
-    }
-    else
-      hint->dsCoord = FT_MulFix( hint->csCoord, scale );
-  }
-
-
-  /* initialize an invalid hint map element */
-  static void
-  cf2_hint_initZero( CF2_Hint  hint )
-  {
-    FT_ZERO( hint );
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  cf2_hint_isValid( const CF2_Hint  hint )
-  {
-    return (FT_Bool)( hint->flags != 0 );
-  }
-
-
-  static FT_Bool
-  cf2_hint_isPair( const CF2_Hint  hint )
-  {
-    return (FT_Bool)( ( hint->flags                      &
-                        ( CF2_PairBottom | CF2_PairTop ) ) != 0 );
-  }
-
-
-  static FT_Bool
-  cf2_hint_isPairTop( const CF2_Hint  hint )
-  {
-    return (FT_Bool)( ( hint->flags & CF2_PairTop ) != 0 );
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  cf2_hint_isTop( const CF2_Hint  hint )
-  {
-    return (FT_Bool)( ( hint->flags                    &
-                        ( CF2_PairTop | CF2_GhostTop ) ) != 0 );
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  cf2_hint_isBottom( const CF2_Hint  hint )
-  {
-    return (FT_Bool)( ( hint->flags                          &
-                        ( CF2_PairBottom | CF2_GhostBottom ) ) != 0 );
-  }
-
-
-  static FT_Bool
-  cf2_hint_isLocked( const CF2_Hint  hint )
-  {
-    return (FT_Bool)( ( hint->flags & CF2_Locked ) != 0 );
-  }
-
-
-  static FT_Bool
-  cf2_hint_isSynthetic( const CF2_Hint  hint )
-  {
-    return (FT_Bool)( ( hint->flags & CF2_Synthetic ) != 0 );
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_hint_lock( CF2_Hint  hint )
-  {
-    hint->flags |= CF2_Locked;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_hintmap_init( CF2_HintMap   hintmap,
-                    CF2_Font      font,
-                    CF2_HintMap   initialMap,
-                    CF2_ArrStack  hintMoves,
-                    CF2_Fixed     scale )
-  {
-    FT_ZERO( hintmap );
-
-    /* copy parameters from font instance */
-    hintmap->hinted         = font->hinted;
-    hintmap->scale          = scale;
-    hintmap->font           = font;
-    hintmap->initialHintMap = initialMap;
-    /* will clear in `cf2_hintmap_adjustHints' */
-    hintmap->hintMoves      = hintMoves;
-  }
-
-
-  static FT_Bool
-  cf2_hintmap_isValid( const CF2_HintMap  hintmap )
-  {
-    return hintmap->isValid;
-  }
-
-
-  /* transform character space coordinate to device space using hint map */
-  static CF2_Fixed
-  cf2_hintmap_map( CF2_HintMap  hintmap,
-                   CF2_Fixed    csCoord )
-  {
-    if ( hintmap->count == 0 || ! hintmap->hinted )
-    {
-      /* there are no hints; use uniform scale and zero offset */
-      return FT_MulFix( csCoord, hintmap->scale );
-    }
-    else
-    {
-      /* start linear search from last hit */
-      CF2_UInt  i = hintmap->lastIndex;
-
-
-      FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
-
-      /* search up */
-      while ( i < hintmap->count - 1                  &&
-              csCoord >= hintmap->edge[i + 1].csCoord )
-        i += 1;
-
-      /* search down */
-      while ( i > 0 && csCoord < hintmap->edge[i].csCoord )
-        i -= 1;
-
-      hintmap->lastIndex = i;
-
-      if ( i == 0 && csCoord < hintmap->edge[0].csCoord )
-      {
-        /* special case for points below first edge: use uniform scale */
-        return ADD_INT32( FT_MulFix( SUB_INT32( csCoord,
-                                                hintmap->edge[0].csCoord ),
-                                     hintmap->scale ),
-                          hintmap->edge[0].dsCoord );
-      }
-      else
-      {
-        /*
-         * Note: entries with duplicate csCoord are allowed.
-         * Use edge[i], the highest entry where csCoord >= entry[i].csCoord
-         */
-        return ADD_INT32( FT_MulFix( SUB_INT32( csCoord,
-                                                hintmap->edge[i].csCoord ),
-                                     hintmap->edge[i].scale ),
-                          hintmap->edge[i].dsCoord );
-      }
-    }
-  }
-
-
-  /*
-   * This hinting policy moves a hint pair in device space so that one of
-   * its two edges is on a device pixel boundary (its fractional part is
-   * zero).  `cf2_hintmap_insertHint' guarantees no overlap in CS
-   * space.  Ensure here that there is no overlap in DS.
-   *
-   * In the first pass, edges are adjusted relative to adjacent hints.
-   * Those that are below have already been adjusted.  Those that are
-   * above have not yet been adjusted.  If a hint above blocks an
-   * adjustment to an optimal position, we will try again in a second
-   * pass.  The second pass is top-down.
-   *
-   */
-
-  static void
-  cf2_hintmap_adjustHints( CF2_HintMap  hintmap )
-  {
-    size_t  i, j;
-
-
-    cf2_arrstack_clear( hintmap->hintMoves );      /* working storage */
-
-    /*
-     * First pass is bottom-up (font hint order) without look-ahead.
-     * Locked edges are already adjusted.
-     * Unlocked edges begin with dsCoord from `initialHintMap'.
-     * Save edges that are not optimally adjusted in `hintMoves' array,
-     * and process them in second pass.
-     */
-
-    for ( i = 0; i < hintmap->count; i++ )
-    {
-      FT_Bool  isPair = cf2_hint_isPair( &hintmap->edge[i] );
-
-
-      /* index of upper edge (same value for ghost hint) */
-      j = isPair ? i + 1 : i;
-
-      FT_ASSERT( j < hintmap->count );
-      FT_ASSERT( cf2_hint_isValid( &hintmap->edge[i] ) );
-      FT_ASSERT( cf2_hint_isValid( &hintmap->edge[j] ) );
-      FT_ASSERT( cf2_hint_isLocked( &hintmap->edge[i] ) ==
-                   cf2_hint_isLocked( &hintmap->edge[j] ) );
-
-      if ( !cf2_hint_isLocked( &hintmap->edge[i] ) )
-      {
-        /* hint edge is not locked, we can adjust it */
-        CF2_Fixed  fracDown = cf2_fixedFraction( hintmap->edge[i].dsCoord );
-        CF2_Fixed  fracUp   = cf2_fixedFraction( hintmap->edge[j].dsCoord );
-
-        /* calculate all four possibilities; moves down are negative */
-        CF2_Fixed  downMoveDown = 0 - fracDown;
-        CF2_Fixed  upMoveDown   = 0 - fracUp;
-        CF2_Fixed  downMoveUp   = ( fracDown == 0 )
-                                    ? 0
-                                    : cf2_intToFixed( 1 ) - fracDown;
-        CF2_Fixed  upMoveUp     = ( fracUp == 0 )
-                                    ? 0
-                                    : cf2_intToFixed( 1 ) - fracUp;
-
-        /* smallest move up */
-        CF2_Fixed  moveUp   = FT_MIN( downMoveUp, upMoveUp );
-        /* smallest move down */
-        CF2_Fixed  moveDown = FT_MAX( downMoveDown, upMoveDown );
-
-        /* final amount to move edge or edge pair */
-        CF2_Fixed  move;
-
-        CF2_Fixed  downMinCounter = CF2_MIN_COUNTER;
-        CF2_Fixed  upMinCounter   = CF2_MIN_COUNTER;
-        FT_Bool    saveEdge       = FALSE;
-
-
-        /* minimum counter constraint doesn't apply when adjacent edges */
-        /* are synthetic                                                */
-        /* TODO: doesn't seem a big effect; for now, reduce the code    */
-#if 0
-        if ( i == 0                                        ||
-             cf2_hint_isSynthetic( &hintmap->edge[i - 1] ) )
-          downMinCounter = 0;
-
-        if ( j >= hintmap->count - 1                       ||
-             cf2_hint_isSynthetic( &hintmap->edge[j + 1] ) )
-          upMinCounter = 0;
-#endif
-
-        /* is there room to move up?                                    */
-        /* there is if we are at top of array or the next edge is at or */
-        /* beyond proposed move up?                                     */
-        if ( j >= hintmap->count - 1                ||
-             hintmap->edge[j + 1].dsCoord >=
-               ADD_INT32( hintmap->edge[j].dsCoord,
-                          moveUp + upMinCounter )   )
-        {
-          /* there is room to move up; is there also room to move down? */
-          if ( i == 0                                   ||
-               hintmap->edge[i - 1].dsCoord <=
-                 ADD_INT32( hintmap->edge[i].dsCoord,
-                            moveDown - downMinCounter ) )
-          {
-            /* move smaller absolute amount */
-            move = ( -moveDown < moveUp ) ? moveDown : moveUp;  /* optimum */
-          }
-          else
-            move = moveUp;
-        }
-        else
-        {
-          /* is there room to move down? */
-          if ( i == 0                                   ||
-               hintmap->edge[i - 1].dsCoord <=
-                 ADD_INT32( hintmap->edge[i].dsCoord,
-                            moveDown - downMinCounter ) )
-          {
-            move     = moveDown;
-            /* true if non-optimum move */
-            saveEdge = (FT_Bool)( moveUp < -moveDown );
-          }
-          else
-          {
-            /* no room to move either way without overlapping or reducing */
-            /* the counter too much                                       */
-            move     = 0;
-            saveEdge = TRUE;
-          }
-        }
-
-        /* Identify non-moves and moves down that aren't optimal, and save */
-        /* them for second pass.                                           */
-        /* Do this only if there is an unlocked edge above (which could    */
-        /* possibly move).                                                 */
-        if ( saveEdge                                    &&
-             j < hintmap->count - 1                      &&
-             !cf2_hint_isLocked( &hintmap->edge[j + 1] ) )
-        {
-          CF2_HintMoveRec  savedMove;
-
-
-          savedMove.j      = j;
-          /* desired adjustment in second pass */
-          savedMove.moveUp = moveUp - move;
-
-          cf2_arrstack_push( hintmap->hintMoves, &savedMove );
-        }
-
-        /* move the edge(s) */
-        hintmap->edge[i].dsCoord = ADD_INT32( hintmap->edge[i].dsCoord,
-                                              move );
-        if ( isPair )
-          hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord,
-                                                move );
-      }
-
-      /* assert there are no overlaps in device space */
-      FT_ASSERT( i == 0                                                   ||
-                 hintmap->edge[i - 1].dsCoord <= hintmap->edge[i].dsCoord );
-      FT_ASSERT( i < j                                                ||
-                 hintmap->edge[i].dsCoord <= hintmap->edge[j].dsCoord );
-
-      /* adjust the scales, avoiding divide by zero */
-      if ( i > 0 )
-      {
-        if ( hintmap->edge[i].csCoord != hintmap->edge[i - 1].csCoord )
-          hintmap->edge[i - 1].scale =
-            FT_DivFix( SUB_INT32( hintmap->edge[i].dsCoord,
-                                  hintmap->edge[i - 1].dsCoord ),
-                       SUB_INT32( hintmap->edge[i].csCoord,
-                                  hintmap->edge[i - 1].csCoord ) );
-      }
-
-      if ( isPair )
-      {
-        if ( hintmap->edge[j].csCoord != hintmap->edge[j - 1].csCoord )
-          hintmap->edge[j - 1].scale =
-            FT_DivFix( SUB_INT32( hintmap->edge[j].dsCoord,
-                                  hintmap->edge[j - 1].dsCoord ),
-                       SUB_INT32( hintmap->edge[j].csCoord,
-                                  hintmap->edge[j - 1].csCoord ) );
-
-        i += 1;     /* skip upper edge on next loop */
-      }
-    }
-
-    /* second pass tries to move non-optimal hints up, in case there is */
-    /* room now                                                         */
-    for ( i = cf2_arrstack_size( hintmap->hintMoves ); i > 0; i-- )
-    {
-      CF2_HintMove  hintMove = (CF2_HintMove)
-                      cf2_arrstack_getPointer( hintmap->hintMoves, i - 1 );
-
-
-      j = hintMove->j;
-
-      /* this was tested before the push, above */
-      FT_ASSERT( j < hintmap->count - 1 );
-
-      /* is there room to move up? */
-      if ( hintmap->edge[j + 1].dsCoord >=
-             ADD_INT32( hintmap->edge[j].dsCoord,
-                        hintMove->moveUp + CF2_MIN_COUNTER ) )
-      {
-        /* there is more room now, move edge up */
-        hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord,
-                                              hintMove->moveUp );
-
-        if ( cf2_hint_isPair( &hintmap->edge[j] ) )
-        {
-          FT_ASSERT( j > 0 );
-          hintmap->edge[j - 1].dsCoord =
-            ADD_INT32( hintmap->edge[j - 1].dsCoord, hintMove->moveUp );
-        }
-      }
-    }
-  }
-
-
-  /* insert hint edges into map, sorted by csCoord */
-  static void
-  cf2_hintmap_insertHint( CF2_HintMap  hintmap,
-                          CF2_Hint     bottomHintEdge,
-                          CF2_Hint     topHintEdge )
-  {
-    CF2_UInt  indexInsert;
-
-    /* set default values, then check for edge hints */
-    FT_Bool   isPair         = TRUE;
-    CF2_Hint  firstHintEdge  = bottomHintEdge;
-    CF2_Hint  secondHintEdge = topHintEdge;
-
-
-    /* one or none of the input params may be invalid when dealing with */
-    /* edge hints; at least one edge must be valid                      */
-    FT_ASSERT( cf2_hint_isValid( bottomHintEdge ) ||
-               cf2_hint_isValid( topHintEdge )    );
-
-    /* determine how many and which edges to insert */
-    if ( !cf2_hint_isValid( bottomHintEdge ) )
-    {
-      /* insert only the top edge */
-      firstHintEdge = topHintEdge;
-      isPair        = FALSE;
-    }
-    else if ( !cf2_hint_isValid( topHintEdge ) )
-    {
-      /* insert only the bottom edge */
-      isPair = FALSE;
-    }
-
-    /* paired edges must be in proper order */
-    if ( isPair                                         &&
-         topHintEdge->csCoord < bottomHintEdge->csCoord )
-      return;
-
-    /* linear search to find index value of insertion point */
-    indexInsert = 0;
-    for ( ; indexInsert < hintmap->count; indexInsert++ )
-    {
-      if ( hintmap->edge[indexInsert].csCoord >= firstHintEdge->csCoord )
-        break;
-    }
-
-    /*
-     * Discard any hints that overlap in character space.  Most often, this
-     * is while building the initial map, where captured hints from all
-     * zones are combined.  Define overlap to include hints that `touch'
-     * (overlap zero).  Hiragino Sans/Gothic fonts have numerous hints that
-     * touch.  Some fonts have non-ideographic glyphs that overlap our
-     * synthetic hints.
-     *
-     * Overlap also occurs when darkening stem hints that are close.
-     *
-     */
-    if ( indexInsert < hintmap->count )
-    {
-      /* we are inserting before an existing edge:    */
-      /* verify that an existing edge is not the same */
-      if ( hintmap->edge[indexInsert].csCoord == firstHintEdge->csCoord )
-        return; /* ignore overlapping stem hint */
-
-      /* verify that a new pair does not straddle the next edge */
-      if ( isPair                                                        &&
-           hintmap->edge[indexInsert].csCoord <= secondHintEdge->csCoord )
-        return; /* ignore overlapping stem hint */
-
-      /* verify that we are not inserting between paired edges */
-      if ( cf2_hint_isPairTop( &hintmap->edge[indexInsert] ) )
-        return; /* ignore overlapping stem hint */
-    }
-
-    /* recompute device space locations using initial hint map */
-    if ( cf2_hintmap_isValid( hintmap->initialHintMap ) &&
-         !cf2_hint_isLocked( firstHintEdge )            )
-    {
-      if ( isPair )
-      {
-        /* Use hint map to position the center of stem, and nominal scale */
-        /* to position the two edges.  This preserves the stem width.     */
-        CF2_Fixed  midpoint =
-                     cf2_hintmap_map(
-                       hintmap->initialHintMap,
-                       ADD_INT32( secondHintEdge->csCoord,
-                                  firstHintEdge->csCoord ) / 2 );
-        CF2_Fixed  halfWidth =
-                     FT_MulFix( SUB_INT32( secondHintEdge->csCoord,
-                                           firstHintEdge->csCoord ) / 2,
-                                hintmap->scale );
-
-
-        firstHintEdge->dsCoord  = SUB_INT32( midpoint, halfWidth );
-        secondHintEdge->dsCoord = ADD_INT32( midpoint, halfWidth );
-      }
-      else
-        firstHintEdge->dsCoord = cf2_hintmap_map( hintmap->initialHintMap,
-                                                  firstHintEdge->csCoord );
-    }
-
-    /*
-     * Discard any hints that overlap in device space; this can occur
-     * because locked hints have been moved to align with blue zones.
-     *
-     * TODO: Although we might correct this later during adjustment, we
-     * don't currently have a way to delete a conflicting hint once it has
-     * been inserted.  See v2.030 MinionPro-Regular, 12 ppem darkened,
-     * initial hint map for second path, glyph 945 (the perispomeni (tilde)
-     * in U+1F6E, Greek omega with psili and perispomeni).  Darkening is
-     * 25.  Pair 667,747 initially conflicts in design space with top edge
-     * 660.  This is because 667 maps to 7.87, and the top edge was
-     * captured by a zone at 8.0.  The pair is later successfully inserted
-     * in a zone without the top edge.  In this zone it is adjusted to 8.0,
-     * and no longer conflicts with the top edge in design space.  This
-     * means it can be included in yet a later zone which does have the top
-     * edge hint.  This produces a small mismatch between the first and
-     * last points of this path, even though the hint masks are the same.
-     * The density map difference is tiny (1/256).
-     *
-     */
-
-    if ( indexInsert > 0 )
-    {
-      /* we are inserting after an existing edge */
-      if ( firstHintEdge->dsCoord < hintmap->edge[indexInsert - 1].dsCoord )
-        return;
-    }
-
-    if ( indexInsert < hintmap->count )
-    {
-      /* we are inserting before an existing edge */
-      if ( isPair )
-      {
-        if ( secondHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord )
-          return;
-      }
-      else
-      {
-        if ( firstHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord )
-          return;
-      }
-    }
-
-    /* make room to insert */
-    {
-      CF2_UInt  iSrc = hintmap->count - 1;
-      CF2_UInt  iDst = isPair ? hintmap->count + 1 : hintmap->count;
-
-      CF2_UInt  count = hintmap->count - indexInsert;
-
-
-      if ( iDst >= CF2_MAX_HINT_EDGES )
-      {
-        FT_TRACE4(( "cf2_hintmap_insertHint: too many hintmaps\n" ));
-        return;
-      }
-
-      while ( count-- )
-        hintmap->edge[iDst--] = hintmap->edge[iSrc--];
-
-      /* insert first edge */
-      hintmap->edge[indexInsert] = *firstHintEdge;         /* copy struct */
-      hintmap->count            += 1;
-
-      if ( isPair )
-      {
-        /* insert second edge */
-        hintmap->edge[indexInsert + 1] = *secondHintEdge;  /* copy struct */
-        hintmap->count                += 1;
-      }
-    }
-
-    return;
-  }
-
-
-  /*
-   * Build a map from hints and mask.
-   *
-   * This function may recur one level if `hintmap->initialHintMap' is not yet
-   * valid.
-   * If `initialMap' is true, simply build initial map.
-   *
-   * Synthetic hints are used in two ways.  A hint at zero is inserted, if
-   * needed, in the initial hint map, to prevent translations from
-   * propagating across the origin.  If synthetic em box hints are enabled
-   * for ideographic dictionaries, then they are inserted in all hint
-   * maps, including the initial one.
-   *
-   */
-  FT_LOCAL_DEF( void )
-  cf2_hintmap_build( CF2_HintMap   hintmap,
-                     CF2_ArrStack  hStemHintArray,
-                     CF2_ArrStack  vStemHintArray,
-                     CF2_HintMask  hintMask,
-                     CF2_Fixed     hintOrigin,
-                     FT_Bool       initialMap )
-  {
-    FT_Byte*  maskPtr;
-
-    CF2_Font         font = hintmap->font;
-    CF2_HintMaskRec  tempHintMask;
-
-    size_t   bitCount, i;
-    FT_Byte  maskByte;
-
-
-    /* check whether initial map is constructed */
-    if ( !initialMap && !cf2_hintmap_isValid( hintmap->initialHintMap ) )
-    {
-      /* make recursive call with initialHintMap and temporary mask; */
-      /* temporary mask will get all bits set, below */
-      cf2_hintmask_init( &tempHintMask, hintMask->error );
-      cf2_hintmap_build( hintmap->initialHintMap,
-                         hStemHintArray,
-                         vStemHintArray,
-                         &tempHintMask,
-                         hintOrigin,
-                         TRUE );
-    }
-
-    if ( !cf2_hintmask_isValid( hintMask ) )
-    {
-      /* without a hint mask, assume all hints are active */
-      cf2_hintmask_setAll( hintMask,
-                           cf2_arrstack_size( hStemHintArray ) +
-                             cf2_arrstack_size( vStemHintArray ) );
-      if ( !cf2_hintmask_isValid( hintMask ) )
-        return;                   /* too many stem hints */
-    }
-
-    /* begin by clearing the map */
-    hintmap->count     = 0;
-    hintmap->lastIndex = 0;
-
-    /* make a copy of the hint mask so we can modify it */
-    tempHintMask = *hintMask;
-    maskPtr      = cf2_hintmask_getMaskPtr( &tempHintMask );
-
-    /* use the hStem hints only, which are first in the mask */
-    bitCount = cf2_arrstack_size( hStemHintArray );
-
-    /* Defense-in-depth.  Should never return here. */
-    if ( bitCount > hintMask->bitCount )
-      return;
-
-    /* synthetic embox hints get highest priority */
-    if ( font->blues.doEmBoxHints )
-    {
-      CF2_HintRec  dummy;
-
-
-      cf2_hint_initZero( &dummy );   /* invalid hint map element */
-
-      /* ghost bottom */
-      cf2_hintmap_insertHint( hintmap,
-                              &font->blues.emBoxBottomEdge,
-                              &dummy );
-      /* ghost top */
-      cf2_hintmap_insertHint( hintmap,
-                              &dummy,
-                              &font->blues.emBoxTopEdge );
-    }
-
-    /* insert hints captured by a blue zone or already locked (higher */
-    /* priority)                                                      */
-    for ( i = 0, maskByte = 0x80; i < bitCount; i++ )
-    {
-      if ( maskByte & *maskPtr )
-      {
-        /* expand StemHint into two `CF2_Hint' elements */
-        CF2_HintRec  bottomHintEdge, topHintEdge;
-
-
-        cf2_hint_init( &bottomHintEdge,
-                       hStemHintArray,
-                       i,
-                       font,
-                       hintOrigin,
-                       hintmap->scale,
-                       TRUE /* bottom */ );
-        cf2_hint_init( &topHintEdge,
-                       hStemHintArray,
-                       i,
-                       font,
-                       hintOrigin,
-                       hintmap->scale,
-                       FALSE /* top */ );
-
-        if ( cf2_hint_isLocked( &bottomHintEdge ) ||
-             cf2_hint_isLocked( &topHintEdge )    ||
-             cf2_blues_capture( &font->blues,
-                                &bottomHintEdge,
-                                &topHintEdge )   )
-        {
-          /* insert captured hint into map */
-          cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
-
-          *maskPtr &= ~maskByte;      /* turn off the bit for this hint */
-        }
-      }
-
-      if ( ( i & 7 ) == 7 )
-      {
-        /* move to next mask byte */
-        maskPtr++;
-        maskByte = 0x80;
-      }
-      else
-        maskByte >>= 1;
-    }
-
-    /* initial hint map includes only captured hints plus maybe one at 0 */
-
-    /*
-     * TODO: There is a problem here because we are trying to build a
-     *       single hint map containing all captured hints.  It is
-     *       possible for there to be conflicts between captured hints,
-     *       either because of darkening or because the hints are in
-     *       separate hint zones (we are ignoring hint zones for the
-     *       initial map).  An example of the latter is MinionPro-Regular
-     *       v2.030 glyph 883 (Greek Capital Alpha with Psili) at 15ppem.
-     *       A stem hint for the psili conflicts with the top edge hint
-     *       for the base character.  The stem hint gets priority because
-     *       of its sort order.  In glyph 884 (Greek Capital Alpha with
-     *       Psili and Oxia), the top of the base character gets a stem
-     *       hint, and the psili does not.  This creates different initial
-     *       maps for the two glyphs resulting in different renderings of
-     *       the base character.  Will probably defer this either as not
-     *       worth the cost or as a font bug.  I don't think there is any
-     *       good reason for an accent to be captured by an alignment
-     *       zone.  -darnold 2/12/10
-     */
-
-    if ( initialMap )
-    {
-      /* Apply a heuristic that inserts a point for (0,0), unless it's     */
-      /* already covered by a mapping.  This locks the baseline for glyphs */
-      /* that have no baseline hints.                                      */
-
-      if ( hintmap->count == 0                           ||
-           hintmap->edge[0].csCoord > 0                  ||
-           hintmap->edge[hintmap->count - 1].csCoord < 0 )
-      {
-        /* all edges are above 0 or all edges are below 0; */
-        /* construct a locked edge hint at 0               */
-
-        CF2_HintRec  edge, invalid;
-
-
-        cf2_hint_initZero( &edge );
-
-        edge.flags = CF2_GhostBottom |
-                     CF2_Locked      |
-                     CF2_Synthetic;
-        edge.scale = hintmap->scale;
-
-        cf2_hint_initZero( &invalid );
-        cf2_hintmap_insertHint( hintmap, &edge, &invalid );
-      }
-    }
-    else
-    {
-      /* insert remaining hints */
-
-      maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask );
-
-      for ( i = 0, maskByte = 0x80; i < bitCount; i++ )
-      {
-        if ( maskByte & *maskPtr )
-        {
-          CF2_HintRec  bottomHintEdge, topHintEdge;
-
-
-          cf2_hint_init( &bottomHintEdge,
-                         hStemHintArray,
-                         i,
-                         font,
-                         hintOrigin,
-                         hintmap->scale,
-                         TRUE /* bottom */ );
-          cf2_hint_init( &topHintEdge,
-                         hStemHintArray,
-                         i,
-                         font,
-                         hintOrigin,
-                         hintmap->scale,
-                         FALSE /* top */ );
-
-          cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
-        }
-
-        if ( ( i & 7 ) == 7 )
-        {
-          /* move to next mask byte */
-          maskPtr++;
-          maskByte = 0x80;
-        }
-        else
-          maskByte >>= 1;
-      }
-    }
-
-    /*
-     * Note: The following line is a convenient place to break when
-     *       debugging hinting.  Examine `hintmap->edge' for the list of
-     *       enabled hints, then step over the call to see the effect of
-     *       adjustment.  We stop here first on the recursive call that
-     *       creates the initial map, and then on each counter group and
-     *       hint zone.
-     */
-
-    /* adjust positions of hint edges that are not locked to blue zones */
-    cf2_hintmap_adjustHints( hintmap );
-
-    /* save the position of all hints that were used in this hint map; */
-    /* if we use them again, we'll locate them in the same position    */
-    if ( !initialMap )
-    {
-      for ( i = 0; i < hintmap->count; i++ )
-      {
-        if ( !cf2_hint_isSynthetic( &hintmap->edge[i] ) )
-        {
-          /* Note: include both valid and invalid edges            */
-          /* Note: top and bottom edges are copied back separately */
-          CF2_StemHint  stemhint = (CF2_StemHint)
-                          cf2_arrstack_getPointer( hStemHintArray,
-                                                   hintmap->edge[i].index );
-
-
-          if ( cf2_hint_isTop( &hintmap->edge[i] ) )
-            stemhint->maxDS = hintmap->edge[i].dsCoord;
-          else
-            stemhint->minDS = hintmap->edge[i].dsCoord;
-
-          stemhint->used = TRUE;
-        }
-      }
-    }
-
-    /* hint map is ready to use */
-    hintmap->isValid = TRUE;
-
-    /* remember this mask has been used */
-    cf2_hintmask_setNew( hintMask, FALSE );
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_glyphpath_init( CF2_GlyphPath         glyphpath,
-                      CF2_Font              font,
-                      CF2_OutlineCallbacks  callbacks,
-                      CF2_Fixed             scaleY,
-                      /* CF2_Fixed  hShift, */
-                      CF2_ArrStack          hStemHintArray,
-                      CF2_ArrStack          vStemHintArray,
-                      CF2_HintMask          hintMask,
-                      CF2_Fixed             hintOriginY,
-                      const CF2_Blues       blues,
-                      const FT_Vector*      fractionalTranslation )
-  {
-    FT_ZERO( glyphpath );
-
-    glyphpath->font      = font;
-    glyphpath->callbacks = callbacks;
-
-    cf2_arrstack_init( &glyphpath->hintMoves,
-                       font->memory,
-                       &font->error,
-                       sizeof ( CF2_HintMoveRec ) );
-
-    cf2_hintmap_init( &glyphpath->initialHintMap,
-                      font,
-                      &glyphpath->initialHintMap,
-                      &glyphpath->hintMoves,
-                      scaleY );
-    cf2_hintmap_init( &glyphpath->firstHintMap,
-                      font,
-                      &glyphpath->initialHintMap,
-                      &glyphpath->hintMoves,
-                      scaleY );
-    cf2_hintmap_init( &glyphpath->hintMap,
-                      font,
-                      &glyphpath->initialHintMap,
-                      &glyphpath->hintMoves,
-                      scaleY );
-
-    glyphpath->scaleX = font->innerTransform.a;
-    glyphpath->scaleC = font->innerTransform.c;
-    glyphpath->scaleY = font->innerTransform.d;
-
-    glyphpath->fractionalTranslation = *fractionalTranslation;
-
-#if 0
-    glyphpath->hShift = hShift;       /* for fauxing */
-#endif
-
-    glyphpath->hStemHintArray = hStemHintArray;
-    glyphpath->vStemHintArray = vStemHintArray;
-    glyphpath->hintMask       = hintMask;      /* ptr to current mask */
-    glyphpath->hintOriginY    = hintOriginY;
-    glyphpath->blues          = blues;
-    glyphpath->darken         = font->darkened; /* TODO: should we make copies? */
-    glyphpath->xOffset        = font->darkenX;
-    glyphpath->yOffset        = font->darkenY;
-    glyphpath->miterLimit     = 2 * FT_MAX(
-                                     cf2_fixedAbs( glyphpath->xOffset ),
-                                     cf2_fixedAbs( glyphpath->yOffset ) );
-
-    /* .1 character space unit */
-    glyphpath->snapThreshold = cf2_doubleToFixed( 0.1 );
-
-    glyphpath->moveIsPending = TRUE;
-    glyphpath->pathIsOpen    = FALSE;
-    glyphpath->pathIsClosing = FALSE;
-    glyphpath->elemIsQueued  = FALSE;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_glyphpath_finalize( CF2_GlyphPath  glyphpath )
-  {
-    cf2_arrstack_finalize( &glyphpath->hintMoves );
-  }
-
-
-  /*
-   * Hint point in y-direction and apply outerTransform.
-   * Input `current' hint map (which is actually delayed by one element).
-   * Input x,y point in Character Space.
-   * Output x,y point in Device Space, including translation.
-   */
-  static void
-  cf2_glyphpath_hintPoint( CF2_GlyphPath  glyphpath,
-                           CF2_HintMap    hintmap,
-                           FT_Vector*     ppt,
-                           CF2_Fixed      x,
-                           CF2_Fixed      y )
-  {
-    FT_Vector  pt;   /* hinted point in upright DS */
-
-
-    pt.x = ADD_INT32( FT_MulFix( glyphpath->scaleX, x ),
-                      FT_MulFix( glyphpath->scaleC, y ) );
-    pt.y = cf2_hintmap_map( hintmap, y );
-
-    ppt->x = ADD_INT32(
-               FT_MulFix( glyphpath->font->outerTransform.a, pt.x ),
-               ADD_INT32(
-                 FT_MulFix( glyphpath->font->outerTransform.c, pt.y ),
-                 glyphpath->fractionalTranslation.x ) );
-    ppt->y = ADD_INT32(
-               FT_MulFix( glyphpath->font->outerTransform.b, pt.x ),
-               ADD_INT32(
-                 FT_MulFix( glyphpath->font->outerTransform.d, pt.y ),
-                 glyphpath->fractionalTranslation.y ) );
-  }
-
-
-  /*
-   * From two line segments, (u1,u2) and (v1,v2), compute a point of
-   * intersection on the corresponding lines.
-   * Return false if no intersection is found, or if the intersection is
-   * too far away from the ends of the line segments, u2 and v1.
-   *
-   */
-  static FT_Bool
-  cf2_glyphpath_computeIntersection( CF2_GlyphPath     glyphpath,
-                                     const FT_Vector*  u1,
-                                     const FT_Vector*  u2,
-                                     const FT_Vector*  v1,
-                                     const FT_Vector*  v2,
-                                     FT_Vector*        intersection )
-  {
-    /*
-     * Let `u' be a zero-based vector from the first segment, `v' from the
-     * second segment.
-     * Let `w 'be the zero-based vector from `u1' to `v1'.
-     * `perp' is the `perpendicular dot product'; see
-     * http://mathworld.wolfram.com/PerpDotProduct.html.
-     * `s' is the parameter for the parametric line for the first segment
-     * (`u').
-     *
-     * See notation in
-     * http://softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm.
-     * Calculations are done in 16.16, but must handle the squaring of
-     * line lengths in character space.  We scale all vectors by 1/32 to
-     * avoid overflow.  This allows values up to 4095 to be squared.  The
-     * scale factor cancels in the divide.
-     *
-     * TODO: the scale factor could be computed from UnitsPerEm.
-     *
-     */
-
-#define cf2_perp( a, b )                                    \
-          ( FT_MulFix( a.x, b.y ) - FT_MulFix( a.y, b.x ) )
-
-  /* round and divide by 32 */
-#define CF2_CS_SCALE( x )         \
-          ( ( (x) + 0x10 ) >> 5 )
-
-    FT_Vector  u, v, w;      /* scaled vectors */
-    CF2_Fixed  denominator, s;
-
-
-    u.x = CF2_CS_SCALE( SUB_INT32( u2->x, u1->x ) );
-    u.y = CF2_CS_SCALE( SUB_INT32( u2->y, u1->y ) );
-    v.x = CF2_CS_SCALE( SUB_INT32( v2->x, v1->x ) );
-    v.y = CF2_CS_SCALE( SUB_INT32( v2->y, v1->y ) );
-    w.x = CF2_CS_SCALE( SUB_INT32( v1->x, u1->x ) );
-    w.y = CF2_CS_SCALE( SUB_INT32( v1->y, u1->y ) );
-
-    denominator = cf2_perp( u, v );
-
-    if ( denominator == 0 )
-      return FALSE;           /* parallel or coincident lines */
-
-    s = FT_DivFix( cf2_perp( w, v ), denominator );
-
-    intersection->x = ADD_INT32( u1->x,
-                                 FT_MulFix( s, SUB_INT32( u2->x, u1->x ) ) );
-    intersection->y = ADD_INT32( u1->y,
-                                 FT_MulFix( s, SUB_INT32( u2->y, u1->y ) ) );
-
-
-    /*
-     * Special case snapping for horizontal and vertical lines.
-     * This cleans up intersections and reduces problems with winding
-     * order detection.
-     * Sample case is sbc cd KozGoPr6N-Medium.otf 20 16685.
-     * Note: these calculations are in character space.
-     *
-     */
-
-    if ( u1->x == u2->x                                                &&
-         cf2_fixedAbs( SUB_INT32( intersection->x,
-                                  u1->x ) ) < glyphpath->snapThreshold )
-      intersection->x = u1->x;
-    if ( u1->y == u2->y                                                &&
-         cf2_fixedAbs( SUB_INT32( intersection->y,
-                                  u1->y ) ) < glyphpath->snapThreshold )
-      intersection->y = u1->y;
-
-    if ( v1->x == v2->x                                                &&
-         cf2_fixedAbs( SUB_INT32( intersection->x,
-                                  v1->x ) ) < glyphpath->snapThreshold )
-      intersection->x = v1->x;
-    if ( v1->y == v2->y                                                &&
-         cf2_fixedAbs( SUB_INT32( intersection->y,
-                                  v1->y ) ) < glyphpath->snapThreshold )
-      intersection->y = v1->y;
-
-    /* limit the intersection distance from midpoint of u2 and v1 */
-    if ( cf2_fixedAbs( intersection->x - ADD_INT32( u2->x, v1->x ) / 2 ) >
-           glyphpath->miterLimit                                           ||
-         cf2_fixedAbs( intersection->y - ADD_INT32( u2->y, v1->y ) / 2 ) >
-           glyphpath->miterLimit                                           )
-      return FALSE;
-
-    return TRUE;
-  }
-
-
-  /*
-   * Push the cached element (glyphpath->prevElem*) to the outline
-   * consumer.  When a darkening offset is used, the end point of the
-   * cached element may be adjusted to an intersection point or we may
-   * synthesize a connecting line to the current element.  If we are
-   * closing a subpath, we may also generate a connecting line to the start
-   * point.
-   *
-   * This is where Character Space (CS) is converted to Device Space (DS)
-   * using a hint map.  This calculation must use a HintMap that was valid
-   * at the time the element was saved.  For the first point in a subpath,
-   * that is a saved HintMap.  For most elements, it just means the caller
-   * has delayed building a HintMap from the current HintMask.
-   *
-   * Transform each point with outerTransform and call the outline
-   * callbacks.  This is a general 3x3 transform:
-   *
-   *   x' = a*x + c*y + tx, y' = b*x + d*y + ty
-   *
-   * but it uses 4 elements from CF2_Font and the translation part
-   * from CF2_GlyphPath.
-   *
-   */
-  static void
-  cf2_glyphpath_pushPrevElem( CF2_GlyphPath  glyphpath,
-                              CF2_HintMap    hintmap,
-                              FT_Vector*     nextP0,
-                              FT_Vector      nextP1,
-                              FT_Bool        close )
-  {
-    CF2_CallbackParamsRec  params;
-
-    FT_Vector*  prevP0;
-    FT_Vector*  prevP1;
-
-    FT_Vector  intersection    = { 0, 0 };
-    FT_Bool    useIntersection = FALSE;
-
-
-    FT_ASSERT( glyphpath->prevElemOp == CF2_PathOpLineTo ||
-               glyphpath->prevElemOp == CF2_PathOpCubeTo );
-
-    if ( glyphpath->prevElemOp == CF2_PathOpLineTo )
-    {
-      prevP0 = &glyphpath->prevElemP0;
-      prevP1 = &glyphpath->prevElemP1;
-    }
-    else
-    {
-      prevP0 = &glyphpath->prevElemP2;
-      prevP1 = &glyphpath->prevElemP3;
-    }
-
-    /* optimization: if previous and next elements are offset by the same */
-    /* amount, then there will be no gap, and no need to compute an       */
-    /* intersection.                                                      */
-    if ( prevP1->x != nextP0->x || prevP1->y != nextP0->y )
-    {
-      /* previous element does not join next element:             */
-      /* adjust end point of previous element to the intersection */
-      useIntersection = cf2_glyphpath_computeIntersection( glyphpath,
-                                                           prevP0,
-                                                           prevP1,
-                                                           nextP0,
-                                                           &nextP1,
-                                                           &intersection );
-      if ( useIntersection )
-      {
-        /* modify the last point of the cached element (either line or */
-        /* curve)                                                      */
-        *prevP1 = intersection;
-      }
-    }
-
-    params.pt0 = glyphpath->currentDS;
-
-    switch( glyphpath->prevElemOp )
-    {
-    case CF2_PathOpLineTo:
-      params.op = CF2_PathOpLineTo;
-
-      /* note: pt2 and pt3 are unused */
-
-      if ( close )
-      {
-        /* use first hint map if closing */
-        cf2_glyphpath_hintPoint( glyphpath,
-                                 &glyphpath->firstHintMap,
-                                 &params.pt1,
-                                 glyphpath->prevElemP1.x,
-                                 glyphpath->prevElemP1.y );
-      }
-      else
-      {
-        cf2_glyphpath_hintPoint( glyphpath,
-                                 hintmap,
-                                 &params.pt1,
-                                 glyphpath->prevElemP1.x,
-                                 glyphpath->prevElemP1.y );
-      }
-
-      /* output only non-zero length lines */
-      if ( params.pt0.x != params.pt1.x || params.pt0.y != params.pt1.y )
-      {
-        glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
-
-        glyphpath->currentDS = params.pt1;
-      }
-      break;
-
-    case CF2_PathOpCubeTo:
-      params.op = CF2_PathOpCubeTo;
-
-      /* TODO: should we intersect the interior joins (p1-p2 and p2-p3)? */
-      cf2_glyphpath_hintPoint( glyphpath,
-                               hintmap,
-                               &params.pt1,
-                               glyphpath->prevElemP1.x,
-                               glyphpath->prevElemP1.y );
-      cf2_glyphpath_hintPoint( glyphpath,
-                               hintmap,
-                               &params.pt2,
-                               glyphpath->prevElemP2.x,
-                               glyphpath->prevElemP2.y );
-      cf2_glyphpath_hintPoint( glyphpath,
-                               hintmap,
-                               &params.pt3,
-                               glyphpath->prevElemP3.x,
-                               glyphpath->prevElemP3.y );
-
-      glyphpath->callbacks->cubeTo( glyphpath->callbacks, &params );
-
-      glyphpath->currentDS = params.pt3;
-
-      break;
-    }
-
-    if ( !useIntersection || close )
-    {
-      /* insert connecting line between end of previous element and start */
-      /* of current one                                                   */
-      /* note: at the end of a subpath, we might do both, so use `nextP0' */
-      /* before we change it, below                                       */
-
-      if ( close )
-      {
-        /* if we are closing the subpath, then nextP0 is in the first     */
-        /* hint zone                                                      */
-        cf2_glyphpath_hintPoint( glyphpath,
-                                 &glyphpath->firstHintMap,
-                                 &params.pt1,
-                                 nextP0->x,
-                                 nextP0->y );
-      }
-      else
-      {
-        cf2_glyphpath_hintPoint( glyphpath,
-                                 hintmap,
-                                 &params.pt1,
-                                 nextP0->x,
-                                 nextP0->y );
-      }
-
-      if ( params.pt1.x != glyphpath->currentDS.x ||
-           params.pt1.y != glyphpath->currentDS.y )
-      {
-        /* length is nonzero */
-        params.op  = CF2_PathOpLineTo;
-        params.pt0 = glyphpath->currentDS;
-
-        /* note: pt2 and pt3 are unused */
-        glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
-
-        glyphpath->currentDS = params.pt1;
-      }
-    }
-
-    if ( useIntersection )
-    {
-      /* return intersection point to caller */
-      *nextP0 = intersection;
-    }
-  }
-
-
-  /* push a MoveTo element based on current point and offset of current */
-  /* element                                                            */
-  static void
-  cf2_glyphpath_pushMove( CF2_GlyphPath  glyphpath,
-                          FT_Vector      start )
-  {
-    CF2_CallbackParamsRec  params;
-
-
-    params.op  = CF2_PathOpMoveTo;
-    params.pt0 = glyphpath->currentDS;
-
-    /* Test if move has really happened yet; it would have called */
-    /* `cf2_hintmap_build' to set `isValid'.                   */
-    if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) )
-    {
-      /* we are here iff first subpath is missing a moveto operator: */
-      /* synthesize first moveTo to finish initialization of hintMap */
-      cf2_glyphpath_moveTo( glyphpath,
-                            glyphpath->start.x,
-                            glyphpath->start.y );
-    }
-
-    cf2_glyphpath_hintPoint( glyphpath,
-                             &glyphpath->hintMap,
-                             &params.pt1,
-                             start.x,
-                             start.y );
-
-    /* note: pt2 and pt3 are unused */
-    glyphpath->callbacks->moveTo( glyphpath->callbacks, &params );
-
-    glyphpath->currentDS    = params.pt1;
-    glyphpath->offsetStart0 = start;
-  }
-
-
-  /*
-   * All coordinates are in character space.
-   * On input, (x1, y1) and (x2, y2) give line segment.
-   * On output, (x, y) give offset vector.
-   * We use a piecewise approximation to trig functions.
-   *
-   * TODO: Offset true perpendicular and proper length
-   *       supply the y-translation for hinting here, too,
-   *       that adds yOffset unconditionally to *y.
-   */
-  static void
-  cf2_glyphpath_computeOffset( CF2_GlyphPath  glyphpath,
-                               CF2_Fixed      x1,
-                               CF2_Fixed      y1,
-                               CF2_Fixed      x2,
-                               CF2_Fixed      y2,
-                               CF2_Fixed*     x,
-                               CF2_Fixed*     y )
-  {
-    CF2_Fixed  dx = SUB_INT32( x2, x1 );
-    CF2_Fixed  dy = SUB_INT32( y2, y1 );
-
-
-    /* note: negative offsets don't work here; negate deltas to change */
-    /* quadrants, below                                                */
-    if ( glyphpath->font->reverseWinding )
-    {
-      dx = NEG_INT32( dx );
-      dy = NEG_INT32( dy );
-    }
-
-    *x = *y = 0;
-
-    if ( !glyphpath->darken )
-        return;
-
-    /* add momentum for this path element */
-    glyphpath->callbacks->windingMomentum =
-      ADD_INT32( glyphpath->callbacks->windingMomentum,
-                 cf2_getWindingMomentum( x1, y1, x2, y2 ) );
-
-    /* note: allow mixed integer and fixed multiplication here */
-    if ( dx >= 0 )
-    {
-      if ( dy >= 0 )
-      {
-        /* first quadrant, +x +y */
-
-        if ( dx > MUL_INT32( 2, dy ) )
-        {
-          /* +x */
-          *x = 0;
-          *y = 0;
-        }
-        else if ( dy > MUL_INT32( 2, dx ) )
-        {
-          /* +y */
-          *x = glyphpath->xOffset;
-          *y = glyphpath->yOffset;
-        }
-        else
-        {
-          /* +x +y */
-          *x = FT_MulFix( cf2_doubleToFixed( 0.7 ),
-                          glyphpath->xOffset );
-          *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ),
-                          glyphpath->yOffset );
-        }
-      }
-      else
-      {
-        /* fourth quadrant, +x -y */
-
-        if ( dx > MUL_INT32( -2, dy ) )
-        {
-          /* +x */
-          *x = 0;
-          *y = 0;
-        }
-        else if ( NEG_INT32( dy ) > MUL_INT32( 2, dx ) )
-        {
-          /* -y */
-          *x = NEG_INT32( glyphpath->xOffset );
-          *y = glyphpath->yOffset;
-        }
-        else
-        {
-          /* +x -y */
-          *x = FT_MulFix( cf2_doubleToFixed( -0.7 ),
-                          glyphpath->xOffset );
-          *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ),
-                          glyphpath->yOffset );
-        }
-      }
-    }
-    else
-    {
-      if ( dy >= 0 )
-      {
-        /* second quadrant, -x +y */
-
-        if ( NEG_INT32( dx ) > MUL_INT32( 2, dy ) )
-        {
-          /* -x */
-          *x = 0;
-          *y = MUL_INT32( 2, glyphpath->yOffset );
-        }
-        else if ( dy > MUL_INT32( -2, dx ) )
-        {
-          /* +y */
-          *x = glyphpath->xOffset;
-          *y = glyphpath->yOffset;
-        }
-        else
-        {
-          /* -x +y */
-          *x = FT_MulFix( cf2_doubleToFixed( 0.7 ),
-                          glyphpath->xOffset );
-          *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ),
-                          glyphpath->yOffset );
-        }
-      }
-      else
-      {
-        /* third quadrant, -x -y */
-
-        if ( NEG_INT32( dx ) > MUL_INT32( -2, dy ) )
-        {
-          /* -x */
-          *x = 0;
-          *y = MUL_INT32( 2, glyphpath->yOffset );
-        }
-        else if ( NEG_INT32( dy ) > MUL_INT32( -2, dx ) )
-        {
-          /* -y */
-          *x = NEG_INT32( glyphpath->xOffset );
-          *y = glyphpath->yOffset;
-        }
-        else
-        {
-          /* -x -y */
-          *x = FT_MulFix( cf2_doubleToFixed( -0.7 ),
-                          glyphpath->xOffset );
-          *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ),
-                          glyphpath->yOffset );
-        }
-      }
-    }
-  }
-
-
-  /*
-   * The functions cf2_glyphpath_{moveTo,lineTo,curveTo,closeOpenPath} are
-   * called by the interpreter with Character Space (CS) coordinates.  Each
-   * path element is placed into a queue of length one to await the
-   * calculation of the following element.  At that time, the darkening
-   * offset of the following element is known and joins can be computed,
-   * including possible modification of this element, before mapping to
-   * Device Space (DS) and passing it on to the outline consumer.
-   *
-   */
-  FT_LOCAL_DEF( void )
-  cf2_glyphpath_moveTo( CF2_GlyphPath  glyphpath,
-                        CF2_Fixed      x,
-                        CF2_Fixed      y )
-  {
-    cf2_glyphpath_closeOpenPath( glyphpath );
-
-    /* save the parameters of the move for later, when we'll know how to */
-    /* offset it;                                                        */
-    /* also save last move point */
-    glyphpath->currentCS.x = glyphpath->start.x = x;
-    glyphpath->currentCS.y = glyphpath->start.y = y;
-
-    glyphpath->moveIsPending = TRUE;
-
-    /* ensure we have a valid map with current mask */
-    if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) ||
-         cf2_hintmask_isNew( glyphpath->hintMask )   )
-      cf2_hintmap_build( &glyphpath->hintMap,
-                         glyphpath->hStemHintArray,
-                         glyphpath->vStemHintArray,
-                         glyphpath->hintMask,
-                         glyphpath->hintOriginY,
-                         FALSE );
-
-    /* save a copy of current HintMap to use when drawing initial point */
-    glyphpath->firstHintMap = glyphpath->hintMap;     /* structure copy */
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_glyphpath_lineTo( CF2_GlyphPath  glyphpath,
-                        CF2_Fixed      x,
-                        CF2_Fixed      y )
-  {
-    CF2_Fixed  xOffset, yOffset;
-    FT_Vector  P0, P1;
-    FT_Bool    newHintMap;
-
-    /*
-     * New hints will be applied after cf2_glyphpath_pushPrevElem has run.
-     * In case this is a synthesized closing line, any new hints should be
-     * delayed until this path is closed (`cf2_hintmask_isNew' will be
-     * called again before the next line or curve).
-     */
-
-    /* true if new hint map not on close */
-    newHintMap = cf2_hintmask_isNew( glyphpath->hintMask ) &&
-                 !glyphpath->pathIsClosing;
-
-    /*
-     * Zero-length lines may occur in the charstring.  Because we cannot
-     * compute darkening offsets or intersections from zero-length lines,
-     * it is best to remove them and avoid artifacts.  However, zero-length
-     * lines in CS at the start of a new hint map can generate non-zero
-     * lines in DS due to hint substitution.  We detect a change in hint
-     * map here and pass those zero-length lines along.
-     */
-
-    /*
-     * Note: Find explicitly closed paths here with a conditional
-     *       breakpoint using
-     *
-     *         !gp->pathIsClosing && gp->start.x == x && gp->start.y == y
-     *
-     */
-
-    if ( glyphpath->currentCS.x == x &&
-         glyphpath->currentCS.y == y &&
-         !newHintMap                 )
-      /*
-       * Ignore zero-length lines in CS where the hint map is the same
-       * because the line in DS will also be zero length.
-       *
-       * Ignore zero-length lines when we synthesize a closing line because
-       * the close will be handled in cf2_glyphPath_pushPrevElem.
-       */
-      return;
-
-    cf2_glyphpath_computeOffset( glyphpath,
-                                 glyphpath->currentCS.x,
-                                 glyphpath->currentCS.y,
-                                 x,
-                                 y,
-                                 &xOffset,
-                                 &yOffset );
-
-    /* construct offset points */
-    P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset );
-    P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset );
-    P1.x = ADD_INT32( x, xOffset );
-    P1.y = ADD_INT32( y, yOffset );
-
-    if ( glyphpath->moveIsPending )
-    {
-      /* emit offset 1st point as MoveTo */
-      cf2_glyphpath_pushMove( glyphpath, P0 );
-
-      glyphpath->moveIsPending = FALSE;  /* adjust state machine */
-      glyphpath->pathIsOpen    = TRUE;
-
-      glyphpath->offsetStart1 = P1;              /* record second point */
-    }
-
-    if ( glyphpath->elemIsQueued )
-    {
-      FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
-                 glyphpath->hintMap.count == 0              );
-
-      cf2_glyphpath_pushPrevElem( glyphpath,
-                                  &glyphpath->hintMap,
-                                  &P0,
-                                  P1,
-                                  FALSE );
-    }
-
-    /* queue the current element with offset points */
-    glyphpath->elemIsQueued = TRUE;
-    glyphpath->prevElemOp   = CF2_PathOpLineTo;
-    glyphpath->prevElemP0   = P0;
-    glyphpath->prevElemP1   = P1;
-
-    /* update current map */
-    if ( newHintMap )
-      cf2_hintmap_build( &glyphpath->hintMap,
-                         glyphpath->hStemHintArray,
-                         glyphpath->vStemHintArray,
-                         glyphpath->hintMask,
-                         glyphpath->hintOriginY,
-                         FALSE );
-
-    glyphpath->currentCS.x = x;     /* pre-offset current point */
-    glyphpath->currentCS.y = y;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_glyphpath_curveTo( CF2_GlyphPath  glyphpath,
-                         CF2_Fixed      x1,
-                         CF2_Fixed      y1,
-                         CF2_Fixed      x2,
-                         CF2_Fixed      y2,
-                         CF2_Fixed      x3,
-                         CF2_Fixed      y3 )
-  {
-    CF2_Fixed  xOffset1, yOffset1, xOffset3, yOffset3;
-    FT_Vector  P0, P1, P2, P3;
-
-
-    /* TODO: ignore zero length portions of curve?? */
-    cf2_glyphpath_computeOffset( glyphpath,
-                                 glyphpath->currentCS.x,
-                                 glyphpath->currentCS.y,
-                                 x1,
-                                 y1,
-                                 &xOffset1,
-                                 &yOffset1 );
-    cf2_glyphpath_computeOffset( glyphpath,
-                                 x2,
-                                 y2,
-                                 x3,
-                                 y3,
-                                 &xOffset3,
-                                 &yOffset3 );
-
-    /* add momentum from the middle segment */
-    glyphpath->callbacks->windingMomentum =
-      ADD_INT32( glyphpath->callbacks->windingMomentum,
-                 cf2_getWindingMomentum( x1, y1, x2, y2 ) );
-
-    /* construct offset points */
-    P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset1 );
-    P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset1 );
-    P1.x = ADD_INT32( x1, xOffset1 );
-    P1.y = ADD_INT32( y1, yOffset1 );
-    /* note: preserve angle of final segment by using offset3 at both ends */
-    P2.x = ADD_INT32( x2, xOffset3 );
-    P2.y = ADD_INT32( y2, yOffset3 );
-    P3.x = ADD_INT32( x3, xOffset3 );
-    P3.y = ADD_INT32( y3, yOffset3 );
-
-    if ( glyphpath->moveIsPending )
-    {
-      /* emit offset 1st point as MoveTo */
-      cf2_glyphpath_pushMove( glyphpath, P0 );
-
-      glyphpath->moveIsPending = FALSE;
-      glyphpath->pathIsOpen    = TRUE;
-
-      glyphpath->offsetStart1 = P1;              /* record second point */
-    }
-
-    if ( glyphpath->elemIsQueued )
-    {
-      FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
-                 glyphpath->hintMap.count == 0              );
-
-      cf2_glyphpath_pushPrevElem( glyphpath,
-                                  &glyphpath->hintMap,
-                                  &P0,
-                                  P1,
-                                  FALSE );
-    }
-
-    /* queue the current element with offset points */
-    glyphpath->elemIsQueued = TRUE;
-    glyphpath->prevElemOp   = CF2_PathOpCubeTo;
-    glyphpath->prevElemP0   = P0;
-    glyphpath->prevElemP1   = P1;
-    glyphpath->prevElemP2   = P2;
-    glyphpath->prevElemP3   = P3;
-
-    /* update current map */
-    if ( cf2_hintmask_isNew( glyphpath->hintMask ) )
-      cf2_hintmap_build( &glyphpath->hintMap,
-                         glyphpath->hStemHintArray,
-                         glyphpath->vStemHintArray,
-                         glyphpath->hintMask,
-                         glyphpath->hintOriginY,
-                         FALSE );
-
-    glyphpath->currentCS.x = x3;       /* pre-offset current point */
-    glyphpath->currentCS.y = y3;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_glyphpath_closeOpenPath( CF2_GlyphPath  glyphpath )
-  {
-    if ( glyphpath->pathIsOpen )
-    {
-      /*
-       * A closing line in Character Space line is always generated below
-       * with `cf2_glyphPath_lineTo'.  It may be ignored later if it turns
-       * out to be zero length in Device Space.
-       */
-      glyphpath->pathIsClosing = TRUE;
-
-      cf2_glyphpath_lineTo( glyphpath,
-                            glyphpath->start.x,
-                            glyphpath->start.y );
-
-      /* empty the final element from the queue and close the path */
-      if ( glyphpath->elemIsQueued )
-        cf2_glyphpath_pushPrevElem( glyphpath,
-                                    &glyphpath->hintMap,
-                                    &glyphpath->offsetStart0,
-                                    glyphpath->offsetStart1,
-                                    TRUE );
-
-      /* reset state machine */
-      glyphpath->moveIsPending = TRUE;
-      glyphpath->pathIsOpen    = FALSE;
-      glyphpath->pathIsClosing = FALSE;
-      glyphpath->elemIsQueued  = FALSE;
-    }
-  }
-
-
-/* END */
--- a/src/psaux/cf2hints.h
+++ /dev/null
@@ -1,289 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2hints.h                                                             */
-/*                                                                         */
-/*    Adobe's code for handling CFF hints (body).                          */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2HINTS_H_
-#define CF2HINTS_H_
-
-
-FT_BEGIN_HEADER
-
-
-  enum
-  {
-    CF2_MAX_HINTS = 96    /* maximum # of hints */
-  };
-
-
-  /*
-   * A HintMask object stores a bit mask that specifies which hints in the
-   * charstring are active at a given time.  Hints in CFF must be declared
-   * at the start, before any drawing operators, with horizontal hints
-   * preceding vertical hints.  The HintMask is ordered the same way, with
-   * horizontal hints immediately followed by vertical hints.  Clients are
-   * responsible for knowing how many of each type are present.
-   *
-   * The maximum total number of hints is 96, as specified by the CFF
-   * specification.
-   *
-   * A HintMask is built 0 or more times while interpreting a charstring, by
-   * the HintMask operator.  There is only one HintMask, but it is built or
-   * rebuilt each time there is a hint substitution (HintMask operator) in
-   * the charstring.  A default HintMask with all bits set is built if there
-   * has been no HintMask operator prior to the first drawing operator.
-   *
-   */
-
-  typedef struct  CF2_HintMaskRec_
-  {
-    FT_Error*  error;
-
-    FT_Bool  isValid;
-    FT_Bool  isNew;
-
-    size_t  bitCount;
-    size_t  byteCount;
-
-    FT_Byte  mask[( CF2_MAX_HINTS + 7 ) / 8];
-
-  } CF2_HintMaskRec, *CF2_HintMask;
-
-
-  typedef struct  CF2_StemHintRec_
-  {
-    FT_Bool  used;     /* DS positions are valid         */
-
-    CF2_Fixed  min;    /* original character space value */
-    CF2_Fixed  max;
-
-    CF2_Fixed  minDS;  /* DS position after first use    */
-    CF2_Fixed  maxDS;
-
-  } CF2_StemHintRec, *CF2_StemHint;
-
-
-  /*
-   * A HintMap object stores a piecewise linear function for mapping
-   * y-coordinates from character space to device space, providing
-   * appropriate pixel alignment to stem edges.
-   *
-   * The map is implemented as an array of `CF2_Hint' elements, each
-   * representing an edge.  When edges are paired, as from stem hints, the
-   * bottom edge must immediately precede the top edge in the array.
-   * Element character space AND device space positions must both increase
-   * monotonically in the array.  `CF2_Hint' elements are also used as
-   * parameters to `cf2_blues_capture'.
-   *
-   * The `cf2_hintmap_build' method must be called before any drawing
-   * operation (beginning with a Move operator) and at each hint
-   * substitution (HintMask operator).
-   *
-   * The `cf2_hintmap_map' method is called to transform y-coordinates at
-   * each drawing operation (move, line, curve).
-   *
-   */
-
-  /* TODO: make this a CF2_ArrStack and add a deep copy method */
-  enum
-  {
-    CF2_MAX_HINT_EDGES = CF2_MAX_HINTS * 2
-  };
-
-
-  typedef struct  CF2_HintMapRec_
-  {
-    CF2_Font  font;
-
-    /* initial map based on blue zones */
-    struct CF2_HintMapRec_*  initialHintMap;
-
-    /* working storage for 2nd pass adjustHints */
-    CF2_ArrStack  hintMoves;
-
-    FT_Bool  isValid;
-    FT_Bool  hinted;
-
-    CF2_Fixed  scale;
-    CF2_UInt   count;
-
-    /* start search from this index */
-    CF2_UInt  lastIndex;
-
-    CF2_HintRec  edge[CF2_MAX_HINT_EDGES]; /* 192 */
-
-  } CF2_HintMapRec, *CF2_HintMap;
-
-
-  FT_LOCAL( FT_Bool )
-  cf2_hint_isValid( const CF2_Hint  hint );
-  FT_LOCAL( FT_Bool )
-  cf2_hint_isTop( const CF2_Hint  hint );
-  FT_LOCAL( FT_Bool )
-  cf2_hint_isBottom( const CF2_Hint  hint );
-  FT_LOCAL( void )
-  cf2_hint_lock( CF2_Hint  hint );
-
-
-  FT_LOCAL( void )
-  cf2_hintmap_init( CF2_HintMap   hintmap,
-                    CF2_Font      font,
-                    CF2_HintMap   initialMap,
-                    CF2_ArrStack  hintMoves,
-                    CF2_Fixed     scale );
-  FT_LOCAL( void )
-  cf2_hintmap_build( CF2_HintMap   hintmap,
-                     CF2_ArrStack  hStemHintArray,
-                     CF2_ArrStack  vStemHintArray,
-                     CF2_HintMask  hintMask,
-                     CF2_Fixed     hintOrigin,
-                     FT_Bool       initialMap );
-
-
-  /*
-   * GlyphPath is a wrapper for drawing operations that scales the
-   * coordinates according to the render matrix and HintMap.  It also tracks
-   * open paths to control ClosePath and to insert MoveTo for broken fonts.
-   *
-   */
-  typedef struct  CF2_GlyphPathRec_
-  {
-    /* TODO: gather some of these into a hinting context */
-
-    CF2_Font              font;           /* font instance    */
-    CF2_OutlineCallbacks  callbacks;      /* outline consumer */
-
-
-    CF2_HintMapRec  hintMap;        /* current hint map            */
-    CF2_HintMapRec  firstHintMap;   /* saved copy                  */
-    CF2_HintMapRec  initialHintMap; /* based on all captured hints */
-
-    CF2_ArrStackRec  hintMoves;  /* list of hint moves for 2nd pass */
-
-    CF2_Fixed  scaleX;         /* matrix a */
-    CF2_Fixed  scaleC;         /* matrix c */
-    CF2_Fixed  scaleY;         /* matrix d */
-
-    FT_Vector  fractionalTranslation;  /* including deviceXScale */
-#if 0
-    CF2_Fixed  hShift;    /* character space horizontal shift */
-                          /* (for fauxing)                    */
-#endif
-
-    FT_Bool  pathIsOpen;     /* true after MoveTo                     */
-    FT_Bool  pathIsClosing;  /* true when synthesizing closepath line */
-    FT_Bool  darken;         /* true if stem darkening                */
-    FT_Bool  moveIsPending;  /* true between MoveTo and offset MoveTo */
-
-    /* references used to call `cf2_hintmap_build', if necessary */
-    CF2_ArrStack         hStemHintArray;
-    CF2_ArrStack         vStemHintArray;
-    CF2_HintMask         hintMask;     /* ptr to the current mask */
-    CF2_Fixed            hintOriginY;  /* copy of current origin  */
-    const CF2_BluesRec*  blues;
-
-    CF2_Fixed  xOffset;        /* character space offsets */
-    CF2_Fixed  yOffset;
-
-    /* character space miter limit threshold */
-    CF2_Fixed  miterLimit;
-    /* vertical/horizontal snap distance in character space */
-    CF2_Fixed  snapThreshold;
-
-    FT_Vector  offsetStart0;  /* first and second points of first */
-    FT_Vector  offsetStart1;  /* element with offset applied      */
-
-    /* current point, character space, before offset */
-    FT_Vector  currentCS;
-    /* current point, device space */
-    FT_Vector  currentDS;
-    /* start point of subpath, character space */
-    FT_Vector  start;
-
-    /* the following members constitute the `queue' of one element */
-    FT_Bool  elemIsQueued;
-    CF2_Int  prevElemOp;
-
-    FT_Vector  prevElemP0;
-    FT_Vector  prevElemP1;
-    FT_Vector  prevElemP2;
-    FT_Vector  prevElemP3;
-
-  } CF2_GlyphPathRec, *CF2_GlyphPath;
-
-
-  FT_LOCAL( void )
-  cf2_glyphpath_init( CF2_GlyphPath         glyphpath,
-                      CF2_Font              font,
-                      CF2_OutlineCallbacks  callbacks,
-                      CF2_Fixed             scaleY,
-                      /* CF2_Fixed hShift, */
-                      CF2_ArrStack          hStemHintArray,
-                      CF2_ArrStack          vStemHintArray,
-                      CF2_HintMask          hintMask,
-                      CF2_Fixed             hintOrigin,
-                      const CF2_Blues       blues,
-                      const FT_Vector*      fractionalTranslation );
-  FT_LOCAL( void )
-  cf2_glyphpath_finalize( CF2_GlyphPath  glyphpath );
-
-  FT_LOCAL( void )
-  cf2_glyphpath_moveTo( CF2_GlyphPath  glyphpath,
-                        CF2_Fixed      x,
-                        CF2_Fixed      y );
-  FT_LOCAL( void )
-  cf2_glyphpath_lineTo( CF2_GlyphPath  glyphpath,
-                        CF2_Fixed      x,
-                        CF2_Fixed      y );
-  FT_LOCAL( void )
-  cf2_glyphpath_curveTo( CF2_GlyphPath  glyphpath,
-                         CF2_Fixed      x1,
-                         CF2_Fixed      y1,
-                         CF2_Fixed      x2,
-                         CF2_Fixed      y2,
-                         CF2_Fixed      x3,
-                         CF2_Fixed      y3 );
-  FT_LOCAL( void )
-  cf2_glyphpath_closeOpenPath( CF2_GlyphPath  glyphpath );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2HINTS_H_ */
-
-
-/* END */
--- a/src/psaux/cf2intrp.c
+++ /dev/null
@@ -1,1959 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2intrp.c                                                             */
-/*                                                                         */
-/*    Adobe's CFF Interpreter (body).                                      */
-/*                                                                         */
-/*  Copyright 2007-2014 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include FT_INTERNAL_DEBUG_H
-#include FT_SERVICE_CFF_TABLE_LOAD_H
-
-#include "cf2glue.h"
-#include "cf2font.h"
-#include "cf2stack.h"
-#include "cf2hints.h"
-#include "cf2intrp.h"
-
-#include "cf2error.h"
-#include "psobjs.h"  /* for cff_random */
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* 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_cf2interp
-
-
-  FT_LOCAL_DEF( void )
-  cf2_hintmask_init( CF2_HintMask  hintmask,
-                     FT_Error*     error )
-  {
-    FT_ZERO( hintmask );
-
-    hintmask->error = error;
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  cf2_hintmask_isValid( const CF2_HintMask  hintmask )
-  {
-    return hintmask->isValid;
-  }
-
-
-  FT_LOCAL_DEF( FT_Bool )
-  cf2_hintmask_isNew( const CF2_HintMask  hintmask )
-  {
-    return hintmask->isNew;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_hintmask_setNew( CF2_HintMask  hintmask,
-                       FT_Bool       val )
-  {
-    hintmask->isNew = val;
-  }
-
-
-  /* clients call `getMaskPtr' in order to iterate */
-  /* through hint mask                             */
-
-  FT_LOCAL_DEF( FT_Byte* )
-  cf2_hintmask_getMaskPtr( CF2_HintMask  hintmask )
-  {
-    return hintmask->mask;
-  }
-
-
-  static size_t
-  cf2_hintmask_setCounts( CF2_HintMask  hintmask,
-                          size_t        bitCount )
-  {
-    if ( bitCount > CF2_MAX_HINTS )
-    {
-      /* total of h and v stems must be <= 96 */
-      CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format );
-      return 0;
-    }
-
-    hintmask->bitCount  = bitCount;
-    hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8;
-
-    hintmask->isValid = TRUE;
-    hintmask->isNew   = TRUE;
-
-    return bitCount;
-  }
-
-
-  /* consume the hintmask bytes from the charstring, advancing the src */
-  /* pointer                                                           */
-  static void
-  cf2_hintmask_read( CF2_HintMask  hintmask,
-                     CF2_Buffer    charstring,
-                     size_t        bitCount )
-  {
-    size_t  i;
-
-#ifndef CF2_NDEBUG
-    /* these are the bits in the final mask byte that should be zero  */
-    /* Note: this variable is only used in an assert expression below */
-    /* and then only if CF2_NDEBUG is not defined                     */
-    CF2_UInt  mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
-#endif
-
-
-    /* initialize counts and isValid */
-    if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
-      return;
-
-    FT_ASSERT( hintmask->byteCount > 0 );
-
-    FT_TRACE4(( " (maskbytes:" ));
-
-    /* set mask and advance interpreter's charstring pointer */
-    for ( i = 0; i < hintmask->byteCount; i++ )
-    {
-      hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring );
-      FT_TRACE4(( " 0x%02X", hintmask->mask[i] ));
-    }
-
-    FT_TRACE4(( ")\n" ));
-
-    /* assert any unused bits in last byte are zero unless there's a prior */
-    /* error                                                               */
-    /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1      */
-#ifndef CF2_NDEBUG
-    FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 ||
-               *hintmask->error                                        );
-#endif
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_hintmask_setAll( CF2_HintMask  hintmask,
-                       size_t        bitCount )
-  {
-    size_t    i;
-    CF2_UInt  mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
-
-
-    /* initialize counts and isValid */
-    if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
-      return;
-
-    FT_ASSERT( hintmask->byteCount > 0 );
-    FT_ASSERT( hintmask->byteCount <=
-                 sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) );
-
-    /* set mask to all ones */
-    for ( i = 0; i < hintmask->byteCount; i++ )
-      hintmask->mask[i] = 0xFF;
-
-    /* clear unused bits                                              */
-    /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */
-    hintmask->mask[hintmask->byteCount - 1] &= ~mask;
-  }
-
-
-  /* Type2 charstring opcodes */
-  enum
-  {
-    cf2_cmdRESERVED_0,   /* 0 */
-    cf2_cmdHSTEM,        /* 1 */
-    cf2_cmdRESERVED_2,   /* 2 */
-    cf2_cmdVSTEM,        /* 3 */
-    cf2_cmdVMOVETO,      /* 4 */
-    cf2_cmdRLINETO,      /* 5 */
-    cf2_cmdHLINETO,      /* 6 */
-    cf2_cmdVLINETO,      /* 7 */
-    cf2_cmdRRCURVETO,    /* 8 */
-    cf2_cmdRESERVED_9,   /* 9 */
-    cf2_cmdCALLSUBR,     /* 10 */
-    cf2_cmdRETURN,       /* 11 */
-    cf2_cmdESC,          /* 12 */
-    cf2_cmdRESERVED_13,  /* 13 */
-    cf2_cmdENDCHAR,      /* 14 */
-    cf2_cmdVSINDEX,      /* 15 */
-    cf2_cmdBLEND,        /* 16 */
-    cf2_cmdRESERVED_17,  /* 17 */
-    cf2_cmdHSTEMHM,      /* 18 */
-    cf2_cmdHINTMASK,     /* 19 */
-    cf2_cmdCNTRMASK,     /* 20 */
-    cf2_cmdRMOVETO,      /* 21 */
-    cf2_cmdHMOVETO,      /* 22 */
-    cf2_cmdVSTEMHM,      /* 23 */
-    cf2_cmdRCURVELINE,   /* 24 */
-    cf2_cmdRLINECURVE,   /* 25 */
-    cf2_cmdVVCURVETO,    /* 26 */
-    cf2_cmdHHCURVETO,    /* 27 */
-    cf2_cmdEXTENDEDNMBR, /* 28 */
-    cf2_cmdCALLGSUBR,    /* 29 */
-    cf2_cmdVHCURVETO,    /* 30 */
-    cf2_cmdHVCURVETO     /* 31 */
-  };
-
-  enum
-  {
-    cf2_escDOTSECTION,   /* 0 */
-    cf2_escRESERVED_1,   /* 1 */
-    cf2_escRESERVED_2,   /* 2 */
-    cf2_escAND,          /* 3 */
-    cf2_escOR,           /* 4 */
-    cf2_escNOT,          /* 5 */
-    cf2_escRESERVED_6,   /* 6 */
-    cf2_escRESERVED_7,   /* 7 */
-    cf2_escRESERVED_8,   /* 8 */
-    cf2_escABS,          /* 9 */
-    cf2_escADD,          /* 10     like otherADD */
-    cf2_escSUB,          /* 11     like otherSUB */
-    cf2_escDIV,          /* 12 */
-    cf2_escRESERVED_13,  /* 13 */
-    cf2_escNEG,          /* 14 */
-    cf2_escEQ,           /* 15 */
-    cf2_escRESERVED_16,  /* 16 */
-    cf2_escRESERVED_17,  /* 17 */
-    cf2_escDROP,         /* 18 */
-    cf2_escRESERVED_19,  /* 19 */
-    cf2_escPUT,          /* 20     like otherPUT    */
-    cf2_escGET,          /* 21     like otherGET    */
-    cf2_escIFELSE,       /* 22     like otherIFELSE */
-    cf2_escRANDOM,       /* 23     like otherRANDOM */
-    cf2_escMUL,          /* 24     like otherMUL    */
-    cf2_escRESERVED_25,  /* 25 */
-    cf2_escSQRT,         /* 26 */
-    cf2_escDUP,          /* 27     like otherDUP    */
-    cf2_escEXCH,         /* 28     like otherEXCH   */
-    cf2_escINDEX,        /* 29 */
-    cf2_escROLL,         /* 30 */
-    cf2_escRESERVED_31,  /* 31 */
-    cf2_escRESERVED_32,  /* 32 */
-    cf2_escRESERVED_33,  /* 33 */
-    cf2_escHFLEX,        /* 34 */
-    cf2_escFLEX,         /* 35 */
-    cf2_escHFLEX1,       /* 36 */
-    cf2_escFLEX1,        /* 37 */
-    cf2_escRESERVED_38   /* 38     & all higher     */
-  };
-
-
-  /* `stemHintArray' does not change once we start drawing the outline. */
-  static void
-  cf2_doStems( const CF2_Font  font,
-               CF2_Stack       opStack,
-               CF2_ArrStack    stemHintArray,
-               CF2_Fixed*      width,
-               FT_Bool*        haveWidth,
-               CF2_Fixed       hintOffset )
-  {
-    CF2_UInt  i;
-    CF2_UInt  count       = cf2_stack_count( opStack );
-    FT_Bool   hasWidthArg = (FT_Bool)( count & 1 );
-
-    /* variable accumulates delta values from operand stack */
-    CF2_Fixed  position = hintOffset;
-
-
-    if ( hasWidthArg && !*haveWidth )
-      *width = cf2_stack_getReal( opStack, 0 ) +
-                 cf2_getNominalWidthX( font->decoder );
-
-    if ( font->decoder->width_only )
-      goto exit;
-
-    for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 )
-    {
-      /* construct a CF2_StemHint and push it onto the list */
-      CF2_StemHintRec  stemhint;
-
-
-      stemhint.min =
-      position     = ADD_INT32( position,
-                                cf2_stack_getReal( opStack, i ) );
-      stemhint.max =
-      position     = ADD_INT32( position,
-                                cf2_stack_getReal( opStack, i + 1 ) );
-
-      stemhint.used  = FALSE;
-      stemhint.maxDS =
-      stemhint.minDS = 0;
-
-      cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */
-    }
-
-    cf2_stack_clear( opStack );
-
-  exit:
-    /* cf2_doStems must define a width (may be default) */
-    *haveWidth = TRUE;
-  }
-
-
-  static void
-  cf2_doFlex( CF2_Stack       opStack,
-              CF2_Fixed*      curX,
-              CF2_Fixed*      curY,
-              CF2_GlyphPath   glyphPath,
-              const FT_Bool*  readFromStack,
-              FT_Bool         doConditionalLastRead )
-  {
-    CF2_Fixed  vals[14];
-    CF2_UInt   idx;
-    FT_Bool    isHFlex;
-    CF2_Int    top, i, j;
-
-
-    vals[0] = *curX;
-    vals[1] = *curY;
-    idx     = 0;
-    isHFlex = FT_BOOL( readFromStack[9] == FALSE );
-    top     = isHFlex ? 9 : 10;
-
-    for ( i = 0; i < top; i++ )
-    {
-      vals[i + 2] = vals[i];
-      if ( readFromStack[i] )
-        vals[i + 2] = ADD_INT32( vals[i + 2], cf2_stack_getReal( opStack,
-                                                                 idx++ ) );
-    }
-
-    if ( isHFlex )
-      vals[9 + 2] = *curY;
-
-    if ( doConditionalLastRead )
-    {
-      FT_Bool    lastIsX = (FT_Bool)(
-                             cf2_fixedAbs( SUB_INT32( vals[10], *curX ) ) >
-                             cf2_fixedAbs( SUB_INT32( vals[11], *curY ) ) );
-      CF2_Fixed  lastVal = cf2_stack_getReal( opStack, idx );
-
-
-      if ( lastIsX )
-      {
-        vals[12] = ADD_INT32( vals[10], lastVal );
-        vals[13] = *curY;
-      }
-      else
-      {
-        vals[12] = *curX;
-        vals[13] = ADD_INT32( vals[11], lastVal );
-      }
-    }
-    else
-    {
-      if ( readFromStack[10] )
-        vals[12] = ADD_INT32( vals[10],
-                              cf2_stack_getReal( opStack, idx++ ) );
-      else
-        vals[12] = *curX;
-
-      if ( readFromStack[11] )
-        vals[13] = ADD_INT32( vals[11],
-                              cf2_stack_getReal( opStack, idx ) );
-      else
-        vals[13] = *curY;
-    }
-
-    for ( j = 0; j < 2; j++ )
-      cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2],
-                                        vals[j * 6 + 3],
-                                        vals[j * 6 + 4],
-                                        vals[j * 6 + 5],
-                                        vals[j * 6 + 6],
-                                        vals[j * 6 + 7] );
-
-    cf2_stack_clear( opStack );
-
-    *curX = vals[12];
-    *curY = vals[13];
-  }
-
-
-  /* Blend numOperands on the stack,                */
-  /* store results into the first numBlends values, */
-  /* then pop remaining arguments.                  */
-  static void
-  cf2_doBlend( const CFF_Blend  blend,
-               CF2_Stack        opStack,
-               CF2_UInt         numBlends )
-  {
-    CF2_UInt  delta;
-    CF2_UInt  base;
-    CF2_UInt  i, j;
-    CF2_UInt  numOperands = (CF2_UInt)( numBlends * blend->lenBV );
-
-
-    base  = cf2_stack_count( opStack ) - numOperands;
-    delta = base + numBlends;
-
-    for ( i = 0; i < numBlends; i++ )
-    {
-      const CF2_Fixed*  weight = &blend->BV[1];
-
-      /* start with first term */
-      CF2_Fixed  sum = cf2_stack_getReal( opStack, i + base );
-
-
-      for ( j = 1; j < blend->lenBV; j++ )
-        sum = ADD_INT32( sum,
-                         FT_MulFix( *weight++,
-                                    cf2_stack_getReal( opStack,
-                                                       delta++ ) ) );
-
-      /* store blended result  */
-      cf2_stack_setReal( opStack, i + base, sum );
-    }
-
-    /* leave only `numBlends' results on stack */
-    cf2_stack_pop( opStack, numOperands - numBlends );
-  }
-
-
-  /*
-   * `error' is a shared error code used by many objects in this
-   * routine.  Before the code continues from an error, it must check and
-   * record the error in `*error'.  The idea is that this shared
-   * error code will record the first error encountered.  If testing
-   * for an error anyway, the cost of `goto exit' is small, so we do it,
-   * even if continuing would be safe.  In this case, `lastError' is
-   * set, so the testing and storing can be done in one place, at `exit'.
-   *
-   * Continuing after an error is intended for objects which do their own
-   * testing of `*error', e.g., array stack functions.  This allows us to
-   * avoid an extra test after the call.
-   *
-   * Unimplemented opcodes are ignored.
-   *
-   */
-  FT_LOCAL_DEF( void )
-  cf2_interpT2CharString( CF2_Font              font,
-                          CF2_Buffer            buf,
-                          CF2_OutlineCallbacks  callbacks,
-                          const FT_Vector*      translation,
-                          FT_Bool               doingSeac,
-                          CF2_Fixed             curX,
-                          CF2_Fixed             curY,
-                          CF2_Fixed*            width )
-  {
-    /* lastError is used for errors that are immediately tested */
-    FT_Error  lastError = FT_Err_Ok;
-
-    /* pointer to parsed font object */
-    CFF_Decoder*  decoder = font->decoder;
-
-    FT_Error*  error  = &font->error;
-    FT_Memory  memory = font->memory;
-
-    CF2_Fixed  scaleY        = font->innerTransform.d;
-    CF2_Fixed  nominalWidthX = cf2_getNominalWidthX( decoder );
-
-    /* save this for hinting seac accents */
-    CF2_Fixed  hintOriginY = curY;
-
-    CF2_Stack  opStack = NULL;
-    FT_UInt    stackSize;
-    FT_Byte    op1;                       /* first opcode byte */
-
-    CF2_F16Dot16  storage[CF2_STORAGE_SIZE];    /* for `put' and `get' */
-
-    /* instruction limit; 20,000,000 matches Avalon */
-    FT_UInt32  instructionLimit = 20000000UL;
-
-    CF2_ArrStackRec  subrStack;
-
-    FT_Bool     haveWidth;
-    CF2_Buffer  charstring = NULL;
-
-    CF2_Int  charstringIndex = -1;       /* initialize to empty */
-
-    /* TODO: placeholders for hint structures */
-
-    /* objects used for hinting */
-    CF2_ArrStackRec  hStemHintArray;
-    CF2_ArrStackRec  vStemHintArray;
-
-    CF2_HintMaskRec   hintMask;
-    CF2_GlyphPathRec  glyphPath;
-
-
-    FT_ZERO( &storage );
-
-    /* initialize the remaining objects */
-    cf2_arrstack_init( &subrStack,
-                       memory,
-                       error,
-                       sizeof ( CF2_BufferRec ) );
-    cf2_arrstack_init( &hStemHintArray,
-                       memory,
-                       error,
-                       sizeof ( CF2_StemHintRec ) );
-    cf2_arrstack_init( &vStemHintArray,
-                       memory,
-                       error,
-                       sizeof ( CF2_StemHintRec ) );
-
-    /* initialize CF2_StemHint arrays */
-    cf2_hintmask_init( &hintMask, error );
-
-    /* initialize path map to manage drawing operations */
-
-    /* Note: last 4 params are used to handle `MoveToPermissive', which */
-    /*       may need to call `hintMap.Build'                           */
-    /* TODO: MoveToPermissive is gone; are these still needed?          */
-    cf2_glyphpath_init( &glyphPath,
-                        font,
-                        callbacks,
-                        scaleY,
-                        /* hShift, */
-                        &hStemHintArray,
-                        &vStemHintArray,
-                        &hintMask,
-                        hintOriginY,
-                        &font->blues,
-                        translation );
-
-    /*
-     * Initialize state for width parsing.  From the CFF Spec:
-     *
-     *   The first stack-clearing operator, which must be one of hstem,
-     *   hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
-     *   rmoveto, or endchar, takes an additional argument - the width (as
-     *   described earlier), which may be expressed as zero or one numeric
-     *   argument.
-     *
-     * What we implement here uses the first validly specified width, but
-     * does not detect errors for specifying more than one width.
-     *
-     * If one of the above operators occurs without explicitly specifying
-     * a width, we assume the default width.
-     *
-     * CFF2 charstrings always return the default width (0).
-     *
-     */
-    haveWidth = font->isCFF2 ? TRUE : FALSE;
-    *width    = cf2_getDefaultWidthX( decoder );
-
-    /*
-     * Note: At this point, all pointers to resources must be NULL
-     *       and all local objects must be initialized.
-     *       There must be no branches to `exit:' above this point.
-     *
-     */
-
-    /* allocate an operand stack */
-    stackSize = font->isCFF2 ? cf2_getMaxstack( decoder )
-                             : CF2_OPERAND_STACK_SIZE;
-    opStack   = cf2_stack_init( memory, error, stackSize );
-
-    if ( !opStack )
-    {
-      lastError = FT_THROW( Out_Of_Memory );
-      goto exit;
-    }
-
-    /* initialize subroutine stack by placing top level charstring as */
-    /* first element (max depth plus one for the charstring)          */
-    /* Note: Caller owns and must finalize the first charstring.      */
-    /*       Our copy of it does not change that requirement.         */
-    cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
-
-    charstring  = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
-    *charstring = *buf;    /* structure copy */
-
-    charstringIndex = 0;       /* entry is valid now */
-
-    /* catch errors so far */
-    if ( *error )
-      goto exit;
-
-    /* main interpreter loop */
-    while ( 1 )
-    {
-      if ( cf2_buf_isEnd( charstring ) )
-      {
-        /* If we've reached the end of the charstring, simulate a */
-        /* cf2_cmdRETURN or cf2_cmdENDCHAR.                       */
-        /* We do this for both CFF and CFF2.                      */
-        if ( charstringIndex )
-          op1 = cf2_cmdRETURN;  /* end of buffer for subroutine */
-        else
-          op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
-      }
-      else
-      {
-        op1 = (FT_Byte)cf2_buf_readByte( charstring );
-
-        /* Explicit RETURN and ENDCHAR in CFF2 should be ignored. */
-        /* Note: Trace message will report 0 instead of 11 or 14. */
-        if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) &&
-             font->isCFF2                                      )
-          op1 = cf2_cmdRESERVED_0;
-      }
-
-      /* check for errors once per loop */
-      if ( *error )
-        goto exit;
-
-      instructionLimit--;
-      if ( instructionLimit == 0 )
-      {
-        lastError = FT_THROW( Invalid_Glyph_Format );
-        goto exit;
-      }
-
-      switch( op1 )
-      {
-      case cf2_cmdRESERVED_0:
-      case cf2_cmdRESERVED_2:
-      case cf2_cmdRESERVED_9:
-      case cf2_cmdRESERVED_13:
-      case cf2_cmdRESERVED_17:
-        /* we may get here if we have a prior error */
-        FT_TRACE4(( " unknown op (%d)\n", op1 ));
-        break;
-
-      case cf2_cmdVSINDEX:
-        FT_TRACE4(( " vsindex\n" ));
-
-        if ( !font->isCFF2 )
-          break;    /* clear stack & ignore */
-
-        if ( font->blend.usedBV )
-        {
-          /* vsindex not allowed after blend */
-          lastError = FT_THROW( Invalid_Glyph_Format );
-          goto exit;
-        }
-
-        {
-          FT_Int  temp = cf2_stack_popInt( opStack );
-
-
-          if ( temp >= 0 )
-            font->vsindex = (FT_UInt)temp;
-        }
-        break;
-
-      case cf2_cmdBLEND:
-        {
-          FT_UInt  numBlends;
-
-
-          FT_TRACE4(( " blend\n" ));
-
-          if ( !font->isCFF2 )
-            break;    /* clear stack & ignore */
-
-          /* do we have a `blend' op in a non-variant font? */
-          if ( !font->blend.font )
-          {
-            lastError = FT_THROW( Invalid_Glyph_Format );
-            goto exit;
-          }
-
-          /* check cached blend vector */
-          if ( font->cffload->blend_check_vector( &font->blend,
-                                                  font->vsindex,
-                                                  font->lenNDV,
-                                                  font->NDV ) )
-          {
-            lastError = font->cffload->blend_build_vector( &font->blend,
-                                                           font->vsindex,
-                                                           font->lenNDV,
-                                                           font->NDV );
-            if ( lastError )
-              goto exit;
-          }
-
-          /* do the blend */
-          numBlends = (FT_UInt)cf2_stack_popInt( opStack );
-          if ( numBlends > stackSize )
-          {
-            lastError = FT_THROW( Invalid_Glyph_Format );
-            goto exit;
-          }
-
-          cf2_doBlend( &font->blend, opStack, numBlends );
-
-          font->blend.usedBV = TRUE;
-        }
-        continue;     /* do not clear the stack */
-
-      case cf2_cmdHSTEMHM:
-      case cf2_cmdHSTEM:
-        FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
-
-        /* never add hints after the mask is computed */
-        if ( cf2_hintmask_isValid( &hintMask ) )
-        {
-          FT_TRACE4(( "cf2_interpT2CharString:"
-                      " invalid horizontal hint mask\n" ));
-          break;
-        }
-
-        cf2_doStems( font,
-                     opStack,
-                     &hStemHintArray,
-                     width,
-                     &haveWidth,
-                     0 );
-
-        if ( font->decoder->width_only )
-          goto exit;
-
-        break;
-
-      case cf2_cmdVSTEMHM:
-      case cf2_cmdVSTEM:
-        FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
-
-        /* never add hints after the mask is computed */
-        if ( cf2_hintmask_isValid( &hintMask ) )
-        {
-          FT_TRACE4(( "cf2_interpT2CharString:"
-                      " invalid vertical hint mask\n" ));
-          break;
-        }
-
-        cf2_doStems( font,
-                     opStack,
-                     &vStemHintArray,
-                     width,
-                     &haveWidth,
-                     0 );
-
-        if ( font->decoder->width_only )
-          goto exit;
-
-        break;
-
-      case cf2_cmdVMOVETO:
-        FT_TRACE4(( " vmoveto\n" ));
-
-        if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
-          *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
-                              nominalWidthX );
-
-        /* width is defined or default after this */
-        haveWidth = TRUE;
-
-        if ( font->decoder->width_only )
-          goto exit;
-
-        curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) );
-
-        cf2_glyphpath_moveTo( &glyphPath, curX, curY );
-
-        break;
-
-      case cf2_cmdRLINETO:
-        {
-          CF2_UInt  idx;
-          CF2_UInt  count = cf2_stack_count( opStack );
-
-
-          FT_TRACE4(( " rlineto\n" ));
-
-          for ( idx = 0; idx < count; idx += 2 )
-          {
-            curX = ADD_INT32( curX, cf2_stack_getReal( opStack,
-                                                       idx + 0 ) );
-            curY = ADD_INT32( curY, cf2_stack_getReal( opStack,
-                                                       idx + 1 ) );
-
-            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
-          }
-
-          cf2_stack_clear( opStack );
-        }
-        continue; /* no need to clear stack again */
-
-      case cf2_cmdHLINETO:
-      case cf2_cmdVLINETO:
-        {
-          CF2_UInt  idx;
-          CF2_UInt  count = cf2_stack_count( opStack );
-
-          FT_Bool  isX = FT_BOOL( op1 == cf2_cmdHLINETO );
-
-
-          FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
-
-          for ( idx = 0; idx < count; idx++ )
-          {
-            CF2_Fixed  v = cf2_stack_getReal( opStack, idx );
-
-
-            if ( isX )
-              curX = ADD_INT32( curX, v );
-            else
-              curY = ADD_INT32( curY, v );
-
-            isX = !isX;
-
-            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
-          }
-
-          cf2_stack_clear( opStack );
-        }
-        continue;
-
-      case cf2_cmdRCURVELINE:
-      case cf2_cmdRRCURVETO:
-        {
-          CF2_UInt  count = cf2_stack_count( opStack );
-          CF2_UInt  idx   = 0;
-
-
-          FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n"
-                                               : " rrcurveto\n" ));
-
-          while ( idx + 6 <= count )
-          {
-            CF2_Fixed  x1, y1, x2, y2, x3, y3;
-
-
-            x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
-            y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY );
-            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 );
-            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 );
-            x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 );
-            y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 );
-
-            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
-
-            curX  = x3;
-            curY  = y3;
-            idx  += 6;
-          }
-
-          if ( op1 == cf2_cmdRCURVELINE )
-          {
-            curX = ADD_INT32( curX, cf2_stack_getReal( opStack,
-                                                       idx + 0 ) );
-            curY = ADD_INT32( curY, cf2_stack_getReal( opStack,
-                                                       idx + 1 ) );
-
-            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
-          }
-
-          cf2_stack_clear( opStack );
-        }
-        continue; /* no need to clear stack again */
-
-      case cf2_cmdCALLGSUBR:
-      case cf2_cmdCALLSUBR:
-        {
-          CF2_Int  subrNum;
-
-
-          FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
-                                              : " callsubr" ));
-
-          if ( charstringIndex > CF2_MAX_SUBR )
-          {
-            /* max subr plus one for charstring */
-            lastError = FT_THROW( Invalid_Glyph_Format );
-            goto exit;                      /* overflow of stack */
-          }
-
-          /* push our current CFF charstring region on subrStack */
-          charstring = (CF2_Buffer)
-                         cf2_arrstack_getPointer(
-                           &subrStack,
-                           (size_t)charstringIndex + 1 );
-
-          /* set up the new CFF region and pointer */
-          subrNum = cf2_stack_popInt( opStack );
-
-          switch ( op1 )
-          {
-          case cf2_cmdCALLGSUBR:
-            FT_TRACE4(( " (idx %d, entering level %d)\n",
-                        subrNum + decoder->globals_bias,
-                        charstringIndex + 1 ));
-
-            if ( cf2_initGlobalRegionBuffer( decoder,
-                                             subrNum,
-                                             charstring ) )
-            {
-              lastError = FT_THROW( Invalid_Glyph_Format );
-              goto exit;  /* subroutine lookup or stream error */
-            }
-            break;
-
-          default:
-            /* cf2_cmdCALLSUBR */
-            FT_TRACE4(( " (idx %d, entering level %d)\n",
-                        subrNum + decoder->locals_bias,
-                        charstringIndex + 1 ));
-
-            if ( cf2_initLocalRegionBuffer( decoder,
-                                            subrNum,
-                                            charstring ) )
-            {
-              lastError = FT_THROW( Invalid_Glyph_Format );
-              goto exit;  /* subroutine lookup or stream error */
-            }
-          }
-
-          charstringIndex += 1;       /* entry is valid now */
-        }
-        continue; /* do not clear the stack */
-
-      case cf2_cmdRETURN:
-        FT_TRACE4(( " return (leaving level %d)\n", charstringIndex ));
-
-        if ( charstringIndex < 1 )
-        {
-          /* Note: cannot return from top charstring */
-          lastError = FT_THROW( Invalid_Glyph_Format );
-          goto exit;                      /* underflow of stack */
-        }
-
-        /* restore position in previous charstring */
-        charstring = (CF2_Buffer)
-                       cf2_arrstack_getPointer(
-                         &subrStack,
-                         (CF2_UInt)--charstringIndex );
-        continue;     /* do not clear the stack */
-
-      case cf2_cmdESC:
-        {
-          FT_Byte  op2 = (FT_Byte)cf2_buf_readByte( charstring );
-
-
-          /* first switch for 2-byte operators handles CFF2      */
-          /* and opcodes that are reserved for both CFF and CFF2 */
-          switch ( op2 )
-          {
-          case cf2_escHFLEX:
-            {
-              static const FT_Bool  readFromStack[12] =
-              {
-                TRUE /* dx1 */, FALSE /* dy1 */,
-                TRUE /* dx2 */, TRUE  /* dy2 */,
-                TRUE /* dx3 */, FALSE /* dy3 */,
-                TRUE /* dx4 */, FALSE /* dy4 */,
-                TRUE /* dx5 */, FALSE /* dy5 */,
-                TRUE /* dx6 */, FALSE /* dy6 */
-              };
-
-
-              FT_TRACE4(( " hflex\n" ));
-
-              cf2_doFlex( opStack,
-                          &curX,
-                          &curY,
-                          &glyphPath,
-                          readFromStack,
-                          FALSE /* doConditionalLastRead */ );
-            }
-            continue;
-
-          case cf2_escFLEX:
-            {
-              static const FT_Bool  readFromStack[12] =
-              {
-                TRUE /* dx1 */, TRUE /* dy1 */,
-                TRUE /* dx2 */, TRUE /* dy2 */,
-                TRUE /* dx3 */, TRUE /* dy3 */,
-                TRUE /* dx4 */, TRUE /* dy4 */,
-                TRUE /* dx5 */, TRUE /* dy5 */,
-                TRUE /* dx6 */, TRUE /* dy6 */
-              };
-
-
-              FT_TRACE4(( " flex\n" ));
-
-              cf2_doFlex( opStack,
-                          &curX,
-                          &curY,
-                          &glyphPath,
-                          readFromStack,
-                          FALSE /* doConditionalLastRead */ );
-            }
-            break;      /* TODO: why is this not a continue? */
-
-          case cf2_escHFLEX1:
-            {
-              static const FT_Bool  readFromStack[12] =
-              {
-                TRUE /* dx1 */, TRUE  /* dy1 */,
-                TRUE /* dx2 */, TRUE  /* dy2 */,
-                TRUE /* dx3 */, FALSE /* dy3 */,
-                TRUE /* dx4 */, FALSE /* dy4 */,
-                TRUE /* dx5 */, TRUE  /* dy5 */,
-                TRUE /* dx6 */, FALSE /* dy6 */
-              };
-
-
-              FT_TRACE4(( " hflex1\n" ));
-
-              cf2_doFlex( opStack,
-                          &curX,
-                          &curY,
-                          &glyphPath,
-                          readFromStack,
-                          FALSE /* doConditionalLastRead */ );
-            }
-            continue;
-
-          case cf2_escFLEX1:
-            {
-              static const FT_Bool  readFromStack[12] =
-              {
-                TRUE  /* dx1 */, TRUE  /* dy1 */,
-                TRUE  /* dx2 */, TRUE  /* dy2 */,
-                TRUE  /* dx3 */, TRUE  /* dy3 */,
-                TRUE  /* dx4 */, TRUE  /* dy4 */,
-                TRUE  /* dx5 */, TRUE  /* dy5 */,
-                FALSE /* dx6 */, FALSE /* dy6 */
-              };
-
-
-              FT_TRACE4(( " flex1\n" ));
-
-              cf2_doFlex( opStack,
-                          &curX,
-                          &curY,
-                          &glyphPath,
-                          readFromStack,
-                          TRUE /* doConditionalLastRead */ );
-            }
-            continue;
-
-          /* these opcodes are reserved in both CFF & CFF2 */
-          case cf2_escRESERVED_1:
-          case cf2_escRESERVED_2:
-          case cf2_escRESERVED_6:
-          case cf2_escRESERVED_7:
-          case cf2_escRESERVED_8:
-          case cf2_escRESERVED_13:
-          case cf2_escRESERVED_16:
-          case cf2_escRESERVED_17:
-          case cf2_escRESERVED_19:
-          case cf2_escRESERVED_25:
-          case cf2_escRESERVED_31:
-          case cf2_escRESERVED_32:
-          case cf2_escRESERVED_33:
-            FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
-            break;
-
-          default:
-            {
-              if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 )
-                FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
-              else
-              {
-                /* second switch for 2-byte operators handles just CFF */
-                switch ( op2 )
-                {
-
-                case cf2_escDOTSECTION:
-                  /* something about `flip type of locking' -- ignore it */
-                  FT_TRACE4(( " dotsection\n" ));
-
-                  break;
-
-                case cf2_escAND:
-                  {
-                    CF2_F16Dot16  arg1;
-                    CF2_F16Dot16  arg2;
-
-
-                    FT_TRACE4(( " and\n" ));
-
-                    arg2 = cf2_stack_popFixed( opStack );
-                    arg1 = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushInt( opStack, arg1 && arg2 );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escOR:
-                  {
-                    CF2_F16Dot16  arg1;
-                    CF2_F16Dot16  arg2;
-
-
-                    FT_TRACE4(( " or\n" ));
-
-                    arg2 = cf2_stack_popFixed( opStack );
-                    arg1 = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushInt( opStack, arg1 || arg2 );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escNOT:
-                  {
-                    CF2_F16Dot16  arg;
-
-
-                    FT_TRACE4(( " not\n" ));
-
-                    arg = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushInt( opStack, !arg );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escABS:
-                  {
-                    CF2_F16Dot16  arg;
-
-
-                    FT_TRACE4(( " abs\n" ));
-
-                    arg = cf2_stack_popFixed( opStack );
-
-                    if ( arg < -CF2_FIXED_MAX )
-                      cf2_stack_pushFixed( opStack, CF2_FIXED_MAX );
-                    else
-                      cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escADD:
-                  {
-                    CF2_F16Dot16  summand1;
-                    CF2_F16Dot16  summand2;
-
-
-                    FT_TRACE4(( " add\n" ));
-
-                    summand2 = cf2_stack_popFixed( opStack );
-                    summand1 = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushFixed( opStack,
-                                         ADD_INT32( summand1,
-                                                    summand2 ) );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escSUB:
-                  {
-                    CF2_F16Dot16  minuend;
-                    CF2_F16Dot16  subtrahend;
-
-
-                    FT_TRACE4(( " sub\n" ));
-
-                    subtrahend = cf2_stack_popFixed( opStack );
-                    minuend    = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushFixed( opStack,
-                                         SUB_INT32( minuend, subtrahend ) );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escDIV:
-                  {
-                    CF2_F16Dot16  dividend;
-                    CF2_F16Dot16  divisor;
-
-
-                    FT_TRACE4(( " div\n" ));
-
-                    divisor  = cf2_stack_popFixed( opStack );
-                    dividend = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushFixed( opStack,
-                                         FT_DivFix( dividend, divisor ) );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escNEG:
-                  {
-                    CF2_F16Dot16  arg;
-
-
-                    FT_TRACE4(( " neg\n" ));
-
-                    arg = cf2_stack_popFixed( opStack );
-
-                    if ( arg < -CF2_FIXED_MAX )
-                      cf2_stack_pushFixed( opStack, CF2_FIXED_MAX );
-                    else
-                      cf2_stack_pushFixed( opStack, -arg );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escEQ:
-                  {
-                    CF2_F16Dot16  arg1;
-                    CF2_F16Dot16  arg2;
-
-
-                    FT_TRACE4(( " eq\n" ));
-
-                    arg2 = cf2_stack_popFixed( opStack );
-                    arg1 = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushInt( opStack, arg1 == arg2 );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escDROP:
-                  FT_TRACE4(( " drop\n" ));
-
-                  (void)cf2_stack_popFixed( opStack );
-                  continue; /* do not clear the stack */
-
-                case cf2_escPUT:
-                  {
-                    CF2_F16Dot16  val;
-                    CF2_Int       idx;
-
-
-                    FT_TRACE4(( " put\n" ));
-
-                    idx = cf2_stack_popInt( opStack );
-                    val = cf2_stack_popFixed( opStack );
-
-                    if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
-                      storage[idx] = val;
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escGET:
-                  {
-                    CF2_Int  idx;
-
-
-                    FT_TRACE4(( " get\n" ));
-
-                    idx = cf2_stack_popInt( opStack );
-
-                    if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
-                      cf2_stack_pushFixed( opStack, storage[idx] );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escIFELSE:
-                  {
-                    CF2_F16Dot16  arg1;
-                    CF2_F16Dot16  arg2;
-                    CF2_F16Dot16  cond1;
-                    CF2_F16Dot16  cond2;
-
-
-                    FT_TRACE4(( " ifelse\n" ));
-
-                    cond2 = cf2_stack_popFixed( opStack );
-                    cond1 = cf2_stack_popFixed( opStack );
-                    arg2  = cf2_stack_popFixed( opStack );
-                    arg1  = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushFixed( opStack,
-                                         cond1 <= cond2 ? arg1 : arg2 );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escRANDOM: /* in spec */
-                  {
-                    CF2_F16Dot16  r;
-
-
-                    FT_TRACE4(( " random\n" ));
-
-                    /* only use the lower 16 bits of `random'  */
-                    /* to generate a number in the range (0;1] */
-                    r = (CF2_F16Dot16)
-                          ( ( decoder->current_subfont->random & 0xFFFF ) + 1 );
-
-                    decoder->current_subfont->random =
-                      cff_random( decoder->current_subfont->random );
-
-                    cf2_stack_pushFixed( opStack, r );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escMUL:
-                  {
-                    CF2_F16Dot16  factor1;
-                    CF2_F16Dot16  factor2;
-
-
-                    FT_TRACE4(( " mul\n" ));
-
-                    factor2 = cf2_stack_popFixed( opStack );
-                    factor1 = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushFixed( opStack,
-                                         FT_MulFix( factor1, factor2 ) );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escSQRT:
-                  {
-                    CF2_F16Dot16  arg;
-
-
-                    FT_TRACE4(( " sqrt\n" ));
-
-                    arg = cf2_stack_popFixed( opStack );
-                    if ( arg > 0 )
-                    {
-                      /* use a start value that doesn't make */
-                      /* the algorithm's addition overflow   */
-                      FT_Fixed  root = arg < 10 ? arg : arg >> 1;
-                      FT_Fixed  new_root;
-
-
-                      /* Babylonian method */
-                      for (;;)
-                      {
-                        new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
-                        if ( new_root == root )
-                          break;
-                        root = new_root;
-                      }
-                      arg = new_root;
-                    }
-                    else
-                      arg = 0;
-
-                    cf2_stack_pushFixed( opStack, arg );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escDUP:
-                  {
-                    CF2_F16Dot16  arg;
-
-
-                    FT_TRACE4(( " dup\n" ));
-
-                    arg = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushFixed( opStack, arg );
-                    cf2_stack_pushFixed( opStack, arg );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escEXCH:
-                  {
-                    CF2_F16Dot16  arg1;
-                    CF2_F16Dot16  arg2;
-
-
-                    FT_TRACE4(( " exch\n" ));
-
-                    arg2 = cf2_stack_popFixed( opStack );
-                    arg1 = cf2_stack_popFixed( opStack );
-
-                    cf2_stack_pushFixed( opStack, arg2 );
-                    cf2_stack_pushFixed( opStack, arg1 );
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escINDEX:
-                  {
-                    CF2_Int   idx;
-                    CF2_UInt  size;
-
-
-                    FT_TRACE4(( " index\n" ));
-
-                    idx  = cf2_stack_popInt( opStack );
-                    size = cf2_stack_count( opStack );
-
-                    if ( size > 0 )
-                    {
-                      /* for `cf2_stack_getReal',   */
-                      /* index 0 is bottom of stack */
-                      CF2_UInt  gr_idx;
-
-
-                      if ( idx < 0 )
-                        gr_idx = size - 1;
-                      else if ( (CF2_UInt)idx >= size )
-                        gr_idx = 0;
-                      else
-                        gr_idx = size - 1 - (CF2_UInt)idx;
-
-                      cf2_stack_pushFixed( opStack,
-                                           cf2_stack_getReal( opStack,
-                                                              gr_idx ) );
-                    }
-                  }
-                  continue; /* do not clear the stack */
-
-                case cf2_escROLL:
-                  {
-                    CF2_Int  idx;
-                    CF2_Int  count;
-
-
-                    FT_TRACE4(( " roll\n" ));
-
-                    idx   = cf2_stack_popInt( opStack );
-                    count = cf2_stack_popInt( opStack );
-
-                    cf2_stack_roll( opStack, count, idx );
-                  }
-                  continue; /* do not clear the stack */
-
-                } /* end of 2nd switch checking op2 */
-              }
-            }
-          } /* end of 1st switch checking op2 */
-        } /* case cf2_cmdESC */
-
-        break;
-
-      case cf2_cmdENDCHAR:
-        FT_TRACE4(( " endchar\n" ));
-
-        if ( cf2_stack_count( opStack ) == 1 ||
-             cf2_stack_count( opStack ) == 5 )
-        {
-          if ( !haveWidth )
-            *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
-                                nominalWidthX );
-        }
-
-        /* width is defined or default after this */
-        haveWidth = TRUE;
-
-        if ( font->decoder->width_only )
-          goto exit;
-
-        /* close path if still open */
-        cf2_glyphpath_closeOpenPath( &glyphPath );
-
-        /* disable seac for CFF2 (charstring ending with args on stack) */
-        if ( !font->isCFF2 && cf2_stack_count( opStack ) > 1 )
-        {
-          /* must be either 4 or 5 --                       */
-          /* this is a (deprecated) implied `seac' operator */
-
-          CF2_Int        achar;
-          CF2_Int        bchar;
-          CF2_BufferRec  component;
-          CF2_Fixed      dummyWidth;   /* ignore component width */
-          FT_Error       error2;
-
-
-          if ( doingSeac )
-          {
-            lastError = FT_THROW( Invalid_Glyph_Format );
-            goto exit;      /* nested seac */
-          }
-
-          achar = cf2_stack_popInt( opStack );
-          bchar = cf2_stack_popInt( opStack );
-
-          curY = cf2_stack_popFixed( opStack );
-          curX = cf2_stack_popFixed( opStack );
-
-          error2 = cf2_getSeacComponent( decoder, achar, &component );
-          if ( error2 )
-          {
-            lastError = error2;      /* pass FreeType error through */
-            goto exit;
-          }
-          cf2_interpT2CharString( font,
-                                  &component,
-                                  callbacks,
-                                  translation,
-                                  TRUE,
-                                  curX,
-                                  curY,
-                                  &dummyWidth );
-          cf2_freeSeacComponent( decoder, &component );
-
-          error2 = cf2_getSeacComponent( decoder, bchar, &component );
-          if ( error2 )
-          {
-            lastError = error2;      /* pass FreeType error through */
-            goto exit;
-          }
-          cf2_interpT2CharString( font,
-                                  &component,
-                                  callbacks,
-                                  translation,
-                                  TRUE,
-                                  0,
-                                  0,
-                                  &dummyWidth );
-          cf2_freeSeacComponent( decoder, &component );
-        }
-        goto exit;
-
-      case cf2_cmdCNTRMASK:
-      case cf2_cmdHINTMASK:
-        /* the final \n in the tracing message gets added in      */
-        /* `cf2_hintmask_read' (which also traces the mask bytes) */
-        FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
-
-        /* never add hints after the mask is computed */
-        if ( cf2_stack_count( opStack ) > 1    &&
-             cf2_hintmask_isValid( &hintMask ) )
-        {
-          FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
-          break;
-        }
-
-        /* if there are arguments on the stack, there this is an */
-        /* implied cf2_cmdVSTEMHM                                */
-        cf2_doStems( font,
-                     opStack,
-                     &vStemHintArray,
-                     width,
-                     &haveWidth,
-                     0 );
-
-        if ( font->decoder->width_only )
-          goto exit;
-
-        if ( op1 == cf2_cmdHINTMASK )
-        {
-          /* consume the hint mask bytes which follow the operator */
-          cf2_hintmask_read( &hintMask,
-                             charstring,
-                             cf2_arrstack_size( &hStemHintArray ) +
-                               cf2_arrstack_size( &vStemHintArray ) );
-        }
-        else
-        {
-          /*
-           * Consume the counter mask bytes which follow the operator:
-           * Build a temporary hint map, just to place and lock those
-           * stems participating in the counter mask.  These are most
-           * likely the dominant hstems, and are grouped together in a
-           * few counter groups, not necessarily in correspondence
-           * with the hint groups.  This reduces the chances of
-           * conflicts between hstems that are initially placed in
-           * separate hint groups and then brought together.  The
-           * positions are copied back to `hStemHintArray', so we can
-           * discard `counterMask' and `counterHintMap'.
-           *
-           */
-          CF2_HintMapRec   counterHintMap;
-          CF2_HintMaskRec  counterMask;
-
-
-          cf2_hintmap_init( &counterHintMap,
-                            font,
-                            &glyphPath.initialHintMap,
-                            &glyphPath.hintMoves,
-                            scaleY );
-          cf2_hintmask_init( &counterMask, error );
-
-          cf2_hintmask_read( &counterMask,
-                             charstring,
-                             cf2_arrstack_size( &hStemHintArray ) +
-                               cf2_arrstack_size( &vStemHintArray ) );
-          cf2_hintmap_build( &counterHintMap,
-                             &hStemHintArray,
-                             &vStemHintArray,
-                             &counterMask,
-                             0,
-                             FALSE );
-        }
-        break;
-
-      case cf2_cmdRMOVETO:
-        FT_TRACE4(( " rmoveto\n" ));
-
-        if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
-          *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
-                              nominalWidthX );
-
-        /* width is defined or default after this */
-        haveWidth = TRUE;
-
-        if ( font->decoder->width_only )
-          goto exit;
-
-        curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) );
-        curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) );
-
-        cf2_glyphpath_moveTo( &glyphPath, curX, curY );
-
-        break;
-
-      case cf2_cmdHMOVETO:
-        FT_TRACE4(( " hmoveto\n" ));
-
-        if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
-          *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
-                              nominalWidthX );
-
-        /* width is defined or default after this */
-        haveWidth = TRUE;
-
-        if ( font->decoder->width_only )
-          goto exit;
-
-        curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) );
-
-        cf2_glyphpath_moveTo( &glyphPath, curX, curY );
-
-        break;
-
-      case cf2_cmdRLINECURVE:
-        {
-          CF2_UInt  count = cf2_stack_count( opStack );
-          CF2_UInt  idx   = 0;
-
-
-          FT_TRACE4(( " rlinecurve\n" ));
-
-          while ( idx + 6 < count )
-          {
-            curX = ADD_INT32( curX, cf2_stack_getReal( opStack,
-                                                       idx + 0 ) );
-            curY = ADD_INT32( curY, cf2_stack_getReal( opStack,
-                                                       idx + 1 ) );
-
-            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
-            idx += 2;
-          }
-
-          while ( idx < count )
-          {
-            CF2_Fixed  x1, y1, x2, y2, x3, y3;
-
-
-            x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
-            y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY );
-            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 );
-            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 );
-            x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 );
-            y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 );
-
-            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
-
-            curX  = x3;
-            curY  = y3;
-            idx  += 6;
-          }
-
-          cf2_stack_clear( opStack );
-        }
-        continue; /* no need to clear stack again */
-
-      case cf2_cmdVVCURVETO:
-        {
-          CF2_UInt  count, count1 = cf2_stack_count( opStack );
-          CF2_UInt  idx = 0;
-
-
-          /* 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 & ~2U;
-          idx  += count1 - count;
-
-          FT_TRACE4(( " vvcurveto\n" ));
-
-          while ( idx < count )
-          {
-            CF2_Fixed  x1, y1, x2, y2, x3, y3;
-
-
-            if ( ( count - idx ) & 1 )
-            {
-              x1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curX );
-
-              idx++;
-            }
-            else
-              x1 = curX;
-
-            y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY );
-            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
-            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
-            x3 = x2;
-            y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 );
-
-            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
-
-            curX  = x3;
-            curY  = y3;
-            idx  += 4;
-          }
-
-          cf2_stack_clear( opStack );
-        }
-        continue; /* no need to clear stack again */
-
-      case cf2_cmdHHCURVETO:
-        {
-          CF2_UInt  count, count1 = cf2_stack_count( opStack );
-          CF2_UInt  idx = 0;
-
-
-          /* 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 & ~2U;
-          idx  += count1 - count;
-
-          FT_TRACE4(( " hhcurveto\n" ));
-
-          while ( idx < count )
-          {
-            CF2_Fixed  x1, y1, x2, y2, x3, y3;
-
-
-            if ( ( count - idx ) & 1 )
-            {
-              y1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curY );
-
-              idx++;
-            }
-            else
-              y1 = curY;
-
-            x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
-            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
-            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
-            x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 );
-            y3 = y2;
-
-            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
-
-            curX  = x3;
-            curY  = y3;
-            idx  += 4;
-          }
-
-          cf2_stack_clear( opStack );
-        }
-        continue; /* no need to clear stack again */
-
-      case cf2_cmdVHCURVETO:
-      case cf2_cmdHVCURVETO:
-        {
-          CF2_UInt  count, count1 = cf2_stack_count( opStack );
-          CF2_UInt  idx = 0;
-
-          FT_Bool  alternate = FT_BOOL( op1 == cf2_cmdHVCURVETO );
-
-
-          /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */
-          /* 8n+4, or 8n+5, we enforce it by clearing the     */
-          /* second bit                                       */
-          /* (and sorting the stack indexing to suit)         */
-          count = count1 & ~2U;
-          idx  += count1 - count;
-
-          FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
-
-          while ( idx < count )
-          {
-            CF2_Fixed x1, x2, x3, y1, y2, y3;
-
-
-            if ( alternate )
-            {
-              x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
-              y1 = curY;
-              x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
-              y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
-              y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 );
-
-              if ( count - idx == 5 )
-              {
-                x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 );
-
-                idx++;
-              }
-              else
-                x3 = x2;
-
-              alternate = FALSE;
-            }
-            else
-            {
-              x1 = curX;
-              y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY );
-              x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
-              y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
-              x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 );
-
-              if ( count - idx == 5 )
-              {
-                y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), y2 );
-
-                idx++;
-              }
-              else
-                y3 = y2;
-
-              alternate = TRUE;
-            }
-
-            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
-
-            curX  = x3;
-            curY  = y3;
-            idx  += 4;
-          }
-
-          cf2_stack_clear( opStack );
-        }
-        continue;     /* no need to clear stack again */
-
-      case cf2_cmdEXTENDEDNMBR:
-        {
-          CF2_Int  v;
-
-          CF2_Int  byte1 = cf2_buf_readByte( charstring );
-          CF2_Int  byte2 = cf2_buf_readByte( charstring );
-
-
-          v = (FT_Short)( ( byte1 << 8 ) |
-                            byte2        );
-
-          FT_TRACE4(( " %d", v ));
-
-          cf2_stack_pushInt( opStack, v );
-        }
-        continue;
-
-      default:
-        /* numbers */
-        {
-          if ( /* op1 >= 32 && */ op1 <= 246 )
-          {
-            CF2_Int  v;
-
-
-            v = op1 - 139;
-
-            FT_TRACE4(( " %d", v ));
-
-            /* -107 .. 107 */
-            cf2_stack_pushInt( opStack, v );
-          }
-
-          else if ( /* op1 >= 247 && */ op1 <= 250 )
-          {
-            CF2_Int  v;
-
-
-            v  = op1;
-            v -= 247;
-            v *= 256;
-            v += cf2_buf_readByte( charstring );
-            v += 108;
-
-            FT_TRACE4(( " %d", v ));
-
-            /* 108 .. 1131 */
-            cf2_stack_pushInt( opStack, v );
-          }
-
-          else if ( /* op1 >= 251 && */ op1 <= 254 )
-          {
-            CF2_Int  v;
-
-
-            v  = op1;
-            v -= 251;
-            v *= 256;
-            v += cf2_buf_readByte( charstring );
-            v  = -v - 108;
-
-            FT_TRACE4(( " %d", v ));
-
-            /* -1131 .. -108 */
-            cf2_stack_pushInt( opStack, v );
-          }
-
-          else /* op1 == 255 */
-          {
-            CF2_Fixed  v;
-
-            FT_UInt32  byte1 = (FT_UInt32)cf2_buf_readByte( charstring );
-            FT_UInt32  byte2 = (FT_UInt32)cf2_buf_readByte( charstring );
-            FT_UInt32  byte3 = (FT_UInt32)cf2_buf_readByte( charstring );
-            FT_UInt32  byte4 = (FT_UInt32)cf2_buf_readByte( charstring );
-
-
-            v = (CF2_Fixed)( ( byte1 << 24 ) |
-                             ( byte2 << 16 ) |
-                             ( byte3 <<  8 ) |
-                               byte4         );
-
-            FT_TRACE4(( " %.5f", v / 65536.0 ));
-
-            cf2_stack_pushFixed( opStack, v );
-          }
-        }
-        continue;   /* don't clear stack */
-
-      } /* end of switch statement checking `op1' */
-
-      cf2_stack_clear( opStack );
-
-    } /* end of main interpreter loop */
-
-    /* we get here if the charstring ends without cf2_cmdENDCHAR */
-    FT_TRACE4(( "cf2_interpT2CharString:"
-                "  charstring ends without ENDCHAR\n" ));
-
-  exit:
-    /* check whether last error seen is also the first one */
-    cf2_setError( error, lastError );
-
-    if ( *error )
-      FT_TRACE4(( "charstring error %d\n", *error ));
-
-    /* free resources from objects we've used */
-    cf2_glyphpath_finalize( &glyphPath );
-    cf2_arrstack_finalize( &vStemHintArray );
-    cf2_arrstack_finalize( &hStemHintArray );
-    cf2_arrstack_finalize( &subrStack );
-    cf2_stack_free( opStack );
-
-    FT_TRACE4(( "\n" ));
-
-    return;
-  }
-
-
-/* END */
--- a/src/psaux/cf2intrp.h
+++ /dev/null
@@ -1,83 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2font.h                                                              */
-/*                                                                         */
-/*    Adobe's CFF Interpreter (specification).                             */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2INTRP_H_
-#define CF2INTRP_H_
-
-
-#include "cf2ft.h"
-#include "cf2hints.h"
-
-
-FT_BEGIN_HEADER
-
-
-  FT_LOCAL( void )
-  cf2_hintmask_init( CF2_HintMask  hintmask,
-                     FT_Error*     error );
-  FT_LOCAL( FT_Bool )
-  cf2_hintmask_isValid( const CF2_HintMask  hintmask );
-  FT_LOCAL( FT_Bool )
-  cf2_hintmask_isNew( const CF2_HintMask  hintmask );
-  FT_LOCAL( void )
-  cf2_hintmask_setNew( CF2_HintMask  hintmask,
-                       FT_Bool       val );
-  FT_LOCAL( FT_Byte* )
-  cf2_hintmask_getMaskPtr( CF2_HintMask  hintmask );
-  FT_LOCAL( void )
-  cf2_hintmask_setAll( CF2_HintMask  hintmask,
-                       size_t        bitCount );
-
-  FT_LOCAL( void )
-  cf2_interpT2CharString( CF2_Font              font,
-                          CF2_Buffer            charstring,
-                          CF2_OutlineCallbacks  callbacks,
-                          const FT_Vector*      translation,
-                          FT_Bool               doingSeac,
-                          CF2_Fixed             curX,
-                          CF2_Fixed             curY,
-                          CF2_Fixed*            width );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2INTRP_H_ */
-
-
-/* END */
--- a/src/psaux/cf2read.c
+++ /dev/null
@@ -1,112 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2read.c                                                              */
-/*                                                                         */
-/*    Adobe's code for stream handling (body).                             */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include FT_INTERNAL_DEBUG_H
-
-#include "cf2glue.h"
-
-#include "cf2error.h"
-
-
-  /* Define CF2_IO_FAIL as 1 to enable random errors and random */
-  /* value errors in I/O.                                       */
-#define CF2_IO_FAIL  0
-
-
-#if CF2_IO_FAIL
-
-  /* set the .00 value to a nonzero probability */
-  static int
-  randomError2( void )
-  {
-    /* for region buffer ReadByte (interp) function */
-    return (double)rand() / RAND_MAX < .00;
-  }
-
-  /* set the .00 value to a nonzero probability */
-  static CF2_Int
-  randomValue()
-  {
-    return (double)rand() / RAND_MAX < .00 ? rand() : 0;
-  }
-
-#endif /* CF2_IO_FAIL */
-
-
-  /* Region Buffer                                      */
-  /*                                                    */
-  /* Can be constructed from a copied buffer managed by */
-  /* `FCM_getDatablock'.                                */
-  /* Reads bytes with check for end of buffer.          */
-
-  /* reading past the end of the buffer sets error and returns zero */
-  FT_LOCAL_DEF( CF2_Int )
-  cf2_buf_readByte( CF2_Buffer  buf )
-  {
-    if ( buf->ptr < buf->end )
-    {
-#if CF2_IO_FAIL
-      if ( randomError2() )
-      {
-        CF2_SET_ERROR( buf->error, Invalid_Stream_Operation );
-        return 0;
-      }
-
-      return *(buf->ptr)++ + randomValue();
-#else
-      return *(buf->ptr)++;
-#endif
-    }
-    else
-    {
-      CF2_SET_ERROR( buf->error, Invalid_Stream_Operation );
-      return 0;
-    }
-  }
-
-
-  /* note: end condition can occur without error */
-  FT_LOCAL_DEF( FT_Bool )
-  cf2_buf_isEnd( CF2_Buffer  buf )
-  {
-    return (FT_Bool)( buf->ptr >= buf->end );
-  }
-
-
-/* END */
--- a/src/psaux/cf2read.h
+++ /dev/null
@@ -1,68 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2read.h                                                              */
-/*                                                                         */
-/*    Adobe's code for stream handling (specification).                    */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2READ_H_
-#define CF2READ_H_
-
-
-FT_BEGIN_HEADER
-
-
-  typedef struct  CF2_BufferRec_
-  {
-    FT_Error*       error;
-    const FT_Byte*  start;
-    const FT_Byte*  end;
-    const FT_Byte*  ptr;
-
-  } CF2_BufferRec, *CF2_Buffer;
-
-
-  FT_LOCAL( CF2_Int )
-  cf2_buf_readByte( CF2_Buffer  buf );
-  FT_LOCAL( FT_Bool )
-  cf2_buf_isEnd( CF2_Buffer  buf );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2READ_H_ */
-
-
-/* END */
--- a/src/psaux/cf2stack.c
+++ /dev/null
@@ -1,328 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2stack.c                                                             */
-/*                                                                         */
-/*    Adobe's code for emulating a CFF stack (body).                       */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#include "cf2ft.h"
-#include FT_INTERNAL_DEBUG_H
-
-#include "cf2glue.h"
-#include "cf2font.h"
-#include "cf2stack.h"
-
-#include "cf2error.h"
-
-
-  /* Allocate and initialize an instance of CF2_Stack.       */
-  /* Note: This function returns NULL on error (does not set */
-  /* `error').                                               */
-  FT_LOCAL_DEF( CF2_Stack )
-  cf2_stack_init( FT_Memory  memory,
-                  FT_Error*  e,
-                  FT_UInt    stackSize )
-  {
-    FT_Error  error = FT_Err_Ok;     /* for FT_NEW */
-
-    CF2_Stack  stack = NULL;
-
-
-    if ( !FT_NEW( stack ) )
-    {
-      /* initialize the structure; FT_NEW zeroes it */
-      stack->memory = memory;
-      stack->error  = e;
-    }
-
-    /* allocate the stack buffer */
-    if ( FT_NEW_ARRAY( stack->buffer, stackSize ) )
-    {
-      FT_FREE( stack );
-      return NULL;
-    }
-
-    stack->stackSize = stackSize;
-    stack->top       = stack->buffer;     /* empty stack */
-
-    return stack;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_stack_free( CF2_Stack  stack )
-  {
-    if ( stack )
-    {
-      FT_Memory  memory = stack->memory;
-
-      /* free the buffer */
-      FT_FREE( stack->buffer );
-
-      /* free the main structure */
-      FT_FREE( stack );
-    }
-  }
-
-
-  FT_LOCAL_DEF( CF2_UInt )
-  cf2_stack_count( CF2_Stack  stack )
-  {
-    return (CF2_UInt)( stack->top - stack->buffer );
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_stack_pushInt( CF2_Stack  stack,
-                     CF2_Int    val )
-  {
-    if ( stack->top == stack->buffer + stack->stackSize )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Overflow );
-      return;     /* stack overflow */
-    }
-
-    stack->top->u.i  = val;
-    stack->top->type = CF2_NumberInt;
-    stack->top++;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_stack_pushFixed( CF2_Stack  stack,
-                       CF2_Fixed  val )
-  {
-    if ( stack->top == stack->buffer + stack->stackSize )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Overflow );
-      return;     /* stack overflow */
-    }
-
-    stack->top->u.r  = val;
-    stack->top->type = CF2_NumberFixed;
-    stack->top++;
-  }
-
-
-  /* this function is only allowed to pop an integer type */
-  FT_LOCAL_DEF( CF2_Int )
-  cf2_stack_popInt( CF2_Stack  stack )
-  {
-    if ( stack->top == stack->buffer )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Underflow );
-      return 0;   /* underflow */
-    }
-    if ( stack->top[-1].type != CF2_NumberInt )
-    {
-      CF2_SET_ERROR( stack->error, Syntax_Error );
-      return 0;   /* type mismatch */
-    }
-
-    stack->top--;
-
-    return stack->top->u.i;
-  }
-
-
-  /* Note: type mismatch is silently cast */
-  /* TODO: check this                     */
-  FT_LOCAL_DEF( CF2_Fixed )
-  cf2_stack_popFixed( CF2_Stack  stack )
-  {
-    if ( stack->top == stack->buffer )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Underflow );
-      return cf2_intToFixed( 0 );    /* underflow */
-    }
-
-    stack->top--;
-
-    switch ( stack->top->type )
-    {
-    case CF2_NumberInt:
-      return cf2_intToFixed( stack->top->u.i );
-    case CF2_NumberFrac:
-      return cf2_fracToFixed( stack->top->u.f );
-    default:
-      return stack->top->u.r;
-    }
-  }
-
-
-  /* Note: type mismatch is silently cast */
-  /* TODO: check this                     */
-  FT_LOCAL_DEF( CF2_Fixed )
-  cf2_stack_getReal( CF2_Stack  stack,
-                     CF2_UInt   idx )
-  {
-    FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize );
-
-    if ( idx >= cf2_stack_count( stack ) )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Overflow );
-      return cf2_intToFixed( 0 );    /* bounds error */
-    }
-
-    switch ( stack->buffer[idx].type )
-    {
-    case CF2_NumberInt:
-      return cf2_intToFixed( stack->buffer[idx].u.i );
-    case CF2_NumberFrac:
-      return cf2_fracToFixed( stack->buffer[idx].u.f );
-    default:
-      return stack->buffer[idx].u.r;
-    }
-  }
-
-
-  /* provide random access to stack */
-  FT_LOCAL_DEF( void )
-  cf2_stack_setReal( CF2_Stack  stack,
-                     CF2_UInt   idx,
-                     CF2_Fixed  val )
-  {
-    if ( idx > cf2_stack_count( stack ) )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Overflow );
-      return;
-    }
-
-    stack->buffer[idx].u.r  = val;
-    stack->buffer[idx].type = CF2_NumberFixed;
-  }
-
-
-  /* discard (pop) num values from stack */
-  FT_LOCAL_DEF( void )
-  cf2_stack_pop( CF2_Stack  stack,
-                 CF2_UInt   num )
-  {
-    if ( num > cf2_stack_count( stack ) )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Underflow );
-      return;
-    }
-    stack->top -= num;
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_stack_roll( CF2_Stack  stack,
-                  CF2_Int    count,
-                  CF2_Int    shift )
-  {
-    /* we initialize this variable to avoid compiler warnings */
-    CF2_StackNumber  last = { { 0 }, CF2_NumberInt };
-
-    CF2_Int  start_idx, idx, i;
-
-
-    if ( count < 2 )
-      return; /* nothing to do (values 0 and 1), or undefined value */
-
-    if ( (CF2_UInt)count > cf2_stack_count( stack ) )
-    {
-      CF2_SET_ERROR( stack->error, Stack_Overflow );
-      return;
-    }
-
-    if ( shift < 0 )
-      shift = -( ( -shift ) % count );
-    else
-      shift %= count;
-
-    if ( shift == 0 )
-      return; /* nothing to do */
-
-    /* We use the following algorithm to do the rolling, */
-    /* which needs two temporary variables only.         */
-    /*                                                   */
-    /* Example:                                          */
-    /*                                                   */
-    /*   count = 8                                       */
-    /*   shift = 2                                       */
-    /*                                                   */
-    /*   stack indices before roll:  7 6 5 4 3 2 1 0     */
-    /*   stack indices after roll:   1 0 7 6 5 4 3 2     */
-    /*                                                   */
-    /* The value of index 0 gets moved to index 2, while */
-    /* the old value of index 2 gets moved to index 4,   */
-    /* and so on.  We thus have the following copying    */
-    /* chains for shift value 2.                         */
-    /*                                                   */
-    /*   0 -> 2 -> 4 -> 6 -> 0                           */
-    /*   1 -> 3 -> 5 -> 7 -> 1                           */
-    /*                                                   */
-    /* If `count' and `shift' are incommensurable, we    */
-    /* have a single chain only.  Otherwise, increase    */
-    /* the start index by 1 after the first chain, then  */
-    /* do the next chain until all elements in all       */
-    /* chains are handled.                               */
-
-    start_idx = -1;
-    idx       = -1;
-    for ( i = 0; i < count; i++ )
-    {
-      CF2_StackNumber  tmp;
-
-
-      if ( start_idx == idx )
-      {
-        start_idx++;
-        idx  = start_idx;
-        last = stack->buffer[idx];
-      }
-
-      idx += shift;
-      if ( idx >= count )
-        idx -= count;
-      else if ( idx < 0 )
-        idx += count;
-
-      tmp                = stack->buffer[idx];
-      stack->buffer[idx] = last;
-      last               = tmp;
-    }
-  }
-
-
-  FT_LOCAL_DEF( void )
-  cf2_stack_clear( CF2_Stack  stack )
-  {
-    stack->top = stack->buffer;
-  }
-
-
-/* END */
--- a/src/psaux/cf2stack.h
+++ /dev/null
@@ -1,121 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2stack.h                                                             */
-/*                                                                         */
-/*    Adobe's code for emulating a CFF stack (specification).              */
-/*                                                                         */
-/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2STACK_H_
-#define CF2STACK_H_
-
-
-FT_BEGIN_HEADER
-
-
-  /* CFF operand stack; specified maximum of 48 or 192 values */
-  typedef struct  CF2_StackNumber_
-  {
-    union
-    {
-      CF2_Fixed  r;      /* 16.16 fixed point */
-      CF2_Frac   f;      /* 2.30 fixed point (for font matrix) */
-      CF2_Int    i;
-    } u;
-
-    CF2_NumberType  type;
-
-  } CF2_StackNumber;
-
-
-  typedef struct  CF2_StackRec_
-  {
-    FT_Memory         memory;
-    FT_Error*         error;
-    CF2_StackNumber*  buffer;
-    CF2_StackNumber*  top;
-    FT_UInt           stackSize;
-
-  } CF2_StackRec, *CF2_Stack;
-
-
-  FT_LOCAL( CF2_Stack )
-  cf2_stack_init( FT_Memory  memory,
-                  FT_Error*  error,
-                  FT_UInt    stackSize );
-  FT_LOCAL( void )
-  cf2_stack_free( CF2_Stack  stack );
-
-  FT_LOCAL( CF2_UInt )
-  cf2_stack_count( CF2_Stack  stack );
-
-  FT_LOCAL( void )
-  cf2_stack_pushInt( CF2_Stack  stack,
-                     CF2_Int    val );
-  FT_LOCAL( void )
-  cf2_stack_pushFixed( CF2_Stack  stack,
-                       CF2_Fixed  val );
-
-  FT_LOCAL( CF2_Int )
-  cf2_stack_popInt( CF2_Stack  stack );
-  FT_LOCAL( CF2_Fixed )
-  cf2_stack_popFixed( CF2_Stack  stack );
-
-  FT_LOCAL( CF2_Fixed )
-  cf2_stack_getReal( CF2_Stack  stack,
-                     CF2_UInt   idx );
-  FT_LOCAL( void )
-  cf2_stack_setReal( CF2_Stack  stack,
-                     CF2_UInt   idx,
-                     CF2_Fixed  val );
-
-  FT_LOCAL( void )
-  cf2_stack_pop( CF2_Stack  stack,
-                 CF2_UInt   num );
-
-  FT_LOCAL( void )
-  cf2_stack_roll( CF2_Stack  stack,
-                  CF2_Int    count,
-                  CF2_Int    idx );
-
-  FT_LOCAL( void )
-  cf2_stack_clear( CF2_Stack  stack );
-
-
-FT_END_HEADER
-
-
-#endif /* CF2STACK_H_ */
-
-
-/* END */
--- a/src/psaux/cf2types.h
+++ /dev/null
@@ -1,78 +1,0 @@
-/***************************************************************************/
-/*                                                                         */
-/*  cf2types.h                                                             */
-/*                                                                         */
-/*    Adobe's code for defining data types (specification only).           */
-/*                                                                         */
-/*  Copyright 2011-2013 Adobe Systems Incorporated.                        */
-/*                                                                         */
-/*  This software, and all works of authorship, whether in source or       */
-/*  object code form as indicated by the copyright notice(s) included      */
-/*  herein (collectively, the "Work") is made available, and may only be   */
-/*  used, modified, and distributed under the FreeType Project License,    */
-/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
-/*  FreeType Project License, each contributor to the Work hereby grants   */
-/*  to any individual or legal entity exercising permissions granted by    */
-/*  the FreeType Project License and this section (hereafter, "You" or     */
-/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
-/*  royalty-free, irrevocable (except as stated in this section) patent    */
-/*  license to make, have made, use, offer to sell, sell, import, and      */
-/*  otherwise transfer the Work, where such license applies only to those  */
-/*  patent claims licensable by such contributor that are necessarily      */
-/*  infringed by their contribution(s) alone or by combination of their    */
-/*  contribution(s) with the Work to which such contribution(s) was        */
-/*  submitted.  If You institute patent litigation against any entity      */
-/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
-/*  the Work or a contribution incorporated within the Work constitutes    */
-/*  direct or contributory patent infringement, then any patent licenses   */
-/*  granted to You under this License for that Work shall terminate as of  */
-/*  the date such litigation is filed.                                     */
-/*                                                                         */
-/*  By using, modifying, or distributing the Work you indicate that you    */
-/*  have read and understood the terms and conditions of the               */
-/*  FreeType Project License as well as those provided in this section,    */
-/*  and you accept them fully.                                             */
-/*                                                                         */
-/***************************************************************************/
-
-
-#ifndef CF2TYPES_H_
-#define CF2TYPES_H_
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-
-FT_BEGIN_HEADER
-
-
-  /*
-   * The data models that we expect to support are as follows:
-   *
-   *   name  char short int long long-long pointer example
-   *  -----------------------------------------------------
-   *   ILP32  8    16    32  32     64*      32    32-bit MacOS, x86
-   *   LLP64  8    16    32  32     64       64    x64
-   *   LP64   8    16    32  64     64       64    64-bit MacOS
-   *
-   *    *) type may be supported by emulation on a 32-bit architecture
-   *
-   */
-
-
-  /* integers at least 32 bits wide */
-#define CF2_UInt  FT_UFast
-#define CF2_Int   FT_Fast
-
-
-  /* fixed-float numbers */
-  typedef FT_Int32  CF2_F16Dot16;
-
-
-FT_END_HEADER
-
-
-#endif /* CF2TYPES_H_ */
-
-
-/* END */
--- /dev/null
+++ b/src/psaux/psarrst.c
@@ -1,0 +1,241 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2arrst.c                                                             */
+/*                                                                         */
+/*    Adobe's code for Array Stacks (body).                                */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include FT_INTERNAL_DEBUG_H
+
+#include "psglue.h"
+#include "psarrst.h"
+
+#include "pserror.h"
+
+
+  /*
+   * CF2_ArrStack uses an error pointer, to enable shared errors.
+   * Shared errors are necessary when multiple objects allow the program
+   * to continue after detecting errors.  Only the first error should be
+   * recorded.
+   */
+
+  FT_LOCAL_DEF( void )
+  cf2_arrstack_init( CF2_ArrStack  arrstack,
+                     FT_Memory     memory,
+                     FT_Error*     error,
+                     size_t        sizeItem )
+  {
+    FT_ASSERT( arrstack );
+
+    /* initialize the structure */
+    arrstack->memory    = memory;
+    arrstack->error     = error;
+    arrstack->sizeItem  = sizeItem;
+    arrstack->allocated = 0;
+    arrstack->chunk     = 10;    /* chunks of 10 items */
+    arrstack->count     = 0;
+    arrstack->totalSize = 0;
+    arrstack->ptr       = NULL;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_arrstack_finalize( CF2_ArrStack  arrstack )
+  {
+    FT_Memory  memory = arrstack->memory;     /* for FT_FREE */
+
+
+    FT_ASSERT( arrstack );
+
+    arrstack->allocated = 0;
+    arrstack->count     = 0;
+    arrstack->totalSize = 0;
+
+    /* free the data buffer */
+    FT_FREE( arrstack->ptr );
+  }
+
+
+  /* allocate or reallocate the buffer size; */
+  /* return false on memory error */
+  static FT_Bool
+  cf2_arrstack_setNumElements( CF2_ArrStack  arrstack,
+                               size_t        numElements )
+  {
+    FT_ASSERT( arrstack );
+
+    {
+      FT_Error   error  = FT_Err_Ok;        /* for FT_REALLOC */
+      FT_Memory  memory = arrstack->memory; /* for FT_REALLOC */
+
+      size_t  newSize = numElements * arrstack->sizeItem;
+
+
+      if ( numElements > FT_LONG_MAX / arrstack->sizeItem )
+        goto exit;
+
+
+      FT_ASSERT( newSize > 0 );   /* avoid realloc with zero size */
+
+      if ( !FT_REALLOC( arrstack->ptr, arrstack->totalSize, newSize ) )
+      {
+        arrstack->allocated = numElements;
+        arrstack->totalSize = newSize;
+
+        if ( arrstack->count > numElements )
+        {
+          /* we truncated the list! */
+          CF2_SET_ERROR( arrstack->error, Stack_Overflow );
+          arrstack->count = numElements;
+          return FALSE;
+        }
+
+        return TRUE;     /* success */
+      }
+    }
+
+  exit:
+    /* if there's not already an error, store this one */
+    CF2_SET_ERROR( arrstack->error, Out_Of_Memory );
+
+    return FALSE;
+  }
+
+
+  /* set the count, ensuring allocation is sufficient */
+  FT_LOCAL_DEF( void )
+  cf2_arrstack_setCount( CF2_ArrStack  arrstack,
+                         size_t        numElements )
+  {
+    FT_ASSERT( arrstack );
+
+    if ( numElements > arrstack->allocated )
+    {
+      /* expand the allocation first */
+      if ( !cf2_arrstack_setNumElements( arrstack, numElements ) )
+        return;
+    }
+
+    arrstack->count = numElements;
+  }
+
+
+  /* clear the count */
+  FT_LOCAL_DEF( void )
+  cf2_arrstack_clear( CF2_ArrStack  arrstack )
+  {
+    FT_ASSERT( arrstack );
+
+    arrstack->count = 0;
+  }
+
+
+  /* current number of items */
+  FT_LOCAL_DEF( size_t )
+  cf2_arrstack_size( const CF2_ArrStack  arrstack )
+  {
+    FT_ASSERT( arrstack );
+
+    return arrstack->count;
+  }
+
+
+  FT_LOCAL_DEF( void* )
+  cf2_arrstack_getBuffer( const CF2_ArrStack  arrstack )
+  {
+    FT_ASSERT( arrstack );
+
+    return arrstack->ptr;
+  }
+
+
+  /* return pointer to the given element */
+  FT_LOCAL_DEF( void* )
+  cf2_arrstack_getPointer( const CF2_ArrStack  arrstack,
+                           size_t              idx )
+  {
+    void*  newPtr;
+
+
+    FT_ASSERT( arrstack );
+
+    if ( idx >= arrstack->count )
+    {
+      /* overflow */
+      CF2_SET_ERROR( arrstack->error, Stack_Overflow );
+      idx = 0;    /* choose safe default */
+    }
+
+    newPtr = (FT_Byte*)arrstack->ptr + idx * arrstack->sizeItem;
+
+    return newPtr;
+  }
+
+
+  /* push (append) an element at the end of the list;         */
+  /* return false on memory error                             */
+  /* TODO: should there be a length param for extra checking? */
+  FT_LOCAL_DEF( void )
+  cf2_arrstack_push( CF2_ArrStack  arrstack,
+                     const void*   ptr )
+  {
+    FT_ASSERT( arrstack );
+
+    if ( arrstack->count == arrstack->allocated )
+    {
+      /* grow the buffer by one chunk */
+      if ( !cf2_arrstack_setNumElements(
+             arrstack, arrstack->allocated + arrstack->chunk ) )
+      {
+        /* on error, ignore the push */
+        return;
+      }
+    }
+
+    FT_ASSERT( ptr );
+
+    {
+      size_t  offset = arrstack->count * arrstack->sizeItem;
+      void*   newPtr = (FT_Byte*)arrstack->ptr + offset;
+
+
+      FT_MEM_COPY( newPtr, ptr, arrstack->sizeItem );
+      arrstack->count += 1;
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psarrst.h
@@ -1,0 +1,100 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2arrst.h                                                             */
+/*                                                                         */
+/*    Adobe's code for Array Stacks (specification).                       */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2ARRST_H_
+#define CF2ARRST_H_
+
+
+#include "pserror.h"
+
+
+FT_BEGIN_HEADER
+
+
+  /* need to define the struct here (not opaque) so it can be allocated by */
+  /* clients                                                               */
+  typedef struct  CF2_ArrStackRec_
+  {
+    FT_Memory  memory;
+    FT_Error*  error;
+
+    size_t  sizeItem;       /* bytes per element             */
+    size_t  allocated;      /* items allocated               */
+    size_t  chunk;          /* allocation increment in items */
+    size_t  count;          /* number of elements allocated  */
+    size_t  totalSize;      /* total bytes allocated         */
+
+    void*  ptr;             /* ptr to data                   */
+
+  } CF2_ArrStackRec, *CF2_ArrStack;
+
+
+  FT_LOCAL( void )
+  cf2_arrstack_init( CF2_ArrStack  arrstack,
+                     FT_Memory     memory,
+                     FT_Error*     error,
+                     size_t        sizeItem );
+  FT_LOCAL( void )
+  cf2_arrstack_finalize( CF2_ArrStack  arrstack );
+
+  FT_LOCAL( void )
+  cf2_arrstack_setCount( CF2_ArrStack  arrstack,
+                         size_t        numElements );
+  FT_LOCAL( void )
+  cf2_arrstack_clear( CF2_ArrStack  arrstack );
+  FT_LOCAL( size_t )
+  cf2_arrstack_size( const CF2_ArrStack  arrstack );
+
+  FT_LOCAL( void* )
+  cf2_arrstack_getBuffer( const CF2_ArrStack  arrstack );
+  FT_LOCAL( void* )
+  cf2_arrstack_getPointer( const CF2_ArrStack  arrstack,
+                           size_t              idx );
+
+  FT_LOCAL( void )
+  cf2_arrstack_push( CF2_ArrStack  arrstack,
+                     const void*   ptr );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2ARRST_H_ */
+
+
+/* END */
--- a/src/psaux/psaux.c
+++ b/src/psaux/psaux.c
@@ -27,15 +27,15 @@
 #include "t1decode.c"
 #include "cffdecode.c"
 
-#include "cf2arrst.c"
-#include "cf2blues.c"
-#include "cf2error.c"
-#include "cf2font.c"
-#include "cf2ft.c"
-#include "cf2hints.c"
-#include "cf2intrp.c"
-#include "cf2read.c"
-#include "cf2stack.c"
+#include "psarrst.c"
+#include "psblues.c"
+#include "pserror.c"
+#include "psfont.c"
+#include "psft.c"
+#include "pshints.c"
+#include "psintrp.c"
+#include "psread.c"
+#include "psstack.c"
 
 
 /* END */
--- a/src/psaux/psauxmod.c
+++ b/src/psaux/psauxmod.c
@@ -21,7 +21,7 @@
 #include "psobjs.h"
 #include "t1decode.h"
 #include "t1cmap.h"
-#include "cf2ft.h"
+#include "psft.h"
 #include "cffdecode.h"
 
 #ifndef T1_CONFIG_OPTION_NO_AFM
--- /dev/null
+++ b/src/psaux/psblues.c
@@ -1,0 +1,582 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2blues.c                                                             */
+/*                                                                         */
+/*    Adobe's code for handling Blue Zones (body).                         */
+/*                                                                         */
+/*  Copyright 2009-2014 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include FT_INTERNAL_DEBUG_H
+
+#include "psblues.h"
+#include "pshints.h"
+#include "psfont.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* 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_cf2blues
+
+
+  /*
+   * For blue values, the FreeType parser produces an array of integers,
+   * while the Adobe CFF engine produces an array of fixed.
+   * Define a macro to convert FreeType to fixed.
+   */
+#define cf2_blueToFixed( x )  cf2_intToFixed( x )
+
+
+  FT_LOCAL_DEF( void )
+  cf2_blues_init( CF2_Blues  blues,
+                  CF2_Font   font )
+  {
+    /* pointer to parsed font object */
+    CFF_Decoder*  decoder = font->decoder;
+
+    CF2_Fixed  zoneHeight;
+    CF2_Fixed  maxZoneHeight = 0;
+    CF2_Fixed  csUnitsPerPixel;
+
+    size_t  numBlueValues;
+    size_t  numOtherBlues;
+    size_t  numFamilyBlues;
+    size_t  numFamilyOtherBlues;
+
+    FT_Pos*  blueValues;
+    FT_Pos*  otherBlues;
+    FT_Pos*  familyBlues;
+    FT_Pos*  familyOtherBlues;
+
+    size_t     i;
+    CF2_Fixed  emBoxBottom, emBoxTop;
+
+#if 0
+    CF2_Int  unitsPerEm = font->unitsPerEm;
+
+
+    if ( unitsPerEm == 0 )
+      unitsPerEm = 1000;
+#endif
+
+    FT_ZERO( blues );
+    blues->scale = font->innerTransform.d;
+
+    cf2_getBlueMetrics( decoder,
+                        &blues->blueScale,
+                        &blues->blueShift,
+                        &blues->blueFuzz );
+
+    cf2_getBlueValues( decoder, &numBlueValues, &blueValues );
+    cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues );
+    cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues );
+    cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues );
+
+    /*
+     * synthetic em box hint heuristic
+     *
+     * Apply this when ideographic dictionary (LanguageGroup 1) has no
+     * real alignment zones.  Adobe tools generate dummy zones at -250 and
+     * 1100 for a 1000 unit em.  Fonts with ICF-based alignment zones
+     * should not enable the heuristic.  When the heuristic is enabled,
+     * the font's blue zones are ignored.
+     *
+     */
+
+    /* get em box from OS/2 typoAscender/Descender                      */
+    /* TODO: FreeType does not parse these metrics.  Skip them for now. */
+#if 0
+    FCM_getHorizontalLineMetrics( &e,
+                                  font->font,
+                                  &ascender,
+                                  &descender,
+                                  &linegap );
+    if ( ascender - descender == unitsPerEm )
+    {
+      emBoxBottom = cf2_intToFixed( descender );
+      emBoxTop    = cf2_intToFixed( ascender );
+    }
+    else
+#endif
+    {
+      emBoxBottom = CF2_ICF_Bottom;
+      emBoxTop    = CF2_ICF_Top;
+    }
+
+    if ( cf2_getLanguageGroup( decoder ) == 1                   &&
+         ( numBlueValues == 0                                 ||
+           ( numBlueValues == 4                             &&
+             cf2_blueToFixed( blueValues[0] ) < emBoxBottom &&
+             cf2_blueToFixed( blueValues[1] ) < emBoxBottom &&
+             cf2_blueToFixed( blueValues[2] ) > emBoxTop    &&
+             cf2_blueToFixed( blueValues[3] ) > emBoxTop    ) ) )
+    {
+      /*
+       * Construct hint edges suitable for synthetic ghost hints at top
+       * and bottom of em box.  +-CF2_MIN_COUNTER allows for unhinted
+       * features above or below the last hinted edge.  This also gives a
+       * net 1 pixel boost to the height of ideographic glyphs.
+       *
+       * Note: Adjust synthetic hints outward by epsilon (0x.0001) to
+       *       avoid interference.  E.g., some fonts have real hints at
+       *       880 and -120.
+       */
+
+      blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON;
+      blues->emBoxBottomEdge.dsCoord = cf2_fixedRound(
+                                         FT_MulFix(
+                                           blues->emBoxBottomEdge.csCoord,
+                                           blues->scale ) ) -
+                                       CF2_MIN_COUNTER;
+      blues->emBoxBottomEdge.scale   = blues->scale;
+      blues->emBoxBottomEdge.flags   = CF2_GhostBottom |
+                                       CF2_Locked |
+                                       CF2_Synthetic;
+
+      blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON +
+                                    2 * font->darkenY;
+      blues->emBoxTopEdge.dsCoord = cf2_fixedRound(
+                                      FT_MulFix(
+                                        blues->emBoxTopEdge.csCoord,
+                                        blues->scale ) ) +
+                                    CF2_MIN_COUNTER;
+      blues->emBoxTopEdge.scale   = blues->scale;
+      blues->emBoxTopEdge.flags   = CF2_GhostTop |
+                                    CF2_Locked |
+                                    CF2_Synthetic;
+
+      blues->doEmBoxHints = TRUE;    /* enable the heuristic */
+
+      return;
+    }
+
+    /* copy `BlueValues' and `OtherBlues' to a combined array of top and */
+    /* bottom zones                                                      */
+    for ( i = 0; i < numBlueValues; i += 2 )
+    {
+      blues->zone[blues->count].csBottomEdge =
+        cf2_blueToFixed( blueValues[i] );
+      blues->zone[blues->count].csTopEdge =
+        cf2_blueToFixed( blueValues[i + 1] );
+
+      zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge,
+                              blues->zone[blues->count].csBottomEdge );
+
+      if ( zoneHeight < 0 )
+      {
+        FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
+        continue;   /* reject this zone */
+      }
+
+      if ( zoneHeight > maxZoneHeight )
+      {
+        /* take maximum before darkening adjustment      */
+        /* so overshoot suppression point doesn't change */
+        maxZoneHeight = zoneHeight;
+      }
+
+      /* adjust both edges of top zone upward by twice darkening amount */
+      if ( i != 0 )
+      {
+        blues->zone[blues->count].csTopEdge    += 2 * font->darkenY;
+        blues->zone[blues->count].csBottomEdge += 2 * font->darkenY;
+      }
+
+      /* first `BlueValue' is bottom zone; others are top */
+      if ( i == 0 )
+      {
+        blues->zone[blues->count].bottomZone =
+          TRUE;
+        blues->zone[blues->count].csFlatEdge =
+          blues->zone[blues->count].csTopEdge;
+      }
+      else
+      {
+        blues->zone[blues->count].bottomZone =
+          FALSE;
+        blues->zone[blues->count].csFlatEdge =
+          blues->zone[blues->count].csBottomEdge;
+      }
+
+      blues->count += 1;
+    }
+
+    for ( i = 0; i < numOtherBlues; i += 2 )
+    {
+      blues->zone[blues->count].csBottomEdge =
+        cf2_blueToFixed( otherBlues[i] );
+      blues->zone[blues->count].csTopEdge =
+        cf2_blueToFixed( otherBlues[i + 1] );
+
+      zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge,
+                              blues->zone[blues->count].csBottomEdge );
+
+      if ( zoneHeight < 0 )
+      {
+        FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" ));
+        continue;   /* reject this zone */
+      }
+
+      if ( zoneHeight > maxZoneHeight )
+      {
+        /* take maximum before darkening adjustment      */
+        /* so overshoot suppression point doesn't change */
+        maxZoneHeight = zoneHeight;
+      }
+
+      /* Note: bottom zones are not adjusted for darkening amount */
+
+      /* all OtherBlues are bottom zone */
+      blues->zone[blues->count].bottomZone =
+        TRUE;
+      blues->zone[blues->count].csFlatEdge =
+        blues->zone[blues->count].csTopEdge;
+
+      blues->count += 1;
+    }
+
+    /* Adjust for FamilyBlues */
+
+    /* Search for the nearest flat edge in `FamilyBlues' or                */
+    /* `FamilyOtherBlues'.  According to the Black Book, any matching edge */
+    /* must be within one device pixel                                     */
+
+    csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale );
+
+    /* loop on all zones in this font */
+    for ( i = 0; i < blues->count; i++ )
+    {
+      size_t     j;
+      CF2_Fixed  minDiff;
+      CF2_Fixed  flatFamilyEdge, diff;
+      /* value for this font */
+      CF2_Fixed  flatEdge = blues->zone[i].csFlatEdge;
+
+
+      if ( blues->zone[i].bottomZone )
+      {
+        /* In a bottom zone, the top edge is the flat edge.             */
+        /* Search `FamilyOtherBlues' for bottom zones; look for closest */
+        /* Family edge that is within the one pixel threshold.          */
+
+        minDiff = CF2_FIXED_MAX;
+
+        for ( j = 0; j < numFamilyOtherBlues; j += 2 )
+        {
+          /* top edge */
+          flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] );
+
+          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );
+
+          if ( diff < minDiff && diff < csUnitsPerPixel )
+          {
+            blues->zone[i].csFlatEdge = flatFamilyEdge;
+            minDiff                   = diff;
+
+            if ( diff == 0 )
+              break;
+          }
+        }
+
+        /* check the first member of FamilyBlues, which is a bottom zone */
+        if ( numFamilyBlues >= 2 )
+        {
+          /* top edge */
+          flatFamilyEdge = cf2_blueToFixed( familyBlues[1] );
+
+          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );
+
+          if ( diff < minDiff && diff < csUnitsPerPixel )
+            blues->zone[i].csFlatEdge = flatFamilyEdge;
+        }
+      }
+      else
+      {
+        /* In a top zone, the bottom edge is the flat edge.                */
+        /* Search `FamilyBlues' for top zones; skip first zone, which is a */
+        /* bottom zone; look for closest Family edge that is within the    */
+        /* one pixel threshold                                             */
+
+        minDiff = CF2_FIXED_MAX;
+
+        for ( j = 2; j < numFamilyBlues; j += 2 )
+        {
+          /* bottom edge */
+          flatFamilyEdge = cf2_blueToFixed( familyBlues[j] );
+
+          /* adjust edges of top zone upward by twice darkening amount */
+          flatFamilyEdge += 2 * font->darkenY;      /* bottom edge */
+
+          diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) );
+
+          if ( diff < minDiff && diff < csUnitsPerPixel )
+          {
+            blues->zone[i].csFlatEdge = flatFamilyEdge;
+            minDiff                   = diff;
+
+            if ( diff == 0 )
+              break;
+          }
+        }
+      }
+    }
+
+    /* TODO: enforce separation of zones, including BlueFuzz */
+
+    /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */
+    /* `bcsetup.c'.                                               */
+
+    if ( maxZoneHeight > 0 )
+    {
+      if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ),
+                                         maxZoneHeight ) )
+      {
+        /* clamp at maximum scale */
+        blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ),
+                                      maxZoneHeight );
+      }
+
+      /*
+       * TODO: Revisit the bug fix for 613448.  The minimum scale
+       *       requirement catches a number of library fonts.  For
+       *       example, with default BlueScale (.039625) and 0.4 minimum,
+       *       the test below catches any font with maxZoneHeight < 10.1.
+       *       There are library fonts ranging from 2 to 10 that get
+       *       caught, including e.g., Eurostile LT Std Medium with
+       *       maxZoneHeight of 6.
+       *
+       */
+#if 0
+      if ( blueScale < .4 / maxZoneHeight )
+      {
+        tetraphilia_assert( 0 );
+        /* clamp at minimum scale, per bug 0613448 fix */
+        blueScale = .4 / maxZoneHeight;
+      }
+#endif
+
+    }
+
+    /*
+     * Suppress overshoot and boost blue zones at small sizes.  Boost
+     * amount varies linearly from 0.5 pixel near 0 to 0 pixel at
+     * blueScale cutoff.
+     * Note: This boost amount is different from the coretype heuristic.
+     *
+     */
+
+    if ( blues->scale < blues->blueScale )
+    {
+      blues->suppressOvershoot = TRUE;
+
+      /* Change rounding threshold for `dsFlatEdge'.                    */
+      /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */
+      /*       10ppem Arial                                             */
+
+      blues->boost = cf2_doubleToFixed( .6 ) -
+                       FT_MulDiv( cf2_doubleToFixed ( .6 ),
+                                  blues->scale,
+                                  blues->blueScale );
+      if ( blues->boost > 0x7FFF )
+      {
+        /* boost must remain less than 0.5, or baseline could go negative */
+        blues->boost = 0x7FFF;
+      }
+    }
+
+    /* boost and darkening have similar effects; don't do both */
+    if ( font->stemDarkened )
+      blues->boost = 0;
+
+    /* set device space alignment for each zone;    */
+    /* apply boost amount before rounding flat edge */
+
+    for ( i = 0; i < blues->count; i++ )
+    {
+      if ( blues->zone[i].bottomZone )
+        blues->zone[i].dsFlatEdge = cf2_fixedRound(
+                                      FT_MulFix(
+                                        blues->zone[i].csFlatEdge,
+                                        blues->scale ) -
+                                      blues->boost );
+      else
+        blues->zone[i].dsFlatEdge = cf2_fixedRound(
+                                      FT_MulFix(
+                                        blues->zone[i].csFlatEdge,
+                                        blues->scale ) +
+                                      blues->boost );
+    }
+  }
+
+
+  /*
+   * Check whether `stemHint' is captured by one of the blue zones.
+   *
+   * Zero, one or both edges may be valid; only valid edges can be
+   * captured.  For compatibility with CoolType, search top and bottom
+   * zones in the same pass (see `BlueLock').  If a hint is captured,
+   * return true and position the edge(s) in one of 3 ways:
+   *
+   *  1) If `BlueScale' suppresses overshoot, position the captured edge
+   *     at the flat edge of the zone.
+   *  2) If overshoot is not suppressed and `BlueShift' requires
+   *     overshoot, position the captured edge a minimum of 1 device pixel
+   *     from the flat edge.
+   *  3) If overshoot is not suppressed or required, position the captured
+   *     edge at the nearest device pixel.
+   *
+   */
+  FT_LOCAL_DEF( FT_Bool )
+  cf2_blues_capture( const CF2_Blues  blues,
+                     CF2_Hint         bottomHintEdge,
+                     CF2_Hint         topHintEdge )
+  {
+    /* TODO: validate? */
+    CF2_Fixed  csFuzz = blues->blueFuzz;
+
+    /* new position of captured edge */
+    CF2_Fixed  dsNew;
+
+    /* amount that hint is moved when positioned */
+    CF2_Fixed  dsMove = 0;
+
+    FT_Bool   captured = FALSE;
+    CF2_UInt  i;
+
+
+    /* assert edge flags are consistent */
+    FT_ASSERT( !cf2_hint_isTop( bottomHintEdge ) &&
+               !cf2_hint_isBottom( topHintEdge ) );
+
+    /* TODO: search once without blue fuzz for compatibility with coretype? */
+    for ( i = 0; i < blues->count; i++ )
+    {
+      if ( blues->zone[i].bottomZone           &&
+           cf2_hint_isBottom( bottomHintEdge ) )
+      {
+        if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <=
+               bottomHintEdge->csCoord                           &&
+             bottomHintEdge->csCoord <=
+               ADD_INT32( blues->zone[i].csTopEdge, csFuzz )     )
+        {
+          /* bottom edge captured by bottom zone */
+
+          if ( blues->suppressOvershoot )
+            dsNew = blues->zone[i].dsFlatEdge;
+
+          else if ( SUB_INT32( blues->zone[i].csTopEdge,
+                               bottomHintEdge->csCoord ) >=
+                      blues->blueShift )
+          {
+            /* guarantee minimum of 1 pixel overshoot */
+            dsNew = FT_MIN(
+                      cf2_fixedRound( bottomHintEdge->dsCoord ),
+                      blues->zone[i].dsFlatEdge - cf2_intToFixed( 1 ) );
+          }
+
+          else
+          {
+            /* simply round captured edge */
+            dsNew = cf2_fixedRound( bottomHintEdge->dsCoord );
+          }
+
+          dsMove   = SUB_INT32( dsNew, bottomHintEdge->dsCoord );
+          captured = TRUE;
+
+          break;
+        }
+      }
+
+      if ( !blues->zone[i].bottomZone && cf2_hint_isTop( topHintEdge ) )
+      {
+        if ( SUB_INT32( blues->zone[i].csBottomEdge, csFuzz ) <=
+               topHintEdge->csCoord                              &&
+             topHintEdge->csCoord <=
+               ADD_INT32( blues->zone[i].csTopEdge, csFuzz )     )
+        {
+          /* top edge captured by top zone */
+
+          if ( blues->suppressOvershoot )
+            dsNew = blues->zone[i].dsFlatEdge;
+
+          else if ( SUB_INT32( topHintEdge->csCoord,
+                               blues->zone[i].csBottomEdge ) >=
+                      blues->blueShift )
+          {
+            /* guarantee minimum of 1 pixel overshoot */
+            dsNew = FT_MAX(
+                      cf2_fixedRound( topHintEdge->dsCoord ),
+                      blues->zone[i].dsFlatEdge + cf2_intToFixed( 1 ) );
+          }
+
+          else
+          {
+            /* simply round captured edge */
+            dsNew = cf2_fixedRound( topHintEdge->dsCoord );
+          }
+
+          dsMove   = SUB_INT32( dsNew, topHintEdge->dsCoord );
+          captured = TRUE;
+
+          break;
+        }
+      }
+    }
+
+    if ( captured )
+    {
+      /* move both edges and flag them `locked' */
+      if ( cf2_hint_isValid( bottomHintEdge ) )
+      {
+        bottomHintEdge->dsCoord = ADD_INT32( bottomHintEdge->dsCoord,
+                                             dsMove );
+        cf2_hint_lock( bottomHintEdge );
+      }
+
+      if ( cf2_hint_isValid( topHintEdge ) )
+      {
+        topHintEdge->dsCoord = ADD_INT32( topHintEdge->dsCoord, dsMove );
+        cf2_hint_lock( topHintEdge );
+      }
+    }
+
+    return captured;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psblues.h
@@ -1,0 +1,185 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2blues.h                                                             */
+/*                                                                         */
+/*    Adobe's code for handling Blue Zones (specification).                */
+/*                                                                         */
+/*  Copyright 2009-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*
+   * A `CF2_Blues' object stores the blue zones (horizontal alignment
+   * zones) of a font.  These are specified in the CFF private dictionary
+   * by `BlueValues', `OtherBlues', `FamilyBlues', and `FamilyOtherBlues'.
+   * Each zone is defined by a top and bottom edge in character space.
+   * Further, each zone is either a top zone or a bottom zone, as recorded
+   * by `bottomZone'.
+   *
+   * The maximum number of `BlueValues' and `FamilyBlues' is 7 each.
+   * However, these are combined to produce a total of 7 zones.
+   * Similarly, the maximum number of `OtherBlues' and `FamilyOtherBlues'
+   * is 5 and these are combined to produce an additional 5 zones.
+   *
+   * Blue zones are used to `capture' hints and force them to a common
+   * alignment point.  This alignment is recorded in device space in
+   * `dsFlatEdge'.  Except for this value, a `CF2_Blues' object could be
+   * constructed independently of scaling.  Construction may occur once
+   * the matrix is known.  Other features implemented in the Capture
+   * method are overshoot suppression, overshoot enforcement, and Blue
+   * Boost.
+   *
+   * Capture is determined by `BlueValues' and `OtherBlues', but the
+   * alignment point may be adjusted to the scaled flat edge of
+   * `FamilyBlues' or `FamilyOtherBlues'.  No alignment is done to the
+   * curved edge of a zone.
+   *
+   */
+
+
+#ifndef CF2BLUES_H_
+#define CF2BLUES_H_
+
+
+#include "psglue.h"
+
+
+FT_BEGIN_HEADER
+
+
+  /*
+   * `CF2_Hint' is shared by `cf2hints.h' and
+   * `cf2blues.h', but `cf2blues.h' depends on
+   * `cf2hints.h', so define it here.  Note: The typedef is in
+   * `cf2glue.h'.
+   *
+   */
+  enum
+  {
+    CF2_GhostBottom = 0x1,  /* a single bottom edge           */
+    CF2_GhostTop    = 0x2,  /* a single top edge              */
+    CF2_PairBottom  = 0x4,  /* the bottom edge of a stem hint */
+    CF2_PairTop     = 0x8,  /* the top edge of a stem hint    */
+    CF2_Locked      = 0x10, /* this edge has been aligned     */
+                            /* by a blue zone                 */
+    CF2_Synthetic   = 0x20  /* this edge was synthesized      */
+  };
+
+
+  /*
+   * Default value for OS/2 typoAscender/Descender when their difference
+   * is not equal to `unitsPerEm'.  The default is based on -250 and 1100
+   * in `CF2_Blues', assuming 1000 units per em here.
+   *
+   */
+  enum
+  {
+    CF2_ICF_Top    = cf2_intToFixed(  880 ),
+    CF2_ICF_Bottom = cf2_intToFixed( -120 )
+  };
+
+
+  /*
+   * Constant used for hint adjustment and for synthetic em box hint
+   * placement.
+   */
+#define CF2_MIN_COUNTER  cf2_doubleToFixed( 0.5 )
+
+
+  /* shared typedef is in cf2glue.h */
+  struct  CF2_HintRec_
+  {
+    CF2_UInt  flags;  /* attributes of the edge            */
+    size_t    index;  /* index in original stem hint array */
+                      /* (if not synthetic)                */
+    CF2_Fixed  csCoord;
+    CF2_Fixed  dsCoord;
+    CF2_Fixed  scale;
+  };
+
+
+  typedef struct  CF2_BlueRec_
+  {
+    CF2_Fixed  csBottomEdge;
+    CF2_Fixed  csTopEdge;
+    CF2_Fixed  csFlatEdge; /* may be from either local or Family zones */
+    CF2_Fixed  dsFlatEdge; /* top edge of bottom zone or bottom edge   */
+                           /* of top zone (rounded)                    */
+    FT_Bool  bottomZone;
+
+  } CF2_BlueRec;
+
+
+  /* max total blue zones is 12 */
+  enum
+  {
+    CF2_MAX_BLUES      = 7,
+    CF2_MAX_OTHERBLUES = 5
+  };
+
+
+  typedef struct  CF2_BluesRec_
+  {
+    CF2_Fixed  scale;
+    CF2_UInt   count;
+    FT_Bool    suppressOvershoot;
+    FT_Bool    doEmBoxHints;
+
+    CF2_Fixed  blueScale;
+    CF2_Fixed  blueShift;
+    CF2_Fixed  blueFuzz;
+
+    CF2_Fixed  boost;
+
+    CF2_HintRec  emBoxTopEdge;
+    CF2_HintRec  emBoxBottomEdge;
+
+    CF2_BlueRec  zone[CF2_MAX_BLUES + CF2_MAX_OTHERBLUES];
+
+  } CF2_BluesRec, *CF2_Blues;
+
+
+  FT_LOCAL( void )
+  cf2_blues_init( CF2_Blues  blues,
+                  CF2_Font   font );
+  FT_LOCAL( FT_Bool )
+  cf2_blues_capture( const CF2_Blues  blues,
+                     CF2_Hint         bottomHintEdge,
+                     CF2_Hint         topHintEdge );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2BLUES_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/pserror.c
@@ -1,0 +1,52 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2error.c                                                             */
+/*                                                                         */
+/*    Adobe's code for error handling (body).                              */
+/*                                                                         */
+/*  Copyright 2006-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include "pserror.h"
+
+
+  FT_LOCAL_DEF( void )
+  cf2_setError( FT_Error*  error,
+                FT_Error   value )
+  {
+    if ( error && !*error )
+      *error = value;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/pserror.h
@@ -1,0 +1,119 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2error.h                                                             */
+/*                                                                         */
+/*    Adobe's code for error handling (specification).                     */
+/*                                                                         */
+/*  Copyright 2006-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2ERROR_H_
+#define CF2ERROR_H_
+
+
+#include FT_MODULE_ERRORS_H
+
+#undef FTERRORS_H_
+
+#undef  FT_ERR_PREFIX
+#define FT_ERR_PREFIX  CF2_Err_
+#define FT_ERR_BASE    FT_Mod_Err_CF2
+
+
+#include FT_ERRORS_H
+#include "psft.h"
+
+
+FT_BEGIN_HEADER
+
+
+  /*
+   * A poor-man error facility.
+   *
+   * This code being written in vanilla C, doesn't have the luxury of a
+   * language-supported exception mechanism such as the one available in
+   * Java.  Instead, we are stuck with using error codes that must be
+   * carefully managed and preserved.  However, it is convenient for us to
+   * model our error mechanism on a Java-like exception mechanism.
+   * When we assign an error code we are thus `throwing' an error.
+   *
+   * The preservation of an error code is done by coding convention.
+   * Upon a function call if the error code is anything other than
+   * `FT_Err_Ok', which is guaranteed to be zero, we
+   * will return without altering that error.  This will allow the
+   * error to propagate and be handled at the appropriate location in
+   * the code.
+   *
+   * This allows a style of code where the error code is initialized
+   * up front and a block of calls are made with the error code only
+   * being checked after the block.  If a new error occurs, the original
+   * error will be preserved and a functional no-op should result in any
+   * subsequent function that has an initial error code not equal to
+   * `FT_Err_Ok'.
+   *
+   * Errors are encoded by calling the `FT_THROW' macro.  For example,
+   *
+   * {
+   *   FT_Error  e;
+   *
+   *
+   *   ...
+   *   e = FT_THROW( Out_Of_Memory );
+   * }
+   *
+   */
+
+
+  /* Set error code to a particular value. */
+  FT_LOCAL( void )
+  cf2_setError( FT_Error*  error,
+                FT_Error   value );
+
+
+  /*
+   * A macro that conditionally sets an error code.
+   *
+   * This macro will first check whether `error' is set;
+   * if not, it will set it to `e'.
+   *
+  */
+#define CF2_SET_ERROR( error, e )              \
+          cf2_setError( error, FT_THROW( e ) )
+
+
+FT_END_HEADER
+
+
+#endif /* CF2ERROR_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psfixed.h
@@ -1,0 +1,95 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2fixed.h                                                             */
+/*                                                                         */
+/*    Adobe's code for Fixed Point Mathematics (specification only).       */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2FIXED_H_
+#define CF2FIXED_H_
+
+
+FT_BEGIN_HEADER
+
+
+  /* rasterizer integer and fixed point arithmetic must be 32-bit */
+
+#define   CF2_Fixed  CF2_F16Dot16
+  typedef FT_Int32   CF2_Frac;   /* 2.30 fixed point */
+
+
+#define CF2_FIXED_MAX      ( (CF2_Fixed)0x7FFFFFFFL )
+#define CF2_FIXED_MIN      ( (CF2_Fixed)0x80000000L )
+#define CF2_FIXED_ONE      ( (CF2_Fixed)0x10000L )
+#define CF2_FIXED_EPSILON  ( (CF2_Fixed)0x0001 )
+
+  /* in C 89, left and right shift of negative numbers is  */
+  /* implementation specific behaviour in the general case */
+
+#define cf2_intToFixed( i )                                              \
+          ( (CF2_Fixed)( (FT_UInt32)(i) << 16 ) )
+#define cf2_fixedToInt( x )                                              \
+          ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
+#define cf2_fixedRound( x )                                              \
+          ( (CF2_Fixed)( ( (FT_UInt32)(x) + 0x8000U ) & 0xFFFF0000UL ) )
+#define cf2_doubleToFixed( f )                                           \
+          ( (CF2_Fixed)( (f) * 65536.0 + 0.5 ) )
+#define cf2_fixedAbs( x )                                                \
+          ( (x) < 0 ? NEG_INT32( x ) : (x) )
+#define cf2_fixedFloor( x )                                              \
+          ( (CF2_Fixed)( (FT_UInt32)(x) & 0xFFFF0000UL ) )
+#define cf2_fixedFraction( x )                                           \
+          ( (x) - cf2_fixedFloor( x ) )
+#define cf2_fracToFixed( x )                                             \
+          ( (x) < 0 ? -( ( -(x) + 0x2000 ) >> 14 )                       \
+                    :  ( (  (x) + 0x2000 ) >> 14 ) )
+
+
+  /* signed numeric types */
+  typedef enum  CF2_NumberType_
+  {
+    CF2_NumberFixed,    /* 16.16 */
+    CF2_NumberFrac,     /*  2.30 */
+    CF2_NumberInt       /* 32.0  */
+
+  } CF2_NumberType;
+
+
+FT_END_HEADER
+
+
+#endif /* CF2FIXED_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psfont.c
@@ -1,0 +1,563 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2font.c                                                              */
+/*                                                                         */
+/*    Adobe's code for font instances (body).                              */
+/*                                                                         */
+/*  Copyright 2007-2014 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CALC_H
+
+#include "psft.h"
+
+#include "psglue.h"
+#include "psfont.h"
+#include "pserror.h"
+#include "psintrp.h"
+
+
+  /* Compute a stem darkening amount in character space. */
+  static void
+  cf2_computeDarkening( CF2_Fixed   emRatio,
+                        CF2_Fixed   ppem,
+                        CF2_Fixed   stemWidth,
+                        CF2_Fixed*  darkenAmount,
+                        CF2_Fixed   boldenAmount,
+                        FT_Bool     stemDarkened,
+                        FT_Int*     darkenParams )
+  {
+    /*
+     * Total darkening amount is computed in 1000 unit character space
+     * using the modified 5 part curve as Adobe's Avalon rasterizer.
+     * The darkening amount is smaller for thicker stems.
+     * It becomes zero when the stem is thicker than 2.333 pixels.
+     *
+     * By default, we use
+     *
+     *   darkenAmount = 0.4 pixels   if scaledStem <= 0.5 pixels,
+     *   darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels,
+     *   darkenAmount = 0 pixel      if scaledStem >= 2.333 pixels,
+     *
+     * and piecewise linear in-between:
+     *
+     *
+     *   darkening
+     *       ^
+     *       |
+     *       |      (x1,y1)
+     *       |--------+
+     *       |         \
+     *       |          \
+     *       |           \          (x3,y3)
+     *       |            +----------+
+     *       |        (x2,y2)         \
+     *       |                         \
+     *       |                          \
+     *       |                           +-----------------
+     *       |                         (x4,y4)
+     *       +--------------------------------------------->   stem
+     *                                                       thickness
+     *
+     *
+     * This corresponds to the following values for the
+     * `darkening-parameters' property:
+     *
+     *   (x1, y1) = (500, 400)
+     *   (x2, y2) = (1000, 275)
+     *   (x3, y3) = (1667, 275)
+     *   (x4, y4) = (2333, 0)
+     *
+     */
+
+    /* Internal calculations are done in units per thousand for */
+    /* convenience. The x axis is scaled stem width in          */
+    /* thousandths of a pixel. That is, 1000 is 1 pixel.        */
+    /* The y axis is darkening amount in thousandths of a pixel.*/
+    /* In the code, below, dividing by ppem and                 */
+    /* adjusting for emRatio converts darkenAmount to character */
+    /* space (font units).                                      */
+    CF2_Fixed  stemWidthPer1000, scaledStem;
+    FT_Int     logBase2;
+
+
+    *darkenAmount = 0;
+
+    if ( boldenAmount == 0 && !stemDarkened )
+      return;
+
+    /* protect against range problems and divide by zero */
+    if ( emRatio < cf2_doubleToFixed( .01 ) )
+      return;
+
+    if ( stemDarkened )
+    {
+      FT_Int  x1 = darkenParams[0];
+      FT_Int  y1 = darkenParams[1];
+      FT_Int  x2 = darkenParams[2];
+      FT_Int  y2 = darkenParams[3];
+      FT_Int  x3 = darkenParams[4];
+      FT_Int  y3 = darkenParams[5];
+      FT_Int  x4 = darkenParams[6];
+      FT_Int  y4 = darkenParams[7];
+
+
+      /* convert from true character space to 1000 unit character space; */
+      /* add synthetic emboldening effect                                */
+
+      /* `stemWidthPer1000' will not overflow for a legitimate font      */
+
+      stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio );
+
+      /* `scaledStem' can easily overflow, so we must clamp its maximum  */
+      /* value; the test doesn't need to be precise, but must be         */
+      /* conservative.  The clamp value (default 2333) where             */
+      /* `darkenAmount' is zero is well below the overflow value of      */
+      /* 32767.                                                          */
+      /*                                                                 */
+      /* FT_MSB computes the integer part of the base 2 logarithm.  The  */
+      /* number of bits for the product is 1 or 2 more than the sum of   */
+      /* logarithms; remembering that the 16 lowest bits of the fraction */
+      /* are dropped this is correct to within a factor of almost 4.     */
+      /* For example, 0x80.0000 * 0x80.0000 = 0x4000.0000 is 23+23 and   */
+      /* is flagged as possible overflow because 0xFF.FFFF * 0xFF.FFFF = */
+      /* 0xFFFF.FE00 is also 23+23.                                      */
+
+      logBase2 = FT_MSB( (FT_UInt32)stemWidthPer1000 ) +
+                   FT_MSB( (FT_UInt32)ppem );
+
+      if ( logBase2 >= 46 )
+        /* possible overflow */
+        scaledStem = cf2_intToFixed( x4 );
+      else
+        scaledStem = FT_MulFix( stemWidthPer1000, ppem );
+
+      /* now apply the darkening parameters */
+
+      if ( scaledStem < cf2_intToFixed( x1 ) )
+        *darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem );
+
+      else if ( scaledStem < cf2_intToFixed( x2 ) )
+      {
+        FT_Int  xdelta = x2 - x1;
+        FT_Int  ydelta = y2 - y1;
+        FT_Int  x      = stemWidthPer1000 -
+                           FT_DivFix( cf2_intToFixed( x1 ), ppem );
+
+
+        if ( !xdelta )
+          goto Try_x3;
+
+        *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
+                          FT_DivFix( cf2_intToFixed( y1 ), ppem );
+      }
+
+      else if ( scaledStem < cf2_intToFixed( x3 ) )
+      {
+      Try_x3:
+        {
+          FT_Int  xdelta = x3 - x2;
+          FT_Int  ydelta = y3 - y2;
+          FT_Int  x      = stemWidthPer1000 -
+                             FT_DivFix( cf2_intToFixed( x2 ), ppem );
+
+
+          if ( !xdelta )
+            goto Try_x4;
+
+          *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
+                            FT_DivFix( cf2_intToFixed( y2 ), ppem );
+        }
+      }
+
+      else if ( scaledStem < cf2_intToFixed( x4 ) )
+      {
+      Try_x4:
+        {
+          FT_Int  xdelta = x4 - x3;
+          FT_Int  ydelta = y4 - y3;
+          FT_Int  x      = stemWidthPer1000 -
+                             FT_DivFix( cf2_intToFixed( x3 ), ppem );
+
+
+          if ( !xdelta )
+            goto Use_y4;
+
+          *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) +
+                            FT_DivFix( cf2_intToFixed( y3 ), ppem );
+        }
+      }
+
+      else
+      {
+      Use_y4:
+        *darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem );
+      }
+
+      /* use half the amount on each side and convert back to true */
+      /* character space                                           */
+      *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio );
+    }
+
+    /* add synthetic emboldening effect in character space */
+    *darkenAmount += boldenAmount / 2;
+  }
+
+
+  /* set up values for the current FontDict and matrix; */
+  /* called for each glyph to be rendered               */
+
+  /* caller's transform is adjusted for subpixel positioning */
+  static void
+  cf2_font_setup( CF2_Font           font,
+                  const CF2_Matrix*  transform )
+  {
+    /* pointer to parsed font object */
+    CFF_Decoder*  decoder = font->decoder;
+
+    FT_Bool  needExtraSetup = FALSE;
+
+    CFF_VStoreRec*  vstore;
+    FT_Bool         hasVariations = FALSE;
+
+    /* character space units */
+    CF2_Fixed  boldenX = font->syntheticEmboldeningAmountX;
+    CF2_Fixed  boldenY = font->syntheticEmboldeningAmountY;
+
+    CFF_SubFont  subFont;
+    CF2_Fixed    ppem;
+
+    CF2_UInt   lenNormalizedV = 0;
+    FT_Fixed*  normalizedV    = NULL;
+
+    FT_Service_CFFLoad  cffload = (FT_Service_CFFLoad)font->cffload;
+
+    /* clear previous error */
+    font->error = FT_Err_Ok;
+
+    /* if a CID fontDict has changed, we need to recompute some cached */
+    /* data                                                            */
+    subFont = cf2_getSubfont( decoder );
+    if ( font->lastSubfont != subFont )
+    {
+      font->lastSubfont = subFont;
+      needExtraSetup    = TRUE;
+    }
+
+    /* check for variation vectors */
+    vstore        = cf2_getVStore( decoder );
+    hasVariations = ( vstore->dataCount != 0 );
+
+    if ( hasVariations )
+    {
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+      /* check whether Private DICT in this subfont needs to be reparsed */
+      font->error = cf2_getNormalizedVector( decoder,
+                                             &lenNormalizedV,
+                                             &normalizedV );
+      if ( font->error )
+        return;
+
+      if ( cffload->blend_check_vector( &subFont->blend,
+                                        subFont->private_dict.vsindex,
+                                        lenNormalizedV,
+                                        normalizedV ) )
+      {
+        /* blend has changed, reparse */
+        cffload->load_private_dict( decoder->cff,
+                                    subFont,
+                                    lenNormalizedV,
+                                    normalizedV );
+        needExtraSetup = TRUE;
+      }
+#endif
+
+      /* copy from subfont */
+      font->blend.font = subFont->blend.font;
+
+      /* clear state of charstring blend */
+      font->blend.usedBV = FALSE;
+
+      /* initialize value for charstring */
+      font->vsindex = subFont->private_dict.vsindex;
+
+      /* store vector inputs for blends in charstring */
+      font->lenNDV = lenNormalizedV;
+      font->NDV    = normalizedV;
+    }
+
+    /* if ppem has changed, we need to recompute some cached data         */
+    /* note: because of CID font matrix concatenation, ppem and transform */
+    /*       do not necessarily track.                                    */
+    ppem = cf2_getPpemY( decoder );
+    if ( font->ppem != ppem )
+    {
+      font->ppem     = ppem;
+      needExtraSetup = TRUE;
+    }
+
+    /* copy hinted flag on each call */
+    font->hinted = (FT_Bool)( font->renderingFlags & CF2_FlagsHinted );
+
+    /* determine if transform has changed;       */
+    /* include Fontmatrix but ignore translation */
+    if ( ft_memcmp( transform,
+                    &font->currentTransform,
+                    4 * sizeof ( CF2_Fixed ) ) != 0 )
+    {
+      /* save `key' information for `cache of one' matrix data; */
+      /* save client transform, without the translation         */
+      font->currentTransform    = *transform;
+      font->currentTransform.tx =
+      font->currentTransform.ty = cf2_intToFixed( 0 );
+
+      /* TODO: FreeType transform is simple scalar; for now, use identity */
+      /*       for outer                                                  */
+      font->innerTransform   = *transform;
+      font->outerTransform.a =
+      font->outerTransform.d = cf2_intToFixed( 1 );
+      font->outerTransform.b =
+      font->outerTransform.c = cf2_intToFixed( 0 );
+
+      needExtraSetup = TRUE;
+    }
+
+    /*
+     * font->darkened is set to true if there is a stem darkening request or
+     * the font is synthetic emboldened.
+     * font->darkened controls whether to adjust blue zones, winding order,
+     * and hinting.
+     *
+     */
+    if ( font->stemDarkened != ( font->renderingFlags & CF2_FlagsDarkened ) )
+    {
+      font->stemDarkened =
+        (FT_Bool)( font->renderingFlags & CF2_FlagsDarkened );
+
+      /* blue zones depend on darkened flag */
+      needExtraSetup = TRUE;
+    }
+
+    /* recompute variables that are dependent on transform or FontDict or */
+    /* darken flag                                                        */
+    if ( needExtraSetup )
+    {
+      /* StdVW is found in the private dictionary;                       */
+      /* recompute darkening amounts whenever private dictionary or      */
+      /* transform change                                                */
+      /* Note: a rendering flag turns darkening on or off, so we want to */
+      /*       store the `on' amounts;                                   */
+      /*       darkening amount is computed in character space           */
+      /* TODO: testing size-dependent darkening here;                    */
+      /*       what to do for rotations?                                 */
+
+      CF2_Fixed  emRatio;
+      CF2_Fixed  stdHW;
+      CF2_Int    unitsPerEm = font->unitsPerEm;
+
+
+      if ( unitsPerEm == 0 )
+        unitsPerEm = 1000;
+
+      ppem = FT_MAX( cf2_intToFixed( 4 ),
+                     font->ppem ); /* use minimum ppem of 4 */
+
+#if 0
+      /* since vstem is measured in the x-direction, we use the `a' member */
+      /* of the fontMatrix                                                 */
+      emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->a );
+#endif
+
+      /* Freetype does not preserve the fontMatrix when parsing; use */
+      /* unitsPerEm instead.                                         */
+      /* TODO: check precision of this                               */
+      emRatio     = cf2_intToFixed( 1000 ) / unitsPerEm;
+      font->stdVW = cf2_getStdVW( decoder );
+
+      if ( font->stdVW <= 0 )
+        font->stdVW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
+
+      if ( boldenX > 0 )
+      {
+        /* Ensure that boldenX is at least 1 pixel for synthetic bold font */
+        /* (similar to what Avalon does)                                   */
+        boldenX = FT_MAX( boldenX,
+                          FT_DivFix( cf2_intToFixed( unitsPerEm ), ppem ) );
+
+        /* Synthetic emboldening adds at least 1 pixel to darkenX, while */
+        /* stem darkening adds at most half pixel.  Since the purpose of */
+        /* stem darkening (readability at small sizes) is met with       */
+        /* synthetic emboldening, no need to add stem darkening for a    */
+        /* synthetic bold font.                                          */
+        cf2_computeDarkening( emRatio,
+                              ppem,
+                              font->stdVW,
+                              &font->darkenX,
+                              boldenX,
+                              FALSE,
+                              font->darkenParams );
+      }
+      else
+        cf2_computeDarkening( emRatio,
+                              ppem,
+                              font->stdVW,
+                              &font->darkenX,
+                              0,
+                              font->stemDarkened,
+                              font->darkenParams );
+
+#if 0
+      /* since hstem is measured in the y-direction, we use the `d' member */
+      /* of the fontMatrix                                                 */
+      /* TODO: use the same units per em as above; check this              */
+      emRatio = cf2_fixedFracMul( cf2_intToFixed( 1000 ), fontMatrix->d );
+#endif
+
+      /* set the default stem width, because it must be the same for all */
+      /* family members;                                                 */
+      /* choose a constant for StdHW that depends on font contrast       */
+      stdHW = cf2_getStdHW( decoder );
+
+      if ( stdHW > 0 && font->stdVW > MUL_INT32( 2, stdHW ) )
+        font->stdHW = FT_DivFix( cf2_intToFixed( 75 ), emRatio );
+      else
+      {
+        /* low contrast font gets less hstem darkening */
+        font->stdHW = FT_DivFix( cf2_intToFixed( 110 ), emRatio );
+      }
+
+      cf2_computeDarkening( emRatio,
+                            ppem,
+                            font->stdHW,
+                            &font->darkenY,
+                            boldenY,
+                            font->stemDarkened,
+                            font->darkenParams );
+
+      if ( font->darkenX != 0 || font->darkenY != 0 )
+        font->darkened = TRUE;
+      else
+        font->darkened = FALSE;
+
+      font->reverseWinding = FALSE; /* initial expectation is CCW */
+
+      /* compute blue zones for this instance */
+      cf2_blues_init( &font->blues, font );
+
+    } /* needExtraSetup */
+  }
+
+
+  /* equivalent to AdobeGetOutline */
+  FT_LOCAL_DEF( FT_Error )
+  cf2_getGlyphOutline( CF2_Font           font,
+                       CF2_Buffer         charstring,
+                       const CF2_Matrix*  transform,
+                       CF2_F16Dot16*      glyphWidth )
+  {
+    FT_Error  lastError = FT_Err_Ok;
+
+    FT_Vector  translation;
+
+#if 0
+    FT_Vector  advancePoint;
+#endif
+
+    CF2_Fixed  advWidth = 0;
+    FT_Bool    needWinding;
+
+
+    /* Note: use both integer and fraction for outlines.  This allows bbox */
+    /*       to come out directly.                                         */
+
+    translation.x = transform->tx;
+    translation.y = transform->ty;
+
+    /* set up values based on transform */
+    cf2_font_setup( font, transform );
+    if ( font->error )
+      goto exit;                      /* setup encountered an error */
+
+    /* reset darken direction */
+    font->reverseWinding = FALSE;
+
+    /* winding order only affects darkening */
+    needWinding = font->darkened;
+
+    while ( 1 )
+    {
+      /* reset output buffer */
+      cf2_outline_reset( &font->outline );
+
+      /* build the outline, passing the full translation */
+      cf2_interpT2CharString( font,
+                              charstring,
+                              (CF2_OutlineCallbacks)&font->outline,
+                              &translation,
+                              FALSE,
+                              0,
+                              0,
+                              &advWidth );
+
+      if ( font->error )
+        goto exit;
+
+      if ( !needWinding )
+        break;
+
+      /* check winding order */
+      if ( font->outline.root.windingMomentum >= 0 ) /* CFF is CCW */
+        break;
+
+      /* invert darkening and render again                            */
+      /* TODO: this should be a parameter to getOutline-computeOffset */
+      font->reverseWinding = TRUE;
+
+      needWinding = FALSE;    /* exit after next iteration */
+    }
+
+    /* finish storing client outline */
+    cf2_outline_close( &font->outline );
+
+  exit:
+    /* FreeType just wants the advance width; there is no translation */
+    *glyphWidth = advWidth;
+
+    /* free resources and collect errors from objects we've used */
+    cf2_setError( &font->error, lastError );
+
+    return font->error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psfont.h
@@ -1,0 +1,133 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2font.h                                                              */
+/*                                                                         */
+/*    Adobe's code for font instances (specification).                     */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2FONT_H_
+#define CF2FONT_H_
+
+
+#include FT_SERVICE_CFF_TABLE_LOAD_H
+
+#include "psft.h"
+#include "psblues.h"
+
+
+FT_BEGIN_HEADER
+
+
+#define CF2_OPERAND_STACK_SIZE  48
+#define CF2_MAX_SUBR            16 /* maximum subroutine nesting;         */
+                                   /* only 10 are allowed but there exist */
+                                   /* fonts like `HiraKakuProN-W3.ttf'    */
+                                   /* (Hiragino Kaku Gothic ProN W3;      */
+                                   /* 8.2d6e1; 2014-12-19) that exceed    */
+                                   /* this limit                          */
+#define CF2_STORAGE_SIZE        32
+
+
+  /* typedef is in `cf2glue.h' */
+  struct  CF2_FontRec_
+  {
+    FT_Memory  memory;
+    FT_Error   error;     /* shared error for this instance */
+
+    FT_Bool             isCFF2;
+    CF2_RenderingFlags  renderingFlags;
+
+    /* variables that depend on Transform:  */
+    /* the following have zero translation; */
+    /* inner * outer = font * original      */
+
+    CF2_Matrix  currentTransform;  /* original client matrix           */
+    CF2_Matrix  innerTransform;    /* for hinting; erect, scaled       */
+    CF2_Matrix  outerTransform;    /* post hinting; includes rotations */
+    CF2_Fixed   ppem;              /* transform-dependent              */
+
+    /* variation data */
+    CFF_BlendRec  blend;            /* cached charstring blend vector  */
+    CF2_UInt      vsindex;          /* current vsindex                 */
+    CF2_UInt      lenNDV;           /* current length NDV or zero      */
+    FT_Fixed*     NDV;              /* ptr to current NDV or NULL      */
+
+    CF2_Int  unitsPerEm;
+
+    CF2_Fixed  syntheticEmboldeningAmountX;   /* character space units */
+    CF2_Fixed  syntheticEmboldeningAmountY;   /* character space units */
+
+    /* FreeType related members */
+    CF2_OutlineRec  outline;       /* freetype glyph outline functions */
+    CFF_Decoder*    decoder;
+    CFF_SubFont     lastSubfont;              /* FreeType parsed data; */
+                                              /* top font or subfont   */
+
+    /* these flags can vary from one call to the next */
+    FT_Bool  hinted;
+    FT_Bool  darkened;       /* true if stemDarkened or synthetic bold */
+                             /* i.e. darkenX != 0 || darkenY != 0      */
+    FT_Bool  stemDarkened;
+
+    FT_Int  darkenParams[8];              /* 1000 unit character space */
+
+    /* variables that depend on both FontDict and Transform */
+    CF2_Fixed  stdVW;     /* in character space; depends on dict entry */
+    CF2_Fixed  stdHW;     /* in character space; depends on dict entry */
+    CF2_Fixed  darkenX;                    /* character space units    */
+    CF2_Fixed  darkenY;                    /* depends on transform     */
+                                           /* and private dict (StdVW) */
+    FT_Bool  reverseWinding;               /* darken assuming          */
+                                           /* counterclockwise winding */
+
+    CF2_BluesRec  blues;                         /* computed zone data */
+
+    FT_Service_CFFLoad  cffload;                  /* Pointer to cff functions */
+  };
+
+
+  FT_LOCAL( FT_Error )
+  cf2_getGlyphOutline( CF2_Font           font,
+                       CF2_Buffer         charstring,
+                       const CF2_Matrix*  transform,
+                       CF2_F16Dot16*      glyphWidth );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2FONT_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psft.c
@@ -1,0 +1,768 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2ft.c                                                                */
+/*                                                                         */
+/*    FreeType Glue Component to Adobe's Interpreter (body).               */
+/*                                                                         */
+/*  Copyright 2013-2014 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include FT_INTERNAL_DEBUG_H
+
+#include "psfont.h"
+#include "pserror.h"
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+#include FT_MULTIPLE_MASTERS_H
+#include FT_SERVICE_MULTIPLE_MASTERS_H
+#endif
+
+#include FT_SERVICE_CFF_TABLE_LOAD_H
+
+#define CF2_MAX_SIZE  cf2_intToFixed( 2000 )    /* max ppem */
+
+
+  /*
+   * This check should avoid most internal overflow cases.  Clients should
+   * generally respond to `Glyph_Too_Big' by getting a glyph outline
+   * at EM size, scaling it and filling it as a graphics operation.
+   *
+   */
+  static FT_Error
+  cf2_checkTransform( const CF2_Matrix*  transform,
+                      CF2_Int            unitsPerEm )
+  {
+    CF2_Fixed  maxScale;
+
+
+    FT_ASSERT( unitsPerEm > 0 );
+
+    if ( transform->a <= 0 || transform->d <= 0 )
+      return FT_THROW( Invalid_Size_Handle );
+
+    FT_ASSERT( transform->b == 0 && transform->c == 0 );
+    FT_ASSERT( transform->tx == 0 && transform->ty == 0 );
+
+    if ( unitsPerEm > 0x7FFF )
+      return FT_THROW( Glyph_Too_Big );
+
+    maxScale = FT_DivFix( CF2_MAX_SIZE, cf2_intToFixed( unitsPerEm ) );
+
+    if ( transform->a > maxScale || transform->d > maxScale )
+      return FT_THROW( Glyph_Too_Big );
+
+    return FT_Err_Ok;
+  }
+
+
+  static void
+  cf2_setGlyphWidth( CF2_Outline  outline,
+                     CF2_Fixed    width )
+  {
+    CFF_Decoder*  decoder = outline->decoder;
+
+
+    FT_ASSERT( decoder );
+
+    decoder->glyph_width = cf2_fixedToInt( width );
+  }
+
+
+  /* Clean up font instance. */
+  static void
+  cf2_free_instance( void*  ptr )
+  {
+    CF2_Font  font = (CF2_Font)ptr;
+
+
+    if ( font )
+    {
+      FT_Memory  memory = font->memory;
+
+
+      FT_FREE( font->blend.lastNDV );
+      FT_FREE( font->blend.BV );
+    }
+  }
+
+
+  /********************************************/
+  /*                                          */
+  /* functions for handling client outline;   */
+  /* FreeType uses coordinates in 26.6 format */
+  /*                                          */
+  /********************************************/
+
+  static void
+  cf2_builder_moveTo( CF2_OutlineCallbacks      callbacks,
+                      const CF2_CallbackParams  params )
+  {
+    /* downcast the object pointer */
+    CF2_Outline   outline = (CF2_Outline)callbacks;
+    CFF_Builder*  builder;
+
+    (void)params;        /* only used in debug mode */
+
+
+    FT_ASSERT( outline && outline->decoder );
+    FT_ASSERT( params->op == CF2_PathOpMoveTo );
+
+    builder = &outline->decoder->builder;
+
+    /* note: two successive moves simply close the contour twice */
+    cff_builder_close_contour( builder );
+    builder->path_begun = 0;
+  }
+
+
+  static void
+  cf2_builder_lineTo( CF2_OutlineCallbacks      callbacks,
+                      const CF2_CallbackParams  params )
+  {
+    FT_Error  error;
+
+    /* downcast the object pointer */
+    CF2_Outline   outline = (CF2_Outline)callbacks;
+    CFF_Builder*  builder;
+
+
+    FT_ASSERT( outline && outline->decoder );
+    FT_ASSERT( params->op == CF2_PathOpLineTo );
+
+    builder = &outline->decoder->builder;
+
+    if ( !builder->path_begun )
+    {
+      /* record the move before the line; also check points and set */
+      /* `path_begun'                                               */
+      error = cff_builder_start_point( builder,
+                                       params->pt0.x,
+                                       params->pt0.y );
+      if ( error )
+      {
+        if ( !*callbacks->error )
+          *callbacks->error =  error;
+        return;
+      }
+    }
+
+    /* `cff_builder_add_point1' includes a check_points call for one point */
+    error = cff_builder_add_point1( builder,
+                                    params->pt1.x,
+                                    params->pt1.y );
+    if ( error )
+    {
+      if ( !*callbacks->error )
+        *callbacks->error =  error;
+      return;
+    }
+  }
+
+
+  static void
+  cf2_builder_cubeTo( CF2_OutlineCallbacks      callbacks,
+                      const CF2_CallbackParams  params )
+  {
+    FT_Error  error;
+
+    /* downcast the object pointer */
+    CF2_Outline   outline = (CF2_Outline)callbacks;
+    CFF_Builder*  builder;
+
+
+    FT_ASSERT( outline && outline->decoder );
+    FT_ASSERT( params->op == CF2_PathOpCubeTo );
+
+    builder = &outline->decoder->builder;
+
+    if ( !builder->path_begun )
+    {
+      /* record the move before the line; also check points and set */
+      /* `path_begun'                                               */
+      error = cff_builder_start_point( builder,
+                                       params->pt0.x,
+                                       params->pt0.y );
+      if ( error )
+      {
+        if ( !*callbacks->error )
+          *callbacks->error =  error;
+        return;
+      }
+    }
+
+    /* prepare room for 3 points: 2 off-curve, 1 on-curve */
+    error = cff_check_points( builder, 3 );
+    if ( error )
+    {
+      if ( !*callbacks->error )
+        *callbacks->error =  error;
+      return;
+    }
+
+    cff_builder_add_point( builder,
+                           params->pt1.x,
+                           params->pt1.y, 0 );
+    cff_builder_add_point( builder,
+                           params->pt2.x,
+                           params->pt2.y, 0 );
+    cff_builder_add_point( builder,
+                           params->pt3.x,
+                           params->pt3.y, 1 );
+  }
+
+
+  static void
+  cf2_outline_init( CF2_Outline  outline,
+                    FT_Memory    memory,
+                    FT_Error*    error )
+  {
+    FT_ZERO( outline );
+
+    outline->root.memory = memory;
+    outline->root.error  = error;
+
+    outline->root.moveTo = cf2_builder_moveTo;
+    outline->root.lineTo = cf2_builder_lineTo;
+    outline->root.cubeTo = cf2_builder_cubeTo;
+  }
+
+
+  /* get scaling and hint flag from GlyphSlot */
+  static void
+  cf2_getScaleAndHintFlag( CFF_Decoder*  decoder,
+                           CF2_Fixed*    x_scale,
+                           CF2_Fixed*    y_scale,
+                           FT_Bool*      hinted,
+                           FT_Bool*      scaled )
+  {
+    FT_ASSERT( decoder && decoder->builder.glyph );
+
+    /* note: FreeType scale includes a factor of 64 */
+    *hinted = decoder->builder.glyph->hint;
+    *scaled = decoder->builder.glyph->scaled;
+
+    if ( *hinted )
+    {
+      *x_scale = ADD_INT32( decoder->builder.glyph->x_scale, 32 ) / 64;
+      *y_scale = ADD_INT32( decoder->builder.glyph->y_scale, 32 ) / 64;
+    }
+    else
+    {
+      /* for unhinted outlines, `cff_slot_load' does the scaling, */
+      /* thus render at `unity' scale                             */
+
+      *x_scale = 0x0400;   /* 1/64 as 16.16 */
+      *y_scale = 0x0400;
+    }
+  }
+
+
+  /* get units per em from `FT_Face' */
+  /* TODO: should handle font matrix concatenation? */
+  static FT_UShort
+  cf2_getUnitsPerEm( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->builder.face );
+    FT_ASSERT( decoder->builder.face->root.units_per_EM );
+
+    return decoder->builder.face->root.units_per_EM;
+  }
+
+
+  /* Main entry point: Render one glyph. */
+  FT_LOCAL_DEF( FT_Error )
+  cf2_decoder_parse_charstrings( CFF_Decoder*  decoder,
+                                 FT_Byte*      charstring_base,
+                                 FT_ULong      charstring_len )
+  {
+    FT_Memory  memory;
+    FT_Error   error = FT_Err_Ok;
+    CF2_Font   font;
+
+
+    FT_ASSERT( decoder && decoder->cff );
+
+    memory = decoder->builder.memory;
+
+    /* CF2 data is saved here across glyphs */
+    font = (CF2_Font)decoder->cff->cf2_instance.data;
+
+    /* on first glyph, allocate instance structure */
+    if ( !decoder->cff->cf2_instance.data )
+    {
+      decoder->cff->cf2_instance.finalizer =
+        (FT_Generic_Finalizer)cf2_free_instance;
+
+      if ( FT_ALLOC( decoder->cff->cf2_instance.data,
+                     sizeof ( CF2_FontRec ) ) )
+        return FT_THROW( Out_Of_Memory );
+
+      font = (CF2_Font)decoder->cff->cf2_instance.data;
+
+      font->memory = memory;
+      font->cffload = (FT_Service_CFFLoad)decoder->cff->cffload;
+
+      /* initialize a client outline, to be shared by each glyph rendered */
+      cf2_outline_init( &font->outline, font->memory, &font->error );
+    }
+
+    /* save decoder; it is a stack variable and will be different on each */
+    /* call                                                               */
+    font->decoder         = decoder;
+    font->outline.decoder = decoder;
+
+    {
+      /* build parameters for Adobe engine */
+
+      CFF_Builder*  builder = &decoder->builder;
+      CFF_Driver    driver  = (CFF_Driver)FT_FACE_DRIVER( builder->face );
+
+      FT_Bool  no_stem_darkening_driver =
+                 driver->no_stem_darkening;
+      FT_Char  no_stem_darkening_font =
+                 builder->face->root.internal->no_stem_darkening;
+
+      /* local error */
+      FT_Error       error2 = FT_Err_Ok;
+      CF2_BufferRec  buf;
+      CF2_Matrix     transform;
+      CF2_F16Dot16   glyphWidth;
+
+      FT_Bool  hinted;
+      FT_Bool  scaled;
+
+
+      /* FreeType has already looked up the GID; convert to         */
+      /* `RegionBuffer', assuming that the input has been validated */
+      FT_ASSERT( charstring_base + charstring_len >= charstring_base );
+
+      FT_ZERO( &buf );
+      buf.start =
+      buf.ptr   = charstring_base;
+      buf.end   = charstring_base + charstring_len;
+
+      FT_ZERO( &transform );
+
+      cf2_getScaleAndHintFlag( decoder,
+                               &transform.a,
+                               &transform.d,
+                               &hinted,
+                               &scaled );
+
+      /* copy isCFF2 boolean from TT_Face to CF2_Font */
+      font->isCFF2 = builder->face->is_cff2;
+
+      font->renderingFlags = 0;
+      if ( hinted )
+        font->renderingFlags |= CF2_FlagsHinted;
+      if ( scaled && ( !no_stem_darkening_font        ||
+                       ( no_stem_darkening_font < 0 &&
+                         !no_stem_darkening_driver  ) ) )
+        font->renderingFlags |= CF2_FlagsDarkened;
+
+      font->darkenParams[0] = driver->darken_params[0];
+      font->darkenParams[1] = driver->darken_params[1];
+      font->darkenParams[2] = driver->darken_params[2];
+      font->darkenParams[3] = driver->darken_params[3];
+      font->darkenParams[4] = driver->darken_params[4];
+      font->darkenParams[5] = driver->darken_params[5];
+      font->darkenParams[6] = driver->darken_params[6];
+      font->darkenParams[7] = driver->darken_params[7];
+
+      /* now get an outline for this glyph;      */
+      /* also get units per em to validate scale */
+      font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder );
+
+      if ( scaled )
+      {
+        error2 = cf2_checkTransform( &transform, font->unitsPerEm );
+        if ( error2 )
+          return error2;
+      }
+
+      error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth );
+      if ( error2 )
+        return FT_ERR( Invalid_File_Format );
+
+      cf2_setGlyphWidth( &font->outline, glyphWidth );
+
+      return FT_Err_Ok;
+    }
+  }
+
+
+  /* get pointer to current FreeType subfont (based on current glyphID) */
+  FT_LOCAL_DEF( CFF_SubFont )
+  cf2_getSubfont( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    return decoder->current_subfont;
+  }
+
+
+  /* get pointer to VStore structure */
+  FT_LOCAL_DEF( CFF_VStore )
+  cf2_getVStore( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->cff );
+
+    return &decoder->cff->vstore;
+  }
+
+
+  /* get maxstack value from CFF2 Top DICT */
+  FT_LOCAL_DEF( FT_UInt )
+  cf2_getMaxstack( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->cff );
+
+    return decoder->cff->top_font.font_dict.maxstack;
+  }
+
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+  /* Get normalized design vector for current render request; */
+  /* return pointer and length.                               */
+  /*                                                          */
+  /* Note: Uses FT_Fixed not CF2_Fixed for the vector.        */
+  FT_LOCAL_DEF( FT_Error )
+  cf2_getNormalizedVector( CFF_Decoder*  decoder,
+                           CF2_UInt     *len,
+                           FT_Fixed*    *vec )
+  {
+    TT_Face  face;
+    FT_Service_MultiMasters  mm;
+
+    FT_ASSERT( decoder && decoder->builder.face );
+    FT_ASSERT( vec && len );
+    
+    face = decoder->builder.face;
+    mm = (FT_Service_MultiMasters)face->mm;
+    
+    return mm->get_var_blend( FT_FACE( face ), len, NULL, vec, NULL );
+  }
+#endif
+
+
+  /* get `y_ppem' from `CFF_Size' */
+  FT_LOCAL_DEF( CF2_Fixed )
+  cf2_getPpemY( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder                          &&
+               decoder->builder.face            &&
+               decoder->builder.face->root.size );
+
+    /*
+     * Note that `y_ppem' can be zero if there wasn't a call to
+     * `FT_Set_Char_Size' or something similar.  However, this isn't a
+     * problem since we come to this place in the code only if
+     * FT_LOAD_NO_SCALE is set (the other case gets caught by
+     * `cf2_checkTransform').  The ppem value is needed to compute the stem
+     * darkening, which is disabled for getting the unscaled outline.
+     *
+     */
+    return cf2_intToFixed(
+             decoder->builder.face->root.size->metrics.y_ppem );
+  }
+
+
+  /* get standard stem widths for the current subfont; */
+  /* FreeType stores these as integer font units       */
+  /* (note: variable names seem swapped)               */
+  FT_LOCAL_DEF( CF2_Fixed )
+  cf2_getStdVW( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    return cf2_intToFixed(
+             decoder->current_subfont->private_dict.standard_height );
+  }
+
+
+  FT_LOCAL_DEF( CF2_Fixed )
+  cf2_getStdHW( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    return cf2_intToFixed(
+             decoder->current_subfont->private_dict.standard_width );
+  }
+
+
+  /* note: FreeType stores 1000 times the actual value for `BlueScale' */
+  FT_LOCAL_DEF( void )
+  cf2_getBlueMetrics( CFF_Decoder*  decoder,
+                      CF2_Fixed*    blueScale,
+                      CF2_Fixed*    blueShift,
+                      CF2_Fixed*    blueFuzz )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    *blueScale = FT_DivFix(
+                   decoder->current_subfont->private_dict.blue_scale,
+                   cf2_intToFixed( 1000 ) );
+    *blueShift = cf2_intToFixed(
+                   decoder->current_subfont->private_dict.blue_shift );
+    *blueFuzz  = cf2_intToFixed(
+                   decoder->current_subfont->private_dict.blue_fuzz );
+  }
+
+
+  /* get blue values counts and arrays; the FreeType parser has validated */
+  /* the counts and verified that each is an even number                  */
+  FT_LOCAL_DEF( void )
+  cf2_getBlueValues( CFF_Decoder*  decoder,
+                     size_t*       count,
+                     FT_Pos*      *data )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    *count = decoder->current_subfont->private_dict.num_blue_values;
+    *data  = (FT_Pos*)
+               &decoder->current_subfont->private_dict.blue_values;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_getOtherBlues( CFF_Decoder*  decoder,
+                     size_t*       count,
+                     FT_Pos*      *data )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    *count = decoder->current_subfont->private_dict.num_other_blues;
+    *data  = (FT_Pos*)
+               &decoder->current_subfont->private_dict.other_blues;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_getFamilyBlues( CFF_Decoder*  decoder,
+                      size_t*       count,
+                      FT_Pos*      *data )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    *count = decoder->current_subfont->private_dict.num_family_blues;
+    *data  = (FT_Pos*)
+               &decoder->current_subfont->private_dict.family_blues;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_getFamilyOtherBlues( CFF_Decoder*  decoder,
+                           size_t*       count,
+                           FT_Pos*      *data )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    *count = decoder->current_subfont->private_dict.num_family_other_blues;
+    *data  = (FT_Pos*)
+               &decoder->current_subfont->private_dict.family_other_blues;
+  }
+
+
+  FT_LOCAL_DEF( CF2_Int )
+  cf2_getLanguageGroup( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    return decoder->current_subfont->private_dict.language_group;
+  }
+
+
+  /* convert unbiased subroutine index to `CF2_Buffer' and */
+  /* return 0 on success                                   */
+  FT_LOCAL_DEF( CF2_Int )
+  cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
+                              CF2_Int       subrNum,
+                              CF2_Buffer    buf )
+  {
+    CF2_UInt  idx;
+
+
+    FT_ASSERT( decoder );
+
+    FT_ZERO( buf );
+
+    idx = (CF2_UInt)( subrNum + decoder->globals_bias );
+    if ( idx >= decoder->num_globals )
+      return TRUE;     /* error */
+
+    FT_ASSERT( decoder->globals );
+
+    buf->start =
+    buf->ptr   = decoder->globals[idx];
+    buf->end   = decoder->globals[idx + 1];
+
+    return FALSE;      /* success */
+  }
+
+
+  /* convert AdobeStandardEncoding code to CF2_Buffer; */
+  /* used for seac component                           */
+  FT_LOCAL_DEF( FT_Error )
+  cf2_getSeacComponent( CFF_Decoder*  decoder,
+                        CF2_Int       code,
+                        CF2_Buffer    buf )
+  {
+    CF2_Int   gid;
+    FT_Byte*  charstring;
+    FT_ULong  len;
+    FT_Error  error;
+
+
+    FT_ASSERT( decoder );
+
+    FT_ZERO( buf );
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    /* Incremental fonts don't necessarily have valid charsets.        */
+    /* They use the character code, not the glyph index, in this case. */
+    if ( decoder->builder.face->root.internal->incremental_interface )
+      gid = code;
+    else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+    {
+      gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code );
+      if ( gid < 0 )
+        return FT_THROW( Invalid_Glyph_Format );
+    }
+
+    error = decoder->get_glyph_callback( decoder->builder.face,
+                                         (CF2_UInt)gid,
+                                         &charstring,
+                                         &len );
+    /* TODO: for now, just pass the FreeType error through */
+    if ( error )
+      return error;
+
+    /* assume input has been validated */
+    FT_ASSERT( charstring + len >= charstring );
+
+    buf->start = charstring;
+    buf->end   = charstring + len;
+    buf->ptr   = buf->start;
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_freeSeacComponent( CFF_Decoder*  decoder,
+                         CF2_Buffer    buf )
+  {
+    FT_ASSERT( decoder );
+
+    decoder->free_glyph_callback( decoder->builder.face,
+                                  (FT_Byte**)&buf->start,
+                                  (FT_ULong)( buf->end - buf->start ) );
+  }
+
+
+  FT_LOCAL_DEF( CF2_Int )
+  cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
+                             CF2_Int       subrNum,
+                             CF2_Buffer    buf )
+  {
+    CF2_UInt  idx;
+
+
+    FT_ASSERT( decoder );
+
+    FT_ZERO( buf );
+
+    idx = (CF2_UInt)( subrNum + decoder->locals_bias );
+    if ( idx >= decoder->num_locals )
+      return TRUE;     /* error */
+
+    FT_ASSERT( decoder->locals );
+
+    buf->start =
+    buf->ptr   = decoder->locals[idx];
+    buf->end   = decoder->locals[idx + 1];
+
+    return FALSE;      /* success */
+  }
+
+
+  FT_LOCAL_DEF( CF2_Fixed )
+  cf2_getDefaultWidthX( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    return cf2_intToFixed(
+             decoder->current_subfont->private_dict.default_width );
+  }
+
+
+  FT_LOCAL_DEF( CF2_Fixed )
+  cf2_getNominalWidthX( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->current_subfont );
+
+    return cf2_intToFixed(
+             decoder->current_subfont->private_dict.nominal_width );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_outline_reset( CF2_Outline  outline )
+  {
+    CFF_Decoder*  decoder = outline->decoder;
+
+
+    FT_ASSERT( decoder );
+
+    outline->root.windingMomentum = 0;
+
+    FT_GlyphLoader_Rewind( decoder->builder.loader );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_outline_close( CF2_Outline  outline )
+  {
+    CFF_Decoder*  decoder = outline->decoder;
+
+
+    FT_ASSERT( decoder );
+
+    cff_builder_close_contour( &decoder->builder );
+
+    FT_GlyphLoader_Add( decoder->builder.loader );
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psft.h
@@ -1,0 +1,159 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2ft.h                                                                */
+/*                                                                         */
+/*    FreeType Glue Component to Adobe's Interpreter (specification).      */
+/*                                                                         */
+/*  Copyright 2013 Adobe Systems Incorporated.                             */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2FT_H_
+#define CF2FT_H_
+
+
+#include "pstypes.h"
+
+
+  /* TODO: disable asserts for now */
+#define CF2_NDEBUG
+
+
+#include FT_SYSTEM_H
+
+#include "psglue.h"
+#include FT_INTERNAL_POSTSCRIPT_AUX_H    /* for CFF_Decoder */
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  cf2_decoder_parse_charstrings( CFF_Decoder*  decoder,
+                                 FT_Byte*      charstring_base,
+                                 FT_ULong      charstring_len );
+
+  FT_LOCAL( CFF_SubFont )
+  cf2_getSubfont( CFF_Decoder*  decoder );
+
+  FT_LOCAL( CFF_VStore )
+  cf2_getVStore( CFF_Decoder*  decoder );
+
+  FT_LOCAL( FT_UInt )
+  cf2_getMaxstack( CFF_Decoder*  decoder );
+
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+  FT_LOCAL( FT_Error )
+  cf2_getNormalizedVector( CFF_Decoder*  decoder,
+                           CF2_UInt     *len,
+                           FT_Fixed*    *vec );
+#endif
+
+  FT_LOCAL( CF2_Fixed )
+  cf2_getPpemY( CFF_Decoder*  decoder );
+  FT_LOCAL( CF2_Fixed )
+  cf2_getStdVW( CFF_Decoder*  decoder );
+  FT_LOCAL( CF2_Fixed )
+  cf2_getStdHW( CFF_Decoder*  decoder );
+
+  FT_LOCAL( void )
+  cf2_getBlueMetrics( CFF_Decoder*  decoder,
+                      CF2_Fixed*    blueScale,
+                      CF2_Fixed*    blueShift,
+                      CF2_Fixed*    blueFuzz );
+  FT_LOCAL( void )
+  cf2_getBlueValues( CFF_Decoder*  decoder,
+                     size_t*       count,
+                     FT_Pos*      *data );
+  FT_LOCAL( void )
+  cf2_getOtherBlues( CFF_Decoder*  decoder,
+                     size_t*       count,
+                     FT_Pos*      *data );
+  FT_LOCAL( void )
+  cf2_getFamilyBlues( CFF_Decoder*  decoder,
+                      size_t*       count,
+                      FT_Pos*      *data );
+  FT_LOCAL( void )
+  cf2_getFamilyOtherBlues( CFF_Decoder*  decoder,
+                           size_t*       count,
+                           FT_Pos*      *data );
+
+  FT_LOCAL( CF2_Int )
+  cf2_getLanguageGroup( CFF_Decoder*  decoder );
+
+  FT_LOCAL( CF2_Int )
+  cf2_initGlobalRegionBuffer( CFF_Decoder*  decoder,
+                              CF2_Int       subrNum,
+                              CF2_Buffer    buf );
+  FT_LOCAL( FT_Error )
+  cf2_getSeacComponent( CFF_Decoder*  decoder,
+                        CF2_Int       code,
+                        CF2_Buffer    buf );
+  FT_LOCAL( void )
+  cf2_freeSeacComponent( CFF_Decoder*  decoder,
+                         CF2_Buffer    buf );
+  FT_LOCAL( CF2_Int )
+  cf2_initLocalRegionBuffer( CFF_Decoder*  decoder,
+                             CF2_Int       subrNum,
+                             CF2_Buffer    buf );
+
+  FT_LOCAL( CF2_Fixed )
+  cf2_getDefaultWidthX( CFF_Decoder*  decoder );
+  FT_LOCAL( CF2_Fixed )
+  cf2_getNominalWidthX( CFF_Decoder*  decoder );
+
+
+  /*
+   * FreeType client outline
+   *
+   * process output from the charstring interpreter
+   */
+  typedef struct  CF2_OutlineRec_
+  {
+    CF2_OutlineCallbacksRec  root;        /* base class must be first */
+    CFF_Decoder*             decoder;
+
+  } CF2_OutlineRec, *CF2_Outline;
+
+
+  FT_LOCAL( void )
+  cf2_outline_reset( CF2_Outline  outline );
+  FT_LOCAL( void )
+  cf2_outline_close( CF2_Outline  outline );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2FT_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psglue.h
@@ -1,0 +1,144 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2glue.h                                                              */
+/*                                                                         */
+/*    Adobe's code for shared stuff (specification only).                  */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2GLUE_H_
+#define CF2GLUE_H_
+
+
+/* common includes for other modules */
+#include "pserror.h"
+#include "psfixed.h"
+#include "psarrst.h"
+#include "psread.h"
+
+
+FT_BEGIN_HEADER
+
+
+  /* rendering parameters */
+
+  /* apply hints to rendered glyphs */
+#define CF2_FlagsHinted    1
+  /* for testing */
+#define CF2_FlagsDarkened  2
+
+  /* type for holding the flags */
+  typedef CF2_Int  CF2_RenderingFlags;
+
+
+  /* elements of a glyph outline */
+  typedef enum  CF2_PathOp_
+  {
+    CF2_PathOpMoveTo = 1,     /* change the current point */
+    CF2_PathOpLineTo = 2,     /* line                     */
+    CF2_PathOpQuadTo = 3,     /* quadratic curve          */
+    CF2_PathOpCubeTo = 4      /* cubic curve              */
+
+  } CF2_PathOp;
+
+
+  /* a matrix of fixed point values */
+  typedef struct  CF2_Matrix_
+  {
+    CF2_F16Dot16  a;
+    CF2_F16Dot16  b;
+    CF2_F16Dot16  c;
+    CF2_F16Dot16  d;
+    CF2_F16Dot16  tx;
+    CF2_F16Dot16  ty;
+
+  } CF2_Matrix;
+
+
+  /* these typedefs are needed by more than one header file */
+  /* and gcc compiler doesn't allow redefinition            */
+  typedef struct CF2_FontRec_  CF2_FontRec, *CF2_Font;
+  typedef struct CF2_HintRec_  CF2_HintRec, *CF2_Hint;
+
+
+  /* A common structure for all callback parameters.                       */
+  /*                                                                       */
+  /* Some members may be unused.  For example, `pt0' is not used for       */
+  /* `moveTo' and `pt3' is not used for `quadTo'.  The initial point `pt0' */
+  /* is included for each path element for generality; curve conversions   */
+  /* need it.  The `op' parameter allows one function to handle multiple   */
+  /* element types.                                                        */
+
+  typedef struct  CF2_CallbackParamsRec_
+  {
+    FT_Vector  pt0;
+    FT_Vector  pt1;
+    FT_Vector  pt2;
+    FT_Vector  pt3;
+
+    CF2_Int  op;
+
+  } CF2_CallbackParamsRec, *CF2_CallbackParams;
+
+
+  /* forward reference */
+  typedef struct CF2_OutlineCallbacksRec_  CF2_OutlineCallbacksRec,
+                                           *CF2_OutlineCallbacks;
+
+  /* callback function pointers */
+  typedef void
+  (*CF2_Callback_Type)( CF2_OutlineCallbacks      callbacks,
+                        const CF2_CallbackParams  params );
+
+
+  struct  CF2_OutlineCallbacksRec_
+  {
+    CF2_Callback_Type  moveTo;
+    CF2_Callback_Type  lineTo;
+    CF2_Callback_Type  quadTo;
+    CF2_Callback_Type  cubeTo;
+
+    CF2_Int  windingMomentum;    /* for winding order detection */
+
+    FT_Memory  memory;
+    FT_Error*  error;
+  };
+
+
+FT_END_HEADER
+
+
+#endif /* CF2GLUE_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/pshints.c
@@ -1,0 +1,1875 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2hints.c                                                             */
+/*                                                                         */
+/*    Adobe's code for handling CFF hints (body).                          */
+/*                                                                         */
+/*  Copyright 2007-2014 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include FT_INTERNAL_DEBUG_H
+
+#include "psglue.h"
+#include "psfont.h"
+#include "pshints.h"
+#include "psintrp.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* 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_cf2hints
+
+
+  typedef struct  CF2_HintMoveRec_
+  {
+    size_t     j;          /* index of upper hint map edge   */
+    CF2_Fixed  moveUp;     /* adjustment to optimum position */
+
+  } CF2_HintMoveRec, *CF2_HintMove;
+
+
+  /* Compute angular momentum for winding order detection.  It is called */
+  /* for all lines and curves, but not necessarily in element order.     */
+  static CF2_Int
+  cf2_getWindingMomentum( CF2_Fixed  x1,
+                          CF2_Fixed  y1,
+                          CF2_Fixed  x2,
+                          CF2_Fixed  y2 )
+  {
+    /* cross product of pt1 position from origin with pt2 position from  */
+    /* pt1; we reduce the precision so that the result fits into 32 bits */
+
+    return ( x1 >> 16 ) * ( SUB_INT32( y2, y1 ) >> 16 ) -
+           ( y1 >> 16 ) * ( SUB_INT32( x2, x1 ) >> 16 );
+  }
+
+
+  /*
+   * Construct from a StemHint; this is used as a parameter to
+   * `cf2_blues_capture'.
+   * `hintOrigin' is the character space displacement of a seac accent.
+   * Adjust stem hint for darkening here.
+   *
+   */
+  static void
+  cf2_hint_init( CF2_Hint            hint,
+                 const CF2_ArrStack  stemHintArray,
+                 size_t              indexStemHint,
+                 const CF2_Font      font,
+                 CF2_Fixed           hintOrigin,
+                 CF2_Fixed           scale,
+                 FT_Bool             bottom )
+  {
+    CF2_Fixed               width;
+    const CF2_StemHintRec*  stemHint;
+
+
+    FT_ZERO( hint );
+
+    stemHint = (const CF2_StemHintRec*)cf2_arrstack_getPointer(
+                                         stemHintArray,
+                                         indexStemHint );
+
+    width = SUB_INT32( stemHint->max, stemHint->min );
+
+    if ( width == cf2_intToFixed( -21 ) )
+    {
+      /* ghost bottom */
+
+      if ( bottom )
+      {
+        hint->csCoord = stemHint->max;
+        hint->flags   = CF2_GhostBottom;
+      }
+      else
+        hint->flags = 0;
+    }
+
+    else if ( width == cf2_intToFixed( -20 ) )
+    {
+      /* ghost top */
+
+      if ( bottom )
+        hint->flags = 0;
+      else
+      {
+        hint->csCoord = stemHint->min;
+        hint->flags   = CF2_GhostTop;
+      }
+    }
+
+    else if ( width < 0 )
+    {
+      /* inverted pair */
+
+      /*
+       * Hints with negative widths were produced by an early version of a
+       * non-Adobe font tool.  The Type 2 spec allows edge (ghost) hints
+       * with negative widths, but says
+       *
+       *   All other negative widths have undefined meaning.
+       *
+       * CoolType has a silent workaround that negates the hint width; for
+       * permissive mode, we do the same here.
+       *
+       * Note: Such fonts cannot use ghost hints, but should otherwise work.
+       * Note: Some poor hints in our faux fonts can produce negative
+       *       widths at some blends.  For example, see a light weight of
+       *       `u' in ASerifMM.
+       *
+       */
+      if ( bottom )
+      {
+        hint->csCoord = stemHint->max;
+        hint->flags   = CF2_PairBottom;
+      }
+      else
+      {
+        hint->csCoord = stemHint->min;
+        hint->flags   = CF2_PairTop;
+      }
+    }
+
+    else
+    {
+      /* normal pair */
+
+      if ( bottom )
+      {
+        hint->csCoord = stemHint->min;
+        hint->flags   = CF2_PairBottom;
+      }
+      else
+      {
+        hint->csCoord = stemHint->max;
+        hint->flags   = CF2_PairTop;
+      }
+    }
+
+    /* Now that ghost hints have been detected, adjust this edge for      */
+    /* darkening.  Bottoms are not changed; tops are incremented by twice */
+    /* `darkenY'.                                                         */
+    if ( cf2_hint_isTop( hint ) )
+      hint->csCoord = ADD_INT32( hint->csCoord, 2 * font->darkenY );
+
+    hint->csCoord = ADD_INT32( hint->csCoord, hintOrigin );
+    hint->scale   = scale;
+    hint->index   = indexStemHint;   /* index in original stem hint array */
+
+    /* if original stem hint has been used, use the same position */
+    if ( hint->flags != 0 && stemHint->used )
+    {
+      if ( cf2_hint_isTop( hint ) )
+        hint->dsCoord = stemHint->maxDS;
+      else
+        hint->dsCoord = stemHint->minDS;
+
+      cf2_hint_lock( hint );
+    }
+    else
+      hint->dsCoord = FT_MulFix( hint->csCoord, scale );
+  }
+
+
+  /* initialize an invalid hint map element */
+  static void
+  cf2_hint_initZero( CF2_Hint  hint )
+  {
+    FT_ZERO( hint );
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  cf2_hint_isValid( const CF2_Hint  hint )
+  {
+    return (FT_Bool)( hint->flags != 0 );
+  }
+
+
+  static FT_Bool
+  cf2_hint_isPair( const CF2_Hint  hint )
+  {
+    return (FT_Bool)( ( hint->flags                      &
+                        ( CF2_PairBottom | CF2_PairTop ) ) != 0 );
+  }
+
+
+  static FT_Bool
+  cf2_hint_isPairTop( const CF2_Hint  hint )
+  {
+    return (FT_Bool)( ( hint->flags & CF2_PairTop ) != 0 );
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  cf2_hint_isTop( const CF2_Hint  hint )
+  {
+    return (FT_Bool)( ( hint->flags                    &
+                        ( CF2_PairTop | CF2_GhostTop ) ) != 0 );
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  cf2_hint_isBottom( const CF2_Hint  hint )
+  {
+    return (FT_Bool)( ( hint->flags                          &
+                        ( CF2_PairBottom | CF2_GhostBottom ) ) != 0 );
+  }
+
+
+  static FT_Bool
+  cf2_hint_isLocked( const CF2_Hint  hint )
+  {
+    return (FT_Bool)( ( hint->flags & CF2_Locked ) != 0 );
+  }
+
+
+  static FT_Bool
+  cf2_hint_isSynthetic( const CF2_Hint  hint )
+  {
+    return (FT_Bool)( ( hint->flags & CF2_Synthetic ) != 0 );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_hint_lock( CF2_Hint  hint )
+  {
+    hint->flags |= CF2_Locked;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_hintmap_init( CF2_HintMap   hintmap,
+                    CF2_Font      font,
+                    CF2_HintMap   initialMap,
+                    CF2_ArrStack  hintMoves,
+                    CF2_Fixed     scale )
+  {
+    FT_ZERO( hintmap );
+
+    /* copy parameters from font instance */
+    hintmap->hinted         = font->hinted;
+    hintmap->scale          = scale;
+    hintmap->font           = font;
+    hintmap->initialHintMap = initialMap;
+    /* will clear in `cf2_hintmap_adjustHints' */
+    hintmap->hintMoves      = hintMoves;
+  }
+
+
+  static FT_Bool
+  cf2_hintmap_isValid( const CF2_HintMap  hintmap )
+  {
+    return hintmap->isValid;
+  }
+
+
+  /* transform character space coordinate to device space using hint map */
+  static CF2_Fixed
+  cf2_hintmap_map( CF2_HintMap  hintmap,
+                   CF2_Fixed    csCoord )
+  {
+    if ( hintmap->count == 0 || ! hintmap->hinted )
+    {
+      /* there are no hints; use uniform scale and zero offset */
+      return FT_MulFix( csCoord, hintmap->scale );
+    }
+    else
+    {
+      /* start linear search from last hit */
+      CF2_UInt  i = hintmap->lastIndex;
+
+
+      FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
+
+      /* search up */
+      while ( i < hintmap->count - 1                  &&
+              csCoord >= hintmap->edge[i + 1].csCoord )
+        i += 1;
+
+      /* search down */
+      while ( i > 0 && csCoord < hintmap->edge[i].csCoord )
+        i -= 1;
+
+      hintmap->lastIndex = i;
+
+      if ( i == 0 && csCoord < hintmap->edge[0].csCoord )
+      {
+        /* special case for points below first edge: use uniform scale */
+        return ADD_INT32( FT_MulFix( SUB_INT32( csCoord,
+                                                hintmap->edge[0].csCoord ),
+                                     hintmap->scale ),
+                          hintmap->edge[0].dsCoord );
+      }
+      else
+      {
+        /*
+         * Note: entries with duplicate csCoord are allowed.
+         * Use edge[i], the highest entry where csCoord >= entry[i].csCoord
+         */
+        return ADD_INT32( FT_MulFix( SUB_INT32( csCoord,
+                                                hintmap->edge[i].csCoord ),
+                                     hintmap->edge[i].scale ),
+                          hintmap->edge[i].dsCoord );
+      }
+    }
+  }
+
+
+  /*
+   * This hinting policy moves a hint pair in device space so that one of
+   * its two edges is on a device pixel boundary (its fractional part is
+   * zero).  `cf2_hintmap_insertHint' guarantees no overlap in CS
+   * space.  Ensure here that there is no overlap in DS.
+   *
+   * In the first pass, edges are adjusted relative to adjacent hints.
+   * Those that are below have already been adjusted.  Those that are
+   * above have not yet been adjusted.  If a hint above blocks an
+   * adjustment to an optimal position, we will try again in a second
+   * pass.  The second pass is top-down.
+   *
+   */
+
+  static void
+  cf2_hintmap_adjustHints( CF2_HintMap  hintmap )
+  {
+    size_t  i, j;
+
+
+    cf2_arrstack_clear( hintmap->hintMoves );      /* working storage */
+
+    /*
+     * First pass is bottom-up (font hint order) without look-ahead.
+     * Locked edges are already adjusted.
+     * Unlocked edges begin with dsCoord from `initialHintMap'.
+     * Save edges that are not optimally adjusted in `hintMoves' array,
+     * and process them in second pass.
+     */
+
+    for ( i = 0; i < hintmap->count; i++ )
+    {
+      FT_Bool  isPair = cf2_hint_isPair( &hintmap->edge[i] );
+
+
+      /* index of upper edge (same value for ghost hint) */
+      j = isPair ? i + 1 : i;
+
+      FT_ASSERT( j < hintmap->count );
+      FT_ASSERT( cf2_hint_isValid( &hintmap->edge[i] ) );
+      FT_ASSERT( cf2_hint_isValid( &hintmap->edge[j] ) );
+      FT_ASSERT( cf2_hint_isLocked( &hintmap->edge[i] ) ==
+                   cf2_hint_isLocked( &hintmap->edge[j] ) );
+
+      if ( !cf2_hint_isLocked( &hintmap->edge[i] ) )
+      {
+        /* hint edge is not locked, we can adjust it */
+        CF2_Fixed  fracDown = cf2_fixedFraction( hintmap->edge[i].dsCoord );
+        CF2_Fixed  fracUp   = cf2_fixedFraction( hintmap->edge[j].dsCoord );
+
+        /* calculate all four possibilities; moves down are negative */
+        CF2_Fixed  downMoveDown = 0 - fracDown;
+        CF2_Fixed  upMoveDown   = 0 - fracUp;
+        CF2_Fixed  downMoveUp   = ( fracDown == 0 )
+                                    ? 0
+                                    : cf2_intToFixed( 1 ) - fracDown;
+        CF2_Fixed  upMoveUp     = ( fracUp == 0 )
+                                    ? 0
+                                    : cf2_intToFixed( 1 ) - fracUp;
+
+        /* smallest move up */
+        CF2_Fixed  moveUp   = FT_MIN( downMoveUp, upMoveUp );
+        /* smallest move down */
+        CF2_Fixed  moveDown = FT_MAX( downMoveDown, upMoveDown );
+
+        /* final amount to move edge or edge pair */
+        CF2_Fixed  move;
+
+        CF2_Fixed  downMinCounter = CF2_MIN_COUNTER;
+        CF2_Fixed  upMinCounter   = CF2_MIN_COUNTER;
+        FT_Bool    saveEdge       = FALSE;
+
+
+        /* minimum counter constraint doesn't apply when adjacent edges */
+        /* are synthetic                                                */
+        /* TODO: doesn't seem a big effect; for now, reduce the code    */
+#if 0
+        if ( i == 0                                        ||
+             cf2_hint_isSynthetic( &hintmap->edge[i - 1] ) )
+          downMinCounter = 0;
+
+        if ( j >= hintmap->count - 1                       ||
+             cf2_hint_isSynthetic( &hintmap->edge[j + 1] ) )
+          upMinCounter = 0;
+#endif
+
+        /* is there room to move up?                                    */
+        /* there is if we are at top of array or the next edge is at or */
+        /* beyond proposed move up?                                     */
+        if ( j >= hintmap->count - 1                ||
+             hintmap->edge[j + 1].dsCoord >=
+               ADD_INT32( hintmap->edge[j].dsCoord,
+                          moveUp + upMinCounter )   )
+        {
+          /* there is room to move up; is there also room to move down? */
+          if ( i == 0                                   ||
+               hintmap->edge[i - 1].dsCoord <=
+                 ADD_INT32( hintmap->edge[i].dsCoord,
+                            moveDown - downMinCounter ) )
+          {
+            /* move smaller absolute amount */
+            move = ( -moveDown < moveUp ) ? moveDown : moveUp;  /* optimum */
+          }
+          else
+            move = moveUp;
+        }
+        else
+        {
+          /* is there room to move down? */
+          if ( i == 0                                   ||
+               hintmap->edge[i - 1].dsCoord <=
+                 ADD_INT32( hintmap->edge[i].dsCoord,
+                            moveDown - downMinCounter ) )
+          {
+            move     = moveDown;
+            /* true if non-optimum move */
+            saveEdge = (FT_Bool)( moveUp < -moveDown );
+          }
+          else
+          {
+            /* no room to move either way without overlapping or reducing */
+            /* the counter too much                                       */
+            move     = 0;
+            saveEdge = TRUE;
+          }
+        }
+
+        /* Identify non-moves and moves down that aren't optimal, and save */
+        /* them for second pass.                                           */
+        /* Do this only if there is an unlocked edge above (which could    */
+        /* possibly move).                                                 */
+        if ( saveEdge                                    &&
+             j < hintmap->count - 1                      &&
+             !cf2_hint_isLocked( &hintmap->edge[j + 1] ) )
+        {
+          CF2_HintMoveRec  savedMove;
+
+
+          savedMove.j      = j;
+          /* desired adjustment in second pass */
+          savedMove.moveUp = moveUp - move;
+
+          cf2_arrstack_push( hintmap->hintMoves, &savedMove );
+        }
+
+        /* move the edge(s) */
+        hintmap->edge[i].dsCoord = ADD_INT32( hintmap->edge[i].dsCoord,
+                                              move );
+        if ( isPair )
+          hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord,
+                                                move );
+      }
+
+      /* assert there are no overlaps in device space */
+      FT_ASSERT( i == 0                                                   ||
+                 hintmap->edge[i - 1].dsCoord <= hintmap->edge[i].dsCoord );
+      FT_ASSERT( i < j                                                ||
+                 hintmap->edge[i].dsCoord <= hintmap->edge[j].dsCoord );
+
+      /* adjust the scales, avoiding divide by zero */
+      if ( i > 0 )
+      {
+        if ( hintmap->edge[i].csCoord != hintmap->edge[i - 1].csCoord )
+          hintmap->edge[i - 1].scale =
+            FT_DivFix( SUB_INT32( hintmap->edge[i].dsCoord,
+                                  hintmap->edge[i - 1].dsCoord ),
+                       SUB_INT32( hintmap->edge[i].csCoord,
+                                  hintmap->edge[i - 1].csCoord ) );
+      }
+
+      if ( isPair )
+      {
+        if ( hintmap->edge[j].csCoord != hintmap->edge[j - 1].csCoord )
+          hintmap->edge[j - 1].scale =
+            FT_DivFix( SUB_INT32( hintmap->edge[j].dsCoord,
+                                  hintmap->edge[j - 1].dsCoord ),
+                       SUB_INT32( hintmap->edge[j].csCoord,
+                                  hintmap->edge[j - 1].csCoord ) );
+
+        i += 1;     /* skip upper edge on next loop */
+      }
+    }
+
+    /* second pass tries to move non-optimal hints up, in case there is */
+    /* room now                                                         */
+    for ( i = cf2_arrstack_size( hintmap->hintMoves ); i > 0; i-- )
+    {
+      CF2_HintMove  hintMove = (CF2_HintMove)
+                      cf2_arrstack_getPointer( hintmap->hintMoves, i - 1 );
+
+
+      j = hintMove->j;
+
+      /* this was tested before the push, above */
+      FT_ASSERT( j < hintmap->count - 1 );
+
+      /* is there room to move up? */
+      if ( hintmap->edge[j + 1].dsCoord >=
+             ADD_INT32( hintmap->edge[j].dsCoord,
+                        hintMove->moveUp + CF2_MIN_COUNTER ) )
+      {
+        /* there is more room now, move edge up */
+        hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord,
+                                              hintMove->moveUp );
+
+        if ( cf2_hint_isPair( &hintmap->edge[j] ) )
+        {
+          FT_ASSERT( j > 0 );
+          hintmap->edge[j - 1].dsCoord =
+            ADD_INT32( hintmap->edge[j - 1].dsCoord, hintMove->moveUp );
+        }
+      }
+    }
+  }
+
+
+  /* insert hint edges into map, sorted by csCoord */
+  static void
+  cf2_hintmap_insertHint( CF2_HintMap  hintmap,
+                          CF2_Hint     bottomHintEdge,
+                          CF2_Hint     topHintEdge )
+  {
+    CF2_UInt  indexInsert;
+
+    /* set default values, then check for edge hints */
+    FT_Bool   isPair         = TRUE;
+    CF2_Hint  firstHintEdge  = bottomHintEdge;
+    CF2_Hint  secondHintEdge = topHintEdge;
+
+
+    /* one or none of the input params may be invalid when dealing with */
+    /* edge hints; at least one edge must be valid                      */
+    FT_ASSERT( cf2_hint_isValid( bottomHintEdge ) ||
+               cf2_hint_isValid( topHintEdge )    );
+
+    /* determine how many and which edges to insert */
+    if ( !cf2_hint_isValid( bottomHintEdge ) )
+    {
+      /* insert only the top edge */
+      firstHintEdge = topHintEdge;
+      isPair        = FALSE;
+    }
+    else if ( !cf2_hint_isValid( topHintEdge ) )
+    {
+      /* insert only the bottom edge */
+      isPair = FALSE;
+    }
+
+    /* paired edges must be in proper order */
+    if ( isPair                                         &&
+         topHintEdge->csCoord < bottomHintEdge->csCoord )
+      return;
+
+    /* linear search to find index value of insertion point */
+    indexInsert = 0;
+    for ( ; indexInsert < hintmap->count; indexInsert++ )
+    {
+      if ( hintmap->edge[indexInsert].csCoord >= firstHintEdge->csCoord )
+        break;
+    }
+
+    /*
+     * Discard any hints that overlap in character space.  Most often, this
+     * is while building the initial map, where captured hints from all
+     * zones are combined.  Define overlap to include hints that `touch'
+     * (overlap zero).  Hiragino Sans/Gothic fonts have numerous hints that
+     * touch.  Some fonts have non-ideographic glyphs that overlap our
+     * synthetic hints.
+     *
+     * Overlap also occurs when darkening stem hints that are close.
+     *
+     */
+    if ( indexInsert < hintmap->count )
+    {
+      /* we are inserting before an existing edge:    */
+      /* verify that an existing edge is not the same */
+      if ( hintmap->edge[indexInsert].csCoord == firstHintEdge->csCoord )
+        return; /* ignore overlapping stem hint */
+
+      /* verify that a new pair does not straddle the next edge */
+      if ( isPair                                                        &&
+           hintmap->edge[indexInsert].csCoord <= secondHintEdge->csCoord )
+        return; /* ignore overlapping stem hint */
+
+      /* verify that we are not inserting between paired edges */
+      if ( cf2_hint_isPairTop( &hintmap->edge[indexInsert] ) )
+        return; /* ignore overlapping stem hint */
+    }
+
+    /* recompute device space locations using initial hint map */
+    if ( cf2_hintmap_isValid( hintmap->initialHintMap ) &&
+         !cf2_hint_isLocked( firstHintEdge )            )
+    {
+      if ( isPair )
+      {
+        /* Use hint map to position the center of stem, and nominal scale */
+        /* to position the two edges.  This preserves the stem width.     */
+        CF2_Fixed  midpoint =
+                     cf2_hintmap_map(
+                       hintmap->initialHintMap,
+                       ADD_INT32( secondHintEdge->csCoord,
+                                  firstHintEdge->csCoord ) / 2 );
+        CF2_Fixed  halfWidth =
+                     FT_MulFix( SUB_INT32( secondHintEdge->csCoord,
+                                           firstHintEdge->csCoord ) / 2,
+                                hintmap->scale );
+
+
+        firstHintEdge->dsCoord  = SUB_INT32( midpoint, halfWidth );
+        secondHintEdge->dsCoord = ADD_INT32( midpoint, halfWidth );
+      }
+      else
+        firstHintEdge->dsCoord = cf2_hintmap_map( hintmap->initialHintMap,
+                                                  firstHintEdge->csCoord );
+    }
+
+    /*
+     * Discard any hints that overlap in device space; this can occur
+     * because locked hints have been moved to align with blue zones.
+     *
+     * TODO: Although we might correct this later during adjustment, we
+     * don't currently have a way to delete a conflicting hint once it has
+     * been inserted.  See v2.030 MinionPro-Regular, 12 ppem darkened,
+     * initial hint map for second path, glyph 945 (the perispomeni (tilde)
+     * in U+1F6E, Greek omega with psili and perispomeni).  Darkening is
+     * 25.  Pair 667,747 initially conflicts in design space with top edge
+     * 660.  This is because 667 maps to 7.87, and the top edge was
+     * captured by a zone at 8.0.  The pair is later successfully inserted
+     * in a zone without the top edge.  In this zone it is adjusted to 8.0,
+     * and no longer conflicts with the top edge in design space.  This
+     * means it can be included in yet a later zone which does have the top
+     * edge hint.  This produces a small mismatch between the first and
+     * last points of this path, even though the hint masks are the same.
+     * The density map difference is tiny (1/256).
+     *
+     */
+
+    if ( indexInsert > 0 )
+    {
+      /* we are inserting after an existing edge */
+      if ( firstHintEdge->dsCoord < hintmap->edge[indexInsert - 1].dsCoord )
+        return;
+    }
+
+    if ( indexInsert < hintmap->count )
+    {
+      /* we are inserting before an existing edge */
+      if ( isPair )
+      {
+        if ( secondHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord )
+          return;
+      }
+      else
+      {
+        if ( firstHintEdge->dsCoord > hintmap->edge[indexInsert].dsCoord )
+          return;
+      }
+    }
+
+    /* make room to insert */
+    {
+      CF2_UInt  iSrc = hintmap->count - 1;
+      CF2_UInt  iDst = isPair ? hintmap->count + 1 : hintmap->count;
+
+      CF2_UInt  count = hintmap->count - indexInsert;
+
+
+      if ( iDst >= CF2_MAX_HINT_EDGES )
+      {
+        FT_TRACE4(( "cf2_hintmap_insertHint: too many hintmaps\n" ));
+        return;
+      }
+
+      while ( count-- )
+        hintmap->edge[iDst--] = hintmap->edge[iSrc--];
+
+      /* insert first edge */
+      hintmap->edge[indexInsert] = *firstHintEdge;         /* copy struct */
+      hintmap->count            += 1;
+
+      if ( isPair )
+      {
+        /* insert second edge */
+        hintmap->edge[indexInsert + 1] = *secondHintEdge;  /* copy struct */
+        hintmap->count                += 1;
+      }
+    }
+
+    return;
+  }
+
+
+  /*
+   * Build a map from hints and mask.
+   *
+   * This function may recur one level if `hintmap->initialHintMap' is not yet
+   * valid.
+   * If `initialMap' is true, simply build initial map.
+   *
+   * Synthetic hints are used in two ways.  A hint at zero is inserted, if
+   * needed, in the initial hint map, to prevent translations from
+   * propagating across the origin.  If synthetic em box hints are enabled
+   * for ideographic dictionaries, then they are inserted in all hint
+   * maps, including the initial one.
+   *
+   */
+  FT_LOCAL_DEF( void )
+  cf2_hintmap_build( CF2_HintMap   hintmap,
+                     CF2_ArrStack  hStemHintArray,
+                     CF2_ArrStack  vStemHintArray,
+                     CF2_HintMask  hintMask,
+                     CF2_Fixed     hintOrigin,
+                     FT_Bool       initialMap )
+  {
+    FT_Byte*  maskPtr;
+
+    CF2_Font         font = hintmap->font;
+    CF2_HintMaskRec  tempHintMask;
+
+    size_t   bitCount, i;
+    FT_Byte  maskByte;
+
+
+    /* check whether initial map is constructed */
+    if ( !initialMap && !cf2_hintmap_isValid( hintmap->initialHintMap ) )
+    {
+      /* make recursive call with initialHintMap and temporary mask; */
+      /* temporary mask will get all bits set, below */
+      cf2_hintmask_init( &tempHintMask, hintMask->error );
+      cf2_hintmap_build( hintmap->initialHintMap,
+                         hStemHintArray,
+                         vStemHintArray,
+                         &tempHintMask,
+                         hintOrigin,
+                         TRUE );
+    }
+
+    if ( !cf2_hintmask_isValid( hintMask ) )
+    {
+      /* without a hint mask, assume all hints are active */
+      cf2_hintmask_setAll( hintMask,
+                           cf2_arrstack_size( hStemHintArray ) +
+                             cf2_arrstack_size( vStemHintArray ) );
+      if ( !cf2_hintmask_isValid( hintMask ) )
+        return;                   /* too many stem hints */
+    }
+
+    /* begin by clearing the map */
+    hintmap->count     = 0;
+    hintmap->lastIndex = 0;
+
+    /* make a copy of the hint mask so we can modify it */
+    tempHintMask = *hintMask;
+    maskPtr      = cf2_hintmask_getMaskPtr( &tempHintMask );
+
+    /* use the hStem hints only, which are first in the mask */
+    bitCount = cf2_arrstack_size( hStemHintArray );
+
+    /* Defense-in-depth.  Should never return here. */
+    if ( bitCount > hintMask->bitCount )
+      return;
+
+    /* synthetic embox hints get highest priority */
+    if ( font->blues.doEmBoxHints )
+    {
+      CF2_HintRec  dummy;
+
+
+      cf2_hint_initZero( &dummy );   /* invalid hint map element */
+
+      /* ghost bottom */
+      cf2_hintmap_insertHint( hintmap,
+                              &font->blues.emBoxBottomEdge,
+                              &dummy );
+      /* ghost top */
+      cf2_hintmap_insertHint( hintmap,
+                              &dummy,
+                              &font->blues.emBoxTopEdge );
+    }
+
+    /* insert hints captured by a blue zone or already locked (higher */
+    /* priority)                                                      */
+    for ( i = 0, maskByte = 0x80; i < bitCount; i++ )
+    {
+      if ( maskByte & *maskPtr )
+      {
+        /* expand StemHint into two `CF2_Hint' elements */
+        CF2_HintRec  bottomHintEdge, topHintEdge;
+
+
+        cf2_hint_init( &bottomHintEdge,
+                       hStemHintArray,
+                       i,
+                       font,
+                       hintOrigin,
+                       hintmap->scale,
+                       TRUE /* bottom */ );
+        cf2_hint_init( &topHintEdge,
+                       hStemHintArray,
+                       i,
+                       font,
+                       hintOrigin,
+                       hintmap->scale,
+                       FALSE /* top */ );
+
+        if ( cf2_hint_isLocked( &bottomHintEdge ) ||
+             cf2_hint_isLocked( &topHintEdge )    ||
+             cf2_blues_capture( &font->blues,
+                                &bottomHintEdge,
+                                &topHintEdge )   )
+        {
+          /* insert captured hint into map */
+          cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
+
+          *maskPtr &= ~maskByte;      /* turn off the bit for this hint */
+        }
+      }
+
+      if ( ( i & 7 ) == 7 )
+      {
+        /* move to next mask byte */
+        maskPtr++;
+        maskByte = 0x80;
+      }
+      else
+        maskByte >>= 1;
+    }
+
+    /* initial hint map includes only captured hints plus maybe one at 0 */
+
+    /*
+     * TODO: There is a problem here because we are trying to build a
+     *       single hint map containing all captured hints.  It is
+     *       possible for there to be conflicts between captured hints,
+     *       either because of darkening or because the hints are in
+     *       separate hint zones (we are ignoring hint zones for the
+     *       initial map).  An example of the latter is MinionPro-Regular
+     *       v2.030 glyph 883 (Greek Capital Alpha with Psili) at 15ppem.
+     *       A stem hint for the psili conflicts with the top edge hint
+     *       for the base character.  The stem hint gets priority because
+     *       of its sort order.  In glyph 884 (Greek Capital Alpha with
+     *       Psili and Oxia), the top of the base character gets a stem
+     *       hint, and the psili does not.  This creates different initial
+     *       maps for the two glyphs resulting in different renderings of
+     *       the base character.  Will probably defer this either as not
+     *       worth the cost or as a font bug.  I don't think there is any
+     *       good reason for an accent to be captured by an alignment
+     *       zone.  -darnold 2/12/10
+     */
+
+    if ( initialMap )
+    {
+      /* Apply a heuristic that inserts a point for (0,0), unless it's     */
+      /* already covered by a mapping.  This locks the baseline for glyphs */
+      /* that have no baseline hints.                                      */
+
+      if ( hintmap->count == 0                           ||
+           hintmap->edge[0].csCoord > 0                  ||
+           hintmap->edge[hintmap->count - 1].csCoord < 0 )
+      {
+        /* all edges are above 0 or all edges are below 0; */
+        /* construct a locked edge hint at 0               */
+
+        CF2_HintRec  edge, invalid;
+
+
+        cf2_hint_initZero( &edge );
+
+        edge.flags = CF2_GhostBottom |
+                     CF2_Locked      |
+                     CF2_Synthetic;
+        edge.scale = hintmap->scale;
+
+        cf2_hint_initZero( &invalid );
+        cf2_hintmap_insertHint( hintmap, &edge, &invalid );
+      }
+    }
+    else
+    {
+      /* insert remaining hints */
+
+      maskPtr = cf2_hintmask_getMaskPtr( &tempHintMask );
+
+      for ( i = 0, maskByte = 0x80; i < bitCount; i++ )
+      {
+        if ( maskByte & *maskPtr )
+        {
+          CF2_HintRec  bottomHintEdge, topHintEdge;
+
+
+          cf2_hint_init( &bottomHintEdge,
+                         hStemHintArray,
+                         i,
+                         font,
+                         hintOrigin,
+                         hintmap->scale,
+                         TRUE /* bottom */ );
+          cf2_hint_init( &topHintEdge,
+                         hStemHintArray,
+                         i,
+                         font,
+                         hintOrigin,
+                         hintmap->scale,
+                         FALSE /* top */ );
+
+          cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
+        }
+
+        if ( ( i & 7 ) == 7 )
+        {
+          /* move to next mask byte */
+          maskPtr++;
+          maskByte = 0x80;
+        }
+        else
+          maskByte >>= 1;
+      }
+    }
+
+    /*
+     * Note: The following line is a convenient place to break when
+     *       debugging hinting.  Examine `hintmap->edge' for the list of
+     *       enabled hints, then step over the call to see the effect of
+     *       adjustment.  We stop here first on the recursive call that
+     *       creates the initial map, and then on each counter group and
+     *       hint zone.
+     */
+
+    /* adjust positions of hint edges that are not locked to blue zones */
+    cf2_hintmap_adjustHints( hintmap );
+
+    /* save the position of all hints that were used in this hint map; */
+    /* if we use them again, we'll locate them in the same position    */
+    if ( !initialMap )
+    {
+      for ( i = 0; i < hintmap->count; i++ )
+      {
+        if ( !cf2_hint_isSynthetic( &hintmap->edge[i] ) )
+        {
+          /* Note: include both valid and invalid edges            */
+          /* Note: top and bottom edges are copied back separately */
+          CF2_StemHint  stemhint = (CF2_StemHint)
+                          cf2_arrstack_getPointer( hStemHintArray,
+                                                   hintmap->edge[i].index );
+
+
+          if ( cf2_hint_isTop( &hintmap->edge[i] ) )
+            stemhint->maxDS = hintmap->edge[i].dsCoord;
+          else
+            stemhint->minDS = hintmap->edge[i].dsCoord;
+
+          stemhint->used = TRUE;
+        }
+      }
+    }
+
+    /* hint map is ready to use */
+    hintmap->isValid = TRUE;
+
+    /* remember this mask has been used */
+    cf2_hintmask_setNew( hintMask, FALSE );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_glyphpath_init( CF2_GlyphPath         glyphpath,
+                      CF2_Font              font,
+                      CF2_OutlineCallbacks  callbacks,
+                      CF2_Fixed             scaleY,
+                      /* CF2_Fixed  hShift, */
+                      CF2_ArrStack          hStemHintArray,
+                      CF2_ArrStack          vStemHintArray,
+                      CF2_HintMask          hintMask,
+                      CF2_Fixed             hintOriginY,
+                      const CF2_Blues       blues,
+                      const FT_Vector*      fractionalTranslation )
+  {
+    FT_ZERO( glyphpath );
+
+    glyphpath->font      = font;
+    glyphpath->callbacks = callbacks;
+
+    cf2_arrstack_init( &glyphpath->hintMoves,
+                       font->memory,
+                       &font->error,
+                       sizeof ( CF2_HintMoveRec ) );
+
+    cf2_hintmap_init( &glyphpath->initialHintMap,
+                      font,
+                      &glyphpath->initialHintMap,
+                      &glyphpath->hintMoves,
+                      scaleY );
+    cf2_hintmap_init( &glyphpath->firstHintMap,
+                      font,
+                      &glyphpath->initialHintMap,
+                      &glyphpath->hintMoves,
+                      scaleY );
+    cf2_hintmap_init( &glyphpath->hintMap,
+                      font,
+                      &glyphpath->initialHintMap,
+                      &glyphpath->hintMoves,
+                      scaleY );
+
+    glyphpath->scaleX = font->innerTransform.a;
+    glyphpath->scaleC = font->innerTransform.c;
+    glyphpath->scaleY = font->innerTransform.d;
+
+    glyphpath->fractionalTranslation = *fractionalTranslation;
+
+#if 0
+    glyphpath->hShift = hShift;       /* for fauxing */
+#endif
+
+    glyphpath->hStemHintArray = hStemHintArray;
+    glyphpath->vStemHintArray = vStemHintArray;
+    glyphpath->hintMask       = hintMask;      /* ptr to current mask */
+    glyphpath->hintOriginY    = hintOriginY;
+    glyphpath->blues          = blues;
+    glyphpath->darken         = font->darkened; /* TODO: should we make copies? */
+    glyphpath->xOffset        = font->darkenX;
+    glyphpath->yOffset        = font->darkenY;
+    glyphpath->miterLimit     = 2 * FT_MAX(
+                                     cf2_fixedAbs( glyphpath->xOffset ),
+                                     cf2_fixedAbs( glyphpath->yOffset ) );
+
+    /* .1 character space unit */
+    glyphpath->snapThreshold = cf2_doubleToFixed( 0.1 );
+
+    glyphpath->moveIsPending = TRUE;
+    glyphpath->pathIsOpen    = FALSE;
+    glyphpath->pathIsClosing = FALSE;
+    glyphpath->elemIsQueued  = FALSE;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_glyphpath_finalize( CF2_GlyphPath  glyphpath )
+  {
+    cf2_arrstack_finalize( &glyphpath->hintMoves );
+  }
+
+
+  /*
+   * Hint point in y-direction and apply outerTransform.
+   * Input `current' hint map (which is actually delayed by one element).
+   * Input x,y point in Character Space.
+   * Output x,y point in Device Space, including translation.
+   */
+  static void
+  cf2_glyphpath_hintPoint( CF2_GlyphPath  glyphpath,
+                           CF2_HintMap    hintmap,
+                           FT_Vector*     ppt,
+                           CF2_Fixed      x,
+                           CF2_Fixed      y )
+  {
+    FT_Vector  pt;   /* hinted point in upright DS */
+
+
+    pt.x = ADD_INT32( FT_MulFix( glyphpath->scaleX, x ),
+                      FT_MulFix( glyphpath->scaleC, y ) );
+    pt.y = cf2_hintmap_map( hintmap, y );
+
+    ppt->x = ADD_INT32(
+               FT_MulFix( glyphpath->font->outerTransform.a, pt.x ),
+               ADD_INT32(
+                 FT_MulFix( glyphpath->font->outerTransform.c, pt.y ),
+                 glyphpath->fractionalTranslation.x ) );
+    ppt->y = ADD_INT32(
+               FT_MulFix( glyphpath->font->outerTransform.b, pt.x ),
+               ADD_INT32(
+                 FT_MulFix( glyphpath->font->outerTransform.d, pt.y ),
+                 glyphpath->fractionalTranslation.y ) );
+  }
+
+
+  /*
+   * From two line segments, (u1,u2) and (v1,v2), compute a point of
+   * intersection on the corresponding lines.
+   * Return false if no intersection is found, or if the intersection is
+   * too far away from the ends of the line segments, u2 and v1.
+   *
+   */
+  static FT_Bool
+  cf2_glyphpath_computeIntersection( CF2_GlyphPath     glyphpath,
+                                     const FT_Vector*  u1,
+                                     const FT_Vector*  u2,
+                                     const FT_Vector*  v1,
+                                     const FT_Vector*  v2,
+                                     FT_Vector*        intersection )
+  {
+    /*
+     * Let `u' be a zero-based vector from the first segment, `v' from the
+     * second segment.
+     * Let `w 'be the zero-based vector from `u1' to `v1'.
+     * `perp' is the `perpendicular dot product'; see
+     * http://mathworld.wolfram.com/PerpDotProduct.html.
+     * `s' is the parameter for the parametric line for the first segment
+     * (`u').
+     *
+     * See notation in
+     * http://softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm.
+     * Calculations are done in 16.16, but must handle the squaring of
+     * line lengths in character space.  We scale all vectors by 1/32 to
+     * avoid overflow.  This allows values up to 4095 to be squared.  The
+     * scale factor cancels in the divide.
+     *
+     * TODO: the scale factor could be computed from UnitsPerEm.
+     *
+     */
+
+#define cf2_perp( a, b )                                    \
+          ( FT_MulFix( a.x, b.y ) - FT_MulFix( a.y, b.x ) )
+
+  /* round and divide by 32 */
+#define CF2_CS_SCALE( x )         \
+          ( ( (x) + 0x10 ) >> 5 )
+
+    FT_Vector  u, v, w;      /* scaled vectors */
+    CF2_Fixed  denominator, s;
+
+
+    u.x = CF2_CS_SCALE( SUB_INT32( u2->x, u1->x ) );
+    u.y = CF2_CS_SCALE( SUB_INT32( u2->y, u1->y ) );
+    v.x = CF2_CS_SCALE( SUB_INT32( v2->x, v1->x ) );
+    v.y = CF2_CS_SCALE( SUB_INT32( v2->y, v1->y ) );
+    w.x = CF2_CS_SCALE( SUB_INT32( v1->x, u1->x ) );
+    w.y = CF2_CS_SCALE( SUB_INT32( v1->y, u1->y ) );
+
+    denominator = cf2_perp( u, v );
+
+    if ( denominator == 0 )
+      return FALSE;           /* parallel or coincident lines */
+
+    s = FT_DivFix( cf2_perp( w, v ), denominator );
+
+    intersection->x = ADD_INT32( u1->x,
+                                 FT_MulFix( s, SUB_INT32( u2->x, u1->x ) ) );
+    intersection->y = ADD_INT32( u1->y,
+                                 FT_MulFix( s, SUB_INT32( u2->y, u1->y ) ) );
+
+
+    /*
+     * Special case snapping for horizontal and vertical lines.
+     * This cleans up intersections and reduces problems with winding
+     * order detection.
+     * Sample case is sbc cd KozGoPr6N-Medium.otf 20 16685.
+     * Note: these calculations are in character space.
+     *
+     */
+
+    if ( u1->x == u2->x                                                &&
+         cf2_fixedAbs( SUB_INT32( intersection->x,
+                                  u1->x ) ) < glyphpath->snapThreshold )
+      intersection->x = u1->x;
+    if ( u1->y == u2->y                                                &&
+         cf2_fixedAbs( SUB_INT32( intersection->y,
+                                  u1->y ) ) < glyphpath->snapThreshold )
+      intersection->y = u1->y;
+
+    if ( v1->x == v2->x                                                &&
+         cf2_fixedAbs( SUB_INT32( intersection->x,
+                                  v1->x ) ) < glyphpath->snapThreshold )
+      intersection->x = v1->x;
+    if ( v1->y == v2->y                                                &&
+         cf2_fixedAbs( SUB_INT32( intersection->y,
+                                  v1->y ) ) < glyphpath->snapThreshold )
+      intersection->y = v1->y;
+
+    /* limit the intersection distance from midpoint of u2 and v1 */
+    if ( cf2_fixedAbs( intersection->x - ADD_INT32( u2->x, v1->x ) / 2 ) >
+           glyphpath->miterLimit                                           ||
+         cf2_fixedAbs( intersection->y - ADD_INT32( u2->y, v1->y ) / 2 ) >
+           glyphpath->miterLimit                                           )
+      return FALSE;
+
+    return TRUE;
+  }
+
+
+  /*
+   * Push the cached element (glyphpath->prevElem*) to the outline
+   * consumer.  When a darkening offset is used, the end point of the
+   * cached element may be adjusted to an intersection point or we may
+   * synthesize a connecting line to the current element.  If we are
+   * closing a subpath, we may also generate a connecting line to the start
+   * point.
+   *
+   * This is where Character Space (CS) is converted to Device Space (DS)
+   * using a hint map.  This calculation must use a HintMap that was valid
+   * at the time the element was saved.  For the first point in a subpath,
+   * that is a saved HintMap.  For most elements, it just means the caller
+   * has delayed building a HintMap from the current HintMask.
+   *
+   * Transform each point with outerTransform and call the outline
+   * callbacks.  This is a general 3x3 transform:
+   *
+   *   x' = a*x + c*y + tx, y' = b*x + d*y + ty
+   *
+   * but it uses 4 elements from CF2_Font and the translation part
+   * from CF2_GlyphPath.
+   *
+   */
+  static void
+  cf2_glyphpath_pushPrevElem( CF2_GlyphPath  glyphpath,
+                              CF2_HintMap    hintmap,
+                              FT_Vector*     nextP0,
+                              FT_Vector      nextP1,
+                              FT_Bool        close )
+  {
+    CF2_CallbackParamsRec  params;
+
+    FT_Vector*  prevP0;
+    FT_Vector*  prevP1;
+
+    FT_Vector  intersection    = { 0, 0 };
+    FT_Bool    useIntersection = FALSE;
+
+
+    FT_ASSERT( glyphpath->prevElemOp == CF2_PathOpLineTo ||
+               glyphpath->prevElemOp == CF2_PathOpCubeTo );
+
+    if ( glyphpath->prevElemOp == CF2_PathOpLineTo )
+    {
+      prevP0 = &glyphpath->prevElemP0;
+      prevP1 = &glyphpath->prevElemP1;
+    }
+    else
+    {
+      prevP0 = &glyphpath->prevElemP2;
+      prevP1 = &glyphpath->prevElemP3;
+    }
+
+    /* optimization: if previous and next elements are offset by the same */
+    /* amount, then there will be no gap, and no need to compute an       */
+    /* intersection.                                                      */
+    if ( prevP1->x != nextP0->x || prevP1->y != nextP0->y )
+    {
+      /* previous element does not join next element:             */
+      /* adjust end point of previous element to the intersection */
+      useIntersection = cf2_glyphpath_computeIntersection( glyphpath,
+                                                           prevP0,
+                                                           prevP1,
+                                                           nextP0,
+                                                           &nextP1,
+                                                           &intersection );
+      if ( useIntersection )
+      {
+        /* modify the last point of the cached element (either line or */
+        /* curve)                                                      */
+        *prevP1 = intersection;
+      }
+    }
+
+    params.pt0 = glyphpath->currentDS;
+
+    switch( glyphpath->prevElemOp )
+    {
+    case CF2_PathOpLineTo:
+      params.op = CF2_PathOpLineTo;
+
+      /* note: pt2 and pt3 are unused */
+
+      if ( close )
+      {
+        /* use first hint map if closing */
+        cf2_glyphpath_hintPoint( glyphpath,
+                                 &glyphpath->firstHintMap,
+                                 &params.pt1,
+                                 glyphpath->prevElemP1.x,
+                                 glyphpath->prevElemP1.y );
+      }
+      else
+      {
+        cf2_glyphpath_hintPoint( glyphpath,
+                                 hintmap,
+                                 &params.pt1,
+                                 glyphpath->prevElemP1.x,
+                                 glyphpath->prevElemP1.y );
+      }
+
+      /* output only non-zero length lines */
+      if ( params.pt0.x != params.pt1.x || params.pt0.y != params.pt1.y )
+      {
+        glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
+
+        glyphpath->currentDS = params.pt1;
+      }
+      break;
+
+    case CF2_PathOpCubeTo:
+      params.op = CF2_PathOpCubeTo;
+
+      /* TODO: should we intersect the interior joins (p1-p2 and p2-p3)? */
+      cf2_glyphpath_hintPoint( glyphpath,
+                               hintmap,
+                               &params.pt1,
+                               glyphpath->prevElemP1.x,
+                               glyphpath->prevElemP1.y );
+      cf2_glyphpath_hintPoint( glyphpath,
+                               hintmap,
+                               &params.pt2,
+                               glyphpath->prevElemP2.x,
+                               glyphpath->prevElemP2.y );
+      cf2_glyphpath_hintPoint( glyphpath,
+                               hintmap,
+                               &params.pt3,
+                               glyphpath->prevElemP3.x,
+                               glyphpath->prevElemP3.y );
+
+      glyphpath->callbacks->cubeTo( glyphpath->callbacks, &params );
+
+      glyphpath->currentDS = params.pt3;
+
+      break;
+    }
+
+    if ( !useIntersection || close )
+    {
+      /* insert connecting line between end of previous element and start */
+      /* of current one                                                   */
+      /* note: at the end of a subpath, we might do both, so use `nextP0' */
+      /* before we change it, below                                       */
+
+      if ( close )
+      {
+        /* if we are closing the subpath, then nextP0 is in the first     */
+        /* hint zone                                                      */
+        cf2_glyphpath_hintPoint( glyphpath,
+                                 &glyphpath->firstHintMap,
+                                 &params.pt1,
+                                 nextP0->x,
+                                 nextP0->y );
+      }
+      else
+      {
+        cf2_glyphpath_hintPoint( glyphpath,
+                                 hintmap,
+                                 &params.pt1,
+                                 nextP0->x,
+                                 nextP0->y );
+      }
+
+      if ( params.pt1.x != glyphpath->currentDS.x ||
+           params.pt1.y != glyphpath->currentDS.y )
+      {
+        /* length is nonzero */
+        params.op  = CF2_PathOpLineTo;
+        params.pt0 = glyphpath->currentDS;
+
+        /* note: pt2 and pt3 are unused */
+        glyphpath->callbacks->lineTo( glyphpath->callbacks, &params );
+
+        glyphpath->currentDS = params.pt1;
+      }
+    }
+
+    if ( useIntersection )
+    {
+      /* return intersection point to caller */
+      *nextP0 = intersection;
+    }
+  }
+
+
+  /* push a MoveTo element based on current point and offset of current */
+  /* element                                                            */
+  static void
+  cf2_glyphpath_pushMove( CF2_GlyphPath  glyphpath,
+                          FT_Vector      start )
+  {
+    CF2_CallbackParamsRec  params;
+
+
+    params.op  = CF2_PathOpMoveTo;
+    params.pt0 = glyphpath->currentDS;
+
+    /* Test if move has really happened yet; it would have called */
+    /* `cf2_hintmap_build' to set `isValid'.                   */
+    if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) )
+    {
+      /* we are here iff first subpath is missing a moveto operator: */
+      /* synthesize first moveTo to finish initialization of hintMap */
+      cf2_glyphpath_moveTo( glyphpath,
+                            glyphpath->start.x,
+                            glyphpath->start.y );
+    }
+
+    cf2_glyphpath_hintPoint( glyphpath,
+                             &glyphpath->hintMap,
+                             &params.pt1,
+                             start.x,
+                             start.y );
+
+    /* note: pt2 and pt3 are unused */
+    glyphpath->callbacks->moveTo( glyphpath->callbacks, &params );
+
+    glyphpath->currentDS    = params.pt1;
+    glyphpath->offsetStart0 = start;
+  }
+
+
+  /*
+   * All coordinates are in character space.
+   * On input, (x1, y1) and (x2, y2) give line segment.
+   * On output, (x, y) give offset vector.
+   * We use a piecewise approximation to trig functions.
+   *
+   * TODO: Offset true perpendicular and proper length
+   *       supply the y-translation for hinting here, too,
+   *       that adds yOffset unconditionally to *y.
+   */
+  static void
+  cf2_glyphpath_computeOffset( CF2_GlyphPath  glyphpath,
+                               CF2_Fixed      x1,
+                               CF2_Fixed      y1,
+                               CF2_Fixed      x2,
+                               CF2_Fixed      y2,
+                               CF2_Fixed*     x,
+                               CF2_Fixed*     y )
+  {
+    CF2_Fixed  dx = SUB_INT32( x2, x1 );
+    CF2_Fixed  dy = SUB_INT32( y2, y1 );
+
+
+    /* note: negative offsets don't work here; negate deltas to change */
+    /* quadrants, below                                                */
+    if ( glyphpath->font->reverseWinding )
+    {
+      dx = NEG_INT32( dx );
+      dy = NEG_INT32( dy );
+    }
+
+    *x = *y = 0;
+
+    if ( !glyphpath->darken )
+        return;
+
+    /* add momentum for this path element */
+    glyphpath->callbacks->windingMomentum =
+      ADD_INT32( glyphpath->callbacks->windingMomentum,
+                 cf2_getWindingMomentum( x1, y1, x2, y2 ) );
+
+    /* note: allow mixed integer and fixed multiplication here */
+    if ( dx >= 0 )
+    {
+      if ( dy >= 0 )
+      {
+        /* first quadrant, +x +y */
+
+        if ( dx > MUL_INT32( 2, dy ) )
+        {
+          /* +x */
+          *x = 0;
+          *y = 0;
+        }
+        else if ( dy > MUL_INT32( 2, dx ) )
+        {
+          /* +y */
+          *x = glyphpath->xOffset;
+          *y = glyphpath->yOffset;
+        }
+        else
+        {
+          /* +x +y */
+          *x = FT_MulFix( cf2_doubleToFixed( 0.7 ),
+                          glyphpath->xOffset );
+          *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ),
+                          glyphpath->yOffset );
+        }
+      }
+      else
+      {
+        /* fourth quadrant, +x -y */
+
+        if ( dx > MUL_INT32( -2, dy ) )
+        {
+          /* +x */
+          *x = 0;
+          *y = 0;
+        }
+        else if ( NEG_INT32( dy ) > MUL_INT32( 2, dx ) )
+        {
+          /* -y */
+          *x = NEG_INT32( glyphpath->xOffset );
+          *y = glyphpath->yOffset;
+        }
+        else
+        {
+          /* +x -y */
+          *x = FT_MulFix( cf2_doubleToFixed( -0.7 ),
+                          glyphpath->xOffset );
+          *y = FT_MulFix( cf2_doubleToFixed( 1.0 - 0.7 ),
+                          glyphpath->yOffset );
+        }
+      }
+    }
+    else
+    {
+      if ( dy >= 0 )
+      {
+        /* second quadrant, -x +y */
+
+        if ( NEG_INT32( dx ) > MUL_INT32( 2, dy ) )
+        {
+          /* -x */
+          *x = 0;
+          *y = MUL_INT32( 2, glyphpath->yOffset );
+        }
+        else if ( dy > MUL_INT32( -2, dx ) )
+        {
+          /* +y */
+          *x = glyphpath->xOffset;
+          *y = glyphpath->yOffset;
+        }
+        else
+        {
+          /* -x +y */
+          *x = FT_MulFix( cf2_doubleToFixed( 0.7 ),
+                          glyphpath->xOffset );
+          *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ),
+                          glyphpath->yOffset );
+        }
+      }
+      else
+      {
+        /* third quadrant, -x -y */
+
+        if ( NEG_INT32( dx ) > MUL_INT32( -2, dy ) )
+        {
+          /* -x */
+          *x = 0;
+          *y = MUL_INT32( 2, glyphpath->yOffset );
+        }
+        else if ( NEG_INT32( dy ) > MUL_INT32( -2, dx ) )
+        {
+          /* -y */
+          *x = NEG_INT32( glyphpath->xOffset );
+          *y = glyphpath->yOffset;
+        }
+        else
+        {
+          /* -x -y */
+          *x = FT_MulFix( cf2_doubleToFixed( -0.7 ),
+                          glyphpath->xOffset );
+          *y = FT_MulFix( cf2_doubleToFixed( 1.0 + 0.7 ),
+                          glyphpath->yOffset );
+        }
+      }
+    }
+  }
+
+
+  /*
+   * The functions cf2_glyphpath_{moveTo,lineTo,curveTo,closeOpenPath} are
+   * called by the interpreter with Character Space (CS) coordinates.  Each
+   * path element is placed into a queue of length one to await the
+   * calculation of the following element.  At that time, the darkening
+   * offset of the following element is known and joins can be computed,
+   * including possible modification of this element, before mapping to
+   * Device Space (DS) and passing it on to the outline consumer.
+   *
+   */
+  FT_LOCAL_DEF( void )
+  cf2_glyphpath_moveTo( CF2_GlyphPath  glyphpath,
+                        CF2_Fixed      x,
+                        CF2_Fixed      y )
+  {
+    cf2_glyphpath_closeOpenPath( glyphpath );
+
+    /* save the parameters of the move for later, when we'll know how to */
+    /* offset it;                                                        */
+    /* also save last move point */
+    glyphpath->currentCS.x = glyphpath->start.x = x;
+    glyphpath->currentCS.y = glyphpath->start.y = y;
+
+    glyphpath->moveIsPending = TRUE;
+
+    /* ensure we have a valid map with current mask */
+    if ( !cf2_hintmap_isValid( &glyphpath->hintMap ) ||
+         cf2_hintmask_isNew( glyphpath->hintMask )   )
+      cf2_hintmap_build( &glyphpath->hintMap,
+                         glyphpath->hStemHintArray,
+                         glyphpath->vStemHintArray,
+                         glyphpath->hintMask,
+                         glyphpath->hintOriginY,
+                         FALSE );
+
+    /* save a copy of current HintMap to use when drawing initial point */
+    glyphpath->firstHintMap = glyphpath->hintMap;     /* structure copy */
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_glyphpath_lineTo( CF2_GlyphPath  glyphpath,
+                        CF2_Fixed      x,
+                        CF2_Fixed      y )
+  {
+    CF2_Fixed  xOffset, yOffset;
+    FT_Vector  P0, P1;
+    FT_Bool    newHintMap;
+
+    /*
+     * New hints will be applied after cf2_glyphpath_pushPrevElem has run.
+     * In case this is a synthesized closing line, any new hints should be
+     * delayed until this path is closed (`cf2_hintmask_isNew' will be
+     * called again before the next line or curve).
+     */
+
+    /* true if new hint map not on close */
+    newHintMap = cf2_hintmask_isNew( glyphpath->hintMask ) &&
+                 !glyphpath->pathIsClosing;
+
+    /*
+     * Zero-length lines may occur in the charstring.  Because we cannot
+     * compute darkening offsets or intersections from zero-length lines,
+     * it is best to remove them and avoid artifacts.  However, zero-length
+     * lines in CS at the start of a new hint map can generate non-zero
+     * lines in DS due to hint substitution.  We detect a change in hint
+     * map here and pass those zero-length lines along.
+     */
+
+    /*
+     * Note: Find explicitly closed paths here with a conditional
+     *       breakpoint using
+     *
+     *         !gp->pathIsClosing && gp->start.x == x && gp->start.y == y
+     *
+     */
+
+    if ( glyphpath->currentCS.x == x &&
+         glyphpath->currentCS.y == y &&
+         !newHintMap                 )
+      /*
+       * Ignore zero-length lines in CS where the hint map is the same
+       * because the line in DS will also be zero length.
+       *
+       * Ignore zero-length lines when we synthesize a closing line because
+       * the close will be handled in cf2_glyphPath_pushPrevElem.
+       */
+      return;
+
+    cf2_glyphpath_computeOffset( glyphpath,
+                                 glyphpath->currentCS.x,
+                                 glyphpath->currentCS.y,
+                                 x,
+                                 y,
+                                 &xOffset,
+                                 &yOffset );
+
+    /* construct offset points */
+    P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset );
+    P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset );
+    P1.x = ADD_INT32( x, xOffset );
+    P1.y = ADD_INT32( y, yOffset );
+
+    if ( glyphpath->moveIsPending )
+    {
+      /* emit offset 1st point as MoveTo */
+      cf2_glyphpath_pushMove( glyphpath, P0 );
+
+      glyphpath->moveIsPending = FALSE;  /* adjust state machine */
+      glyphpath->pathIsOpen    = TRUE;
+
+      glyphpath->offsetStart1 = P1;              /* record second point */
+    }
+
+    if ( glyphpath->elemIsQueued )
+    {
+      FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
+                 glyphpath->hintMap.count == 0              );
+
+      cf2_glyphpath_pushPrevElem( glyphpath,
+                                  &glyphpath->hintMap,
+                                  &P0,
+                                  P1,
+                                  FALSE );
+    }
+
+    /* queue the current element with offset points */
+    glyphpath->elemIsQueued = TRUE;
+    glyphpath->prevElemOp   = CF2_PathOpLineTo;
+    glyphpath->prevElemP0   = P0;
+    glyphpath->prevElemP1   = P1;
+
+    /* update current map */
+    if ( newHintMap )
+      cf2_hintmap_build( &glyphpath->hintMap,
+                         glyphpath->hStemHintArray,
+                         glyphpath->vStemHintArray,
+                         glyphpath->hintMask,
+                         glyphpath->hintOriginY,
+                         FALSE );
+
+    glyphpath->currentCS.x = x;     /* pre-offset current point */
+    glyphpath->currentCS.y = y;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_glyphpath_curveTo( CF2_GlyphPath  glyphpath,
+                         CF2_Fixed      x1,
+                         CF2_Fixed      y1,
+                         CF2_Fixed      x2,
+                         CF2_Fixed      y2,
+                         CF2_Fixed      x3,
+                         CF2_Fixed      y3 )
+  {
+    CF2_Fixed  xOffset1, yOffset1, xOffset3, yOffset3;
+    FT_Vector  P0, P1, P2, P3;
+
+
+    /* TODO: ignore zero length portions of curve?? */
+    cf2_glyphpath_computeOffset( glyphpath,
+                                 glyphpath->currentCS.x,
+                                 glyphpath->currentCS.y,
+                                 x1,
+                                 y1,
+                                 &xOffset1,
+                                 &yOffset1 );
+    cf2_glyphpath_computeOffset( glyphpath,
+                                 x2,
+                                 y2,
+                                 x3,
+                                 y3,
+                                 &xOffset3,
+                                 &yOffset3 );
+
+    /* add momentum from the middle segment */
+    glyphpath->callbacks->windingMomentum =
+      ADD_INT32( glyphpath->callbacks->windingMomentum,
+                 cf2_getWindingMomentum( x1, y1, x2, y2 ) );
+
+    /* construct offset points */
+    P0.x = ADD_INT32( glyphpath->currentCS.x, xOffset1 );
+    P0.y = ADD_INT32( glyphpath->currentCS.y, yOffset1 );
+    P1.x = ADD_INT32( x1, xOffset1 );
+    P1.y = ADD_INT32( y1, yOffset1 );
+    /* note: preserve angle of final segment by using offset3 at both ends */
+    P2.x = ADD_INT32( x2, xOffset3 );
+    P2.y = ADD_INT32( y2, yOffset3 );
+    P3.x = ADD_INT32( x3, xOffset3 );
+    P3.y = ADD_INT32( y3, yOffset3 );
+
+    if ( glyphpath->moveIsPending )
+    {
+      /* emit offset 1st point as MoveTo */
+      cf2_glyphpath_pushMove( glyphpath, P0 );
+
+      glyphpath->moveIsPending = FALSE;
+      glyphpath->pathIsOpen    = TRUE;
+
+      glyphpath->offsetStart1 = P1;              /* record second point */
+    }
+
+    if ( glyphpath->elemIsQueued )
+    {
+      FT_ASSERT( cf2_hintmap_isValid( &glyphpath->hintMap ) ||
+                 glyphpath->hintMap.count == 0              );
+
+      cf2_glyphpath_pushPrevElem( glyphpath,
+                                  &glyphpath->hintMap,
+                                  &P0,
+                                  P1,
+                                  FALSE );
+    }
+
+    /* queue the current element with offset points */
+    glyphpath->elemIsQueued = TRUE;
+    glyphpath->prevElemOp   = CF2_PathOpCubeTo;
+    glyphpath->prevElemP0   = P0;
+    glyphpath->prevElemP1   = P1;
+    glyphpath->prevElemP2   = P2;
+    glyphpath->prevElemP3   = P3;
+
+    /* update current map */
+    if ( cf2_hintmask_isNew( glyphpath->hintMask ) )
+      cf2_hintmap_build( &glyphpath->hintMap,
+                         glyphpath->hStemHintArray,
+                         glyphpath->vStemHintArray,
+                         glyphpath->hintMask,
+                         glyphpath->hintOriginY,
+                         FALSE );
+
+    glyphpath->currentCS.x = x3;       /* pre-offset current point */
+    glyphpath->currentCS.y = y3;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_glyphpath_closeOpenPath( CF2_GlyphPath  glyphpath )
+  {
+    if ( glyphpath->pathIsOpen )
+    {
+      /*
+       * A closing line in Character Space line is always generated below
+       * with `cf2_glyphPath_lineTo'.  It may be ignored later if it turns
+       * out to be zero length in Device Space.
+       */
+      glyphpath->pathIsClosing = TRUE;
+
+      cf2_glyphpath_lineTo( glyphpath,
+                            glyphpath->start.x,
+                            glyphpath->start.y );
+
+      /* empty the final element from the queue and close the path */
+      if ( glyphpath->elemIsQueued )
+        cf2_glyphpath_pushPrevElem( glyphpath,
+                                    &glyphpath->hintMap,
+                                    &glyphpath->offsetStart0,
+                                    glyphpath->offsetStart1,
+                                    TRUE );
+
+      /* reset state machine */
+      glyphpath->moveIsPending = TRUE;
+      glyphpath->pathIsOpen    = FALSE;
+      glyphpath->pathIsClosing = FALSE;
+      glyphpath->elemIsQueued  = FALSE;
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/pshints.h
@@ -1,0 +1,289 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2hints.h                                                             */
+/*                                                                         */
+/*    Adobe's code for handling CFF hints (body).                          */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2HINTS_H_
+#define CF2HINTS_H_
+
+
+FT_BEGIN_HEADER
+
+
+  enum
+  {
+    CF2_MAX_HINTS = 96    /* maximum # of hints */
+  };
+
+
+  /*
+   * A HintMask object stores a bit mask that specifies which hints in the
+   * charstring are active at a given time.  Hints in CFF must be declared
+   * at the start, before any drawing operators, with horizontal hints
+   * preceding vertical hints.  The HintMask is ordered the same way, with
+   * horizontal hints immediately followed by vertical hints.  Clients are
+   * responsible for knowing how many of each type are present.
+   *
+   * The maximum total number of hints is 96, as specified by the CFF
+   * specification.
+   *
+   * A HintMask is built 0 or more times while interpreting a charstring, by
+   * the HintMask operator.  There is only one HintMask, but it is built or
+   * rebuilt each time there is a hint substitution (HintMask operator) in
+   * the charstring.  A default HintMask with all bits set is built if there
+   * has been no HintMask operator prior to the first drawing operator.
+   *
+   */
+
+  typedef struct  CF2_HintMaskRec_
+  {
+    FT_Error*  error;
+
+    FT_Bool  isValid;
+    FT_Bool  isNew;
+
+    size_t  bitCount;
+    size_t  byteCount;
+
+    FT_Byte  mask[( CF2_MAX_HINTS + 7 ) / 8];
+
+  } CF2_HintMaskRec, *CF2_HintMask;
+
+
+  typedef struct  CF2_StemHintRec_
+  {
+    FT_Bool  used;     /* DS positions are valid         */
+
+    CF2_Fixed  min;    /* original character space value */
+    CF2_Fixed  max;
+
+    CF2_Fixed  minDS;  /* DS position after first use    */
+    CF2_Fixed  maxDS;
+
+  } CF2_StemHintRec, *CF2_StemHint;
+
+
+  /*
+   * A HintMap object stores a piecewise linear function for mapping
+   * y-coordinates from character space to device space, providing
+   * appropriate pixel alignment to stem edges.
+   *
+   * The map is implemented as an array of `CF2_Hint' elements, each
+   * representing an edge.  When edges are paired, as from stem hints, the
+   * bottom edge must immediately precede the top edge in the array.
+   * Element character space AND device space positions must both increase
+   * monotonically in the array.  `CF2_Hint' elements are also used as
+   * parameters to `cf2_blues_capture'.
+   *
+   * The `cf2_hintmap_build' method must be called before any drawing
+   * operation (beginning with a Move operator) and at each hint
+   * substitution (HintMask operator).
+   *
+   * The `cf2_hintmap_map' method is called to transform y-coordinates at
+   * each drawing operation (move, line, curve).
+   *
+   */
+
+  /* TODO: make this a CF2_ArrStack and add a deep copy method */
+  enum
+  {
+    CF2_MAX_HINT_EDGES = CF2_MAX_HINTS * 2
+  };
+
+
+  typedef struct  CF2_HintMapRec_
+  {
+    CF2_Font  font;
+
+    /* initial map based on blue zones */
+    struct CF2_HintMapRec_*  initialHintMap;
+
+    /* working storage for 2nd pass adjustHints */
+    CF2_ArrStack  hintMoves;
+
+    FT_Bool  isValid;
+    FT_Bool  hinted;
+
+    CF2_Fixed  scale;
+    CF2_UInt   count;
+
+    /* start search from this index */
+    CF2_UInt  lastIndex;
+
+    CF2_HintRec  edge[CF2_MAX_HINT_EDGES]; /* 192 */
+
+  } CF2_HintMapRec, *CF2_HintMap;
+
+
+  FT_LOCAL( FT_Bool )
+  cf2_hint_isValid( const CF2_Hint  hint );
+  FT_LOCAL( FT_Bool )
+  cf2_hint_isTop( const CF2_Hint  hint );
+  FT_LOCAL( FT_Bool )
+  cf2_hint_isBottom( const CF2_Hint  hint );
+  FT_LOCAL( void )
+  cf2_hint_lock( CF2_Hint  hint );
+
+
+  FT_LOCAL( void )
+  cf2_hintmap_init( CF2_HintMap   hintmap,
+                    CF2_Font      font,
+                    CF2_HintMap   initialMap,
+                    CF2_ArrStack  hintMoves,
+                    CF2_Fixed     scale );
+  FT_LOCAL( void )
+  cf2_hintmap_build( CF2_HintMap   hintmap,
+                     CF2_ArrStack  hStemHintArray,
+                     CF2_ArrStack  vStemHintArray,
+                     CF2_HintMask  hintMask,
+                     CF2_Fixed     hintOrigin,
+                     FT_Bool       initialMap );
+
+
+  /*
+   * GlyphPath is a wrapper for drawing operations that scales the
+   * coordinates according to the render matrix and HintMap.  It also tracks
+   * open paths to control ClosePath and to insert MoveTo for broken fonts.
+   *
+   */
+  typedef struct  CF2_GlyphPathRec_
+  {
+    /* TODO: gather some of these into a hinting context */
+
+    CF2_Font              font;           /* font instance    */
+    CF2_OutlineCallbacks  callbacks;      /* outline consumer */
+
+
+    CF2_HintMapRec  hintMap;        /* current hint map            */
+    CF2_HintMapRec  firstHintMap;   /* saved copy                  */
+    CF2_HintMapRec  initialHintMap; /* based on all captured hints */
+
+    CF2_ArrStackRec  hintMoves;  /* list of hint moves for 2nd pass */
+
+    CF2_Fixed  scaleX;         /* matrix a */
+    CF2_Fixed  scaleC;         /* matrix c */
+    CF2_Fixed  scaleY;         /* matrix d */
+
+    FT_Vector  fractionalTranslation;  /* including deviceXScale */
+#if 0
+    CF2_Fixed  hShift;    /* character space horizontal shift */
+                          /* (for fauxing)                    */
+#endif
+
+    FT_Bool  pathIsOpen;     /* true after MoveTo                     */
+    FT_Bool  pathIsClosing;  /* true when synthesizing closepath line */
+    FT_Bool  darken;         /* true if stem darkening                */
+    FT_Bool  moveIsPending;  /* true between MoveTo and offset MoveTo */
+
+    /* references used to call `cf2_hintmap_build', if necessary */
+    CF2_ArrStack         hStemHintArray;
+    CF2_ArrStack         vStemHintArray;
+    CF2_HintMask         hintMask;     /* ptr to the current mask */
+    CF2_Fixed            hintOriginY;  /* copy of current origin  */
+    const CF2_BluesRec*  blues;
+
+    CF2_Fixed  xOffset;        /* character space offsets */
+    CF2_Fixed  yOffset;
+
+    /* character space miter limit threshold */
+    CF2_Fixed  miterLimit;
+    /* vertical/horizontal snap distance in character space */
+    CF2_Fixed  snapThreshold;
+
+    FT_Vector  offsetStart0;  /* first and second points of first */
+    FT_Vector  offsetStart1;  /* element with offset applied      */
+
+    /* current point, character space, before offset */
+    FT_Vector  currentCS;
+    /* current point, device space */
+    FT_Vector  currentDS;
+    /* start point of subpath, character space */
+    FT_Vector  start;
+
+    /* the following members constitute the `queue' of one element */
+    FT_Bool  elemIsQueued;
+    CF2_Int  prevElemOp;
+
+    FT_Vector  prevElemP0;
+    FT_Vector  prevElemP1;
+    FT_Vector  prevElemP2;
+    FT_Vector  prevElemP3;
+
+  } CF2_GlyphPathRec, *CF2_GlyphPath;
+
+
+  FT_LOCAL( void )
+  cf2_glyphpath_init( CF2_GlyphPath         glyphpath,
+                      CF2_Font              font,
+                      CF2_OutlineCallbacks  callbacks,
+                      CF2_Fixed             scaleY,
+                      /* CF2_Fixed hShift, */
+                      CF2_ArrStack          hStemHintArray,
+                      CF2_ArrStack          vStemHintArray,
+                      CF2_HintMask          hintMask,
+                      CF2_Fixed             hintOrigin,
+                      const CF2_Blues       blues,
+                      const FT_Vector*      fractionalTranslation );
+  FT_LOCAL( void )
+  cf2_glyphpath_finalize( CF2_GlyphPath  glyphpath );
+
+  FT_LOCAL( void )
+  cf2_glyphpath_moveTo( CF2_GlyphPath  glyphpath,
+                        CF2_Fixed      x,
+                        CF2_Fixed      y );
+  FT_LOCAL( void )
+  cf2_glyphpath_lineTo( CF2_GlyphPath  glyphpath,
+                        CF2_Fixed      x,
+                        CF2_Fixed      y );
+  FT_LOCAL( void )
+  cf2_glyphpath_curveTo( CF2_GlyphPath  glyphpath,
+                         CF2_Fixed      x1,
+                         CF2_Fixed      y1,
+                         CF2_Fixed      x2,
+                         CF2_Fixed      y2,
+                         CF2_Fixed      x3,
+                         CF2_Fixed      y3 );
+  FT_LOCAL( void )
+  cf2_glyphpath_closeOpenPath( CF2_GlyphPath  glyphpath );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2HINTS_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psintrp.c
@@ -1,0 +1,1959 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2intrp.c                                                             */
+/*                                                                         */
+/*    Adobe's CFF Interpreter (body).                                      */
+/*                                                                         */
+/*  Copyright 2007-2014 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_SERVICE_CFF_TABLE_LOAD_H
+
+#include "psglue.h"
+#include "psfont.h"
+#include "psstack.h"
+#include "pshints.h"
+#include "psintrp.h"
+
+#include "pserror.h"
+#include "psobjs.h"  /* for cff_random */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* 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_cf2interp
+
+
+  FT_LOCAL_DEF( void )
+  cf2_hintmask_init( CF2_HintMask  hintmask,
+                     FT_Error*     error )
+  {
+    FT_ZERO( hintmask );
+
+    hintmask->error = error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  cf2_hintmask_isValid( const CF2_HintMask  hintmask )
+  {
+    return hintmask->isValid;
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  cf2_hintmask_isNew( const CF2_HintMask  hintmask )
+  {
+    return hintmask->isNew;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_hintmask_setNew( CF2_HintMask  hintmask,
+                       FT_Bool       val )
+  {
+    hintmask->isNew = val;
+  }
+
+
+  /* clients call `getMaskPtr' in order to iterate */
+  /* through hint mask                             */
+
+  FT_LOCAL_DEF( FT_Byte* )
+  cf2_hintmask_getMaskPtr( CF2_HintMask  hintmask )
+  {
+    return hintmask->mask;
+  }
+
+
+  static size_t
+  cf2_hintmask_setCounts( CF2_HintMask  hintmask,
+                          size_t        bitCount )
+  {
+    if ( bitCount > CF2_MAX_HINTS )
+    {
+      /* total of h and v stems must be <= 96 */
+      CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format );
+      return 0;
+    }
+
+    hintmask->bitCount  = bitCount;
+    hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8;
+
+    hintmask->isValid = TRUE;
+    hintmask->isNew   = TRUE;
+
+    return bitCount;
+  }
+
+
+  /* consume the hintmask bytes from the charstring, advancing the src */
+  /* pointer                                                           */
+  static void
+  cf2_hintmask_read( CF2_HintMask  hintmask,
+                     CF2_Buffer    charstring,
+                     size_t        bitCount )
+  {
+    size_t  i;
+
+#ifndef CF2_NDEBUG
+    /* these are the bits in the final mask byte that should be zero  */
+    /* Note: this variable is only used in an assert expression below */
+    /* and then only if CF2_NDEBUG is not defined                     */
+    CF2_UInt  mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
+#endif
+
+
+    /* initialize counts and isValid */
+    if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
+      return;
+
+    FT_ASSERT( hintmask->byteCount > 0 );
+
+    FT_TRACE4(( " (maskbytes:" ));
+
+    /* set mask and advance interpreter's charstring pointer */
+    for ( i = 0; i < hintmask->byteCount; i++ )
+    {
+      hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring );
+      FT_TRACE4(( " 0x%02X", hintmask->mask[i] ));
+    }
+
+    FT_TRACE4(( ")\n" ));
+
+    /* assert any unused bits in last byte are zero unless there's a prior */
+    /* error                                                               */
+    /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1      */
+#ifndef CF2_NDEBUG
+    FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 ||
+               *hintmask->error                                        );
+#endif
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_hintmask_setAll( CF2_HintMask  hintmask,
+                       size_t        bitCount )
+  {
+    size_t    i;
+    CF2_UInt  mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
+
+
+    /* initialize counts and isValid */
+    if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
+      return;
+
+    FT_ASSERT( hintmask->byteCount > 0 );
+    FT_ASSERT( hintmask->byteCount <=
+                 sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) );
+
+    /* set mask to all ones */
+    for ( i = 0; i < hintmask->byteCount; i++ )
+      hintmask->mask[i] = 0xFF;
+
+    /* clear unused bits                                              */
+    /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */
+    hintmask->mask[hintmask->byteCount - 1] &= ~mask;
+  }
+
+
+  /* Type2 charstring opcodes */
+  enum
+  {
+    cf2_cmdRESERVED_0,   /* 0 */
+    cf2_cmdHSTEM,        /* 1 */
+    cf2_cmdRESERVED_2,   /* 2 */
+    cf2_cmdVSTEM,        /* 3 */
+    cf2_cmdVMOVETO,      /* 4 */
+    cf2_cmdRLINETO,      /* 5 */
+    cf2_cmdHLINETO,      /* 6 */
+    cf2_cmdVLINETO,      /* 7 */
+    cf2_cmdRRCURVETO,    /* 8 */
+    cf2_cmdRESERVED_9,   /* 9 */
+    cf2_cmdCALLSUBR,     /* 10 */
+    cf2_cmdRETURN,       /* 11 */
+    cf2_cmdESC,          /* 12 */
+    cf2_cmdRESERVED_13,  /* 13 */
+    cf2_cmdENDCHAR,      /* 14 */
+    cf2_cmdVSINDEX,      /* 15 */
+    cf2_cmdBLEND,        /* 16 */
+    cf2_cmdRESERVED_17,  /* 17 */
+    cf2_cmdHSTEMHM,      /* 18 */
+    cf2_cmdHINTMASK,     /* 19 */
+    cf2_cmdCNTRMASK,     /* 20 */
+    cf2_cmdRMOVETO,      /* 21 */
+    cf2_cmdHMOVETO,      /* 22 */
+    cf2_cmdVSTEMHM,      /* 23 */
+    cf2_cmdRCURVELINE,   /* 24 */
+    cf2_cmdRLINECURVE,   /* 25 */
+    cf2_cmdVVCURVETO,    /* 26 */
+    cf2_cmdHHCURVETO,    /* 27 */
+    cf2_cmdEXTENDEDNMBR, /* 28 */
+    cf2_cmdCALLGSUBR,    /* 29 */
+    cf2_cmdVHCURVETO,    /* 30 */
+    cf2_cmdHVCURVETO     /* 31 */
+  };
+
+  enum
+  {
+    cf2_escDOTSECTION,   /* 0 */
+    cf2_escRESERVED_1,   /* 1 */
+    cf2_escRESERVED_2,   /* 2 */
+    cf2_escAND,          /* 3 */
+    cf2_escOR,           /* 4 */
+    cf2_escNOT,          /* 5 */
+    cf2_escRESERVED_6,   /* 6 */
+    cf2_escRESERVED_7,   /* 7 */
+    cf2_escRESERVED_8,   /* 8 */
+    cf2_escABS,          /* 9 */
+    cf2_escADD,          /* 10     like otherADD */
+    cf2_escSUB,          /* 11     like otherSUB */
+    cf2_escDIV,          /* 12 */
+    cf2_escRESERVED_13,  /* 13 */
+    cf2_escNEG,          /* 14 */
+    cf2_escEQ,           /* 15 */
+    cf2_escRESERVED_16,  /* 16 */
+    cf2_escRESERVED_17,  /* 17 */
+    cf2_escDROP,         /* 18 */
+    cf2_escRESERVED_19,  /* 19 */
+    cf2_escPUT,          /* 20     like otherPUT    */
+    cf2_escGET,          /* 21     like otherGET    */
+    cf2_escIFELSE,       /* 22     like otherIFELSE */
+    cf2_escRANDOM,       /* 23     like otherRANDOM */
+    cf2_escMUL,          /* 24     like otherMUL    */
+    cf2_escRESERVED_25,  /* 25 */
+    cf2_escSQRT,         /* 26 */
+    cf2_escDUP,          /* 27     like otherDUP    */
+    cf2_escEXCH,         /* 28     like otherEXCH   */
+    cf2_escINDEX,        /* 29 */
+    cf2_escROLL,         /* 30 */
+    cf2_escRESERVED_31,  /* 31 */
+    cf2_escRESERVED_32,  /* 32 */
+    cf2_escRESERVED_33,  /* 33 */
+    cf2_escHFLEX,        /* 34 */
+    cf2_escFLEX,         /* 35 */
+    cf2_escHFLEX1,       /* 36 */
+    cf2_escFLEX1,        /* 37 */
+    cf2_escRESERVED_38   /* 38     & all higher     */
+  };
+
+
+  /* `stemHintArray' does not change once we start drawing the outline. */
+  static void
+  cf2_doStems( const CF2_Font  font,
+               CF2_Stack       opStack,
+               CF2_ArrStack    stemHintArray,
+               CF2_Fixed*      width,
+               FT_Bool*        haveWidth,
+               CF2_Fixed       hintOffset )
+  {
+    CF2_UInt  i;
+    CF2_UInt  count       = cf2_stack_count( opStack );
+    FT_Bool   hasWidthArg = (FT_Bool)( count & 1 );
+
+    /* variable accumulates delta values from operand stack */
+    CF2_Fixed  position = hintOffset;
+
+
+    if ( hasWidthArg && !*haveWidth )
+      *width = cf2_stack_getReal( opStack, 0 ) +
+                 cf2_getNominalWidthX( font->decoder );
+
+    if ( font->decoder->width_only )
+      goto exit;
+
+    for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 )
+    {
+      /* construct a CF2_StemHint and push it onto the list */
+      CF2_StemHintRec  stemhint;
+
+
+      stemhint.min =
+      position     = ADD_INT32( position,
+                                cf2_stack_getReal( opStack, i ) );
+      stemhint.max =
+      position     = ADD_INT32( position,
+                                cf2_stack_getReal( opStack, i + 1 ) );
+
+      stemhint.used  = FALSE;
+      stemhint.maxDS =
+      stemhint.minDS = 0;
+
+      cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */
+    }
+
+    cf2_stack_clear( opStack );
+
+  exit:
+    /* cf2_doStems must define a width (may be default) */
+    *haveWidth = TRUE;
+  }
+
+
+  static void
+  cf2_doFlex( CF2_Stack       opStack,
+              CF2_Fixed*      curX,
+              CF2_Fixed*      curY,
+              CF2_GlyphPath   glyphPath,
+              const FT_Bool*  readFromStack,
+              FT_Bool         doConditionalLastRead )
+  {
+    CF2_Fixed  vals[14];
+    CF2_UInt   idx;
+    FT_Bool    isHFlex;
+    CF2_Int    top, i, j;
+
+
+    vals[0] = *curX;
+    vals[1] = *curY;
+    idx     = 0;
+    isHFlex = FT_BOOL( readFromStack[9] == FALSE );
+    top     = isHFlex ? 9 : 10;
+
+    for ( i = 0; i < top; i++ )
+    {
+      vals[i + 2] = vals[i];
+      if ( readFromStack[i] )
+        vals[i + 2] = ADD_INT32( vals[i + 2], cf2_stack_getReal( opStack,
+                                                                 idx++ ) );
+    }
+
+    if ( isHFlex )
+      vals[9 + 2] = *curY;
+
+    if ( doConditionalLastRead )
+    {
+      FT_Bool    lastIsX = (FT_Bool)(
+                             cf2_fixedAbs( SUB_INT32( vals[10], *curX ) ) >
+                             cf2_fixedAbs( SUB_INT32( vals[11], *curY ) ) );
+      CF2_Fixed  lastVal = cf2_stack_getReal( opStack, idx );
+
+
+      if ( lastIsX )
+      {
+        vals[12] = ADD_INT32( vals[10], lastVal );
+        vals[13] = *curY;
+      }
+      else
+      {
+        vals[12] = *curX;
+        vals[13] = ADD_INT32( vals[11], lastVal );
+      }
+    }
+    else
+    {
+      if ( readFromStack[10] )
+        vals[12] = ADD_INT32( vals[10],
+                              cf2_stack_getReal( opStack, idx++ ) );
+      else
+        vals[12] = *curX;
+
+      if ( readFromStack[11] )
+        vals[13] = ADD_INT32( vals[11],
+                              cf2_stack_getReal( opStack, idx ) );
+      else
+        vals[13] = *curY;
+    }
+
+    for ( j = 0; j < 2; j++ )
+      cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2],
+                                        vals[j * 6 + 3],
+                                        vals[j * 6 + 4],
+                                        vals[j * 6 + 5],
+                                        vals[j * 6 + 6],
+                                        vals[j * 6 + 7] );
+
+    cf2_stack_clear( opStack );
+
+    *curX = vals[12];
+    *curY = vals[13];
+  }
+
+
+  /* Blend numOperands on the stack,                */
+  /* store results into the first numBlends values, */
+  /* then pop remaining arguments.                  */
+  static void
+  cf2_doBlend( const CFF_Blend  blend,
+               CF2_Stack        opStack,
+               CF2_UInt         numBlends )
+  {
+    CF2_UInt  delta;
+    CF2_UInt  base;
+    CF2_UInt  i, j;
+    CF2_UInt  numOperands = (CF2_UInt)( numBlends * blend->lenBV );
+
+
+    base  = cf2_stack_count( opStack ) - numOperands;
+    delta = base + numBlends;
+
+    for ( i = 0; i < numBlends; i++ )
+    {
+      const CF2_Fixed*  weight = &blend->BV[1];
+
+      /* start with first term */
+      CF2_Fixed  sum = cf2_stack_getReal( opStack, i + base );
+
+
+      for ( j = 1; j < blend->lenBV; j++ )
+        sum = ADD_INT32( sum,
+                         FT_MulFix( *weight++,
+                                    cf2_stack_getReal( opStack,
+                                                       delta++ ) ) );
+
+      /* store blended result  */
+      cf2_stack_setReal( opStack, i + base, sum );
+    }
+
+    /* leave only `numBlends' results on stack */
+    cf2_stack_pop( opStack, numOperands - numBlends );
+  }
+
+
+  /*
+   * `error' is a shared error code used by many objects in this
+   * routine.  Before the code continues from an error, it must check and
+   * record the error in `*error'.  The idea is that this shared
+   * error code will record the first error encountered.  If testing
+   * for an error anyway, the cost of `goto exit' is small, so we do it,
+   * even if continuing would be safe.  In this case, `lastError' is
+   * set, so the testing and storing can be done in one place, at `exit'.
+   *
+   * Continuing after an error is intended for objects which do their own
+   * testing of `*error', e.g., array stack functions.  This allows us to
+   * avoid an extra test after the call.
+   *
+   * Unimplemented opcodes are ignored.
+   *
+   */
+  FT_LOCAL_DEF( void )
+  cf2_interpT2CharString( CF2_Font              font,
+                          CF2_Buffer            buf,
+                          CF2_OutlineCallbacks  callbacks,
+                          const FT_Vector*      translation,
+                          FT_Bool               doingSeac,
+                          CF2_Fixed             curX,
+                          CF2_Fixed             curY,
+                          CF2_Fixed*            width )
+  {
+    /* lastError is used for errors that are immediately tested */
+    FT_Error  lastError = FT_Err_Ok;
+
+    /* pointer to parsed font object */
+    CFF_Decoder*  decoder = font->decoder;
+
+    FT_Error*  error  = &font->error;
+    FT_Memory  memory = font->memory;
+
+    CF2_Fixed  scaleY        = font->innerTransform.d;
+    CF2_Fixed  nominalWidthX = cf2_getNominalWidthX( decoder );
+
+    /* save this for hinting seac accents */
+    CF2_Fixed  hintOriginY = curY;
+
+    CF2_Stack  opStack = NULL;
+    FT_UInt    stackSize;
+    FT_Byte    op1;                       /* first opcode byte */
+
+    CF2_F16Dot16  storage[CF2_STORAGE_SIZE];    /* for `put' and `get' */
+
+    /* instruction limit; 20,000,000 matches Avalon */
+    FT_UInt32  instructionLimit = 20000000UL;
+
+    CF2_ArrStackRec  subrStack;
+
+    FT_Bool     haveWidth;
+    CF2_Buffer  charstring = NULL;
+
+    CF2_Int  charstringIndex = -1;       /* initialize to empty */
+
+    /* TODO: placeholders for hint structures */
+
+    /* objects used for hinting */
+    CF2_ArrStackRec  hStemHintArray;
+    CF2_ArrStackRec  vStemHintArray;
+
+    CF2_HintMaskRec   hintMask;
+    CF2_GlyphPathRec  glyphPath;
+
+
+    FT_ZERO( &storage );
+
+    /* initialize the remaining objects */
+    cf2_arrstack_init( &subrStack,
+                       memory,
+                       error,
+                       sizeof ( CF2_BufferRec ) );
+    cf2_arrstack_init( &hStemHintArray,
+                       memory,
+                       error,
+                       sizeof ( CF2_StemHintRec ) );
+    cf2_arrstack_init( &vStemHintArray,
+                       memory,
+                       error,
+                       sizeof ( CF2_StemHintRec ) );
+
+    /* initialize CF2_StemHint arrays */
+    cf2_hintmask_init( &hintMask, error );
+
+    /* initialize path map to manage drawing operations */
+
+    /* Note: last 4 params are used to handle `MoveToPermissive', which */
+    /*       may need to call `hintMap.Build'                           */
+    /* TODO: MoveToPermissive is gone; are these still needed?          */
+    cf2_glyphpath_init( &glyphPath,
+                        font,
+                        callbacks,
+                        scaleY,
+                        /* hShift, */
+                        &hStemHintArray,
+                        &vStemHintArray,
+                        &hintMask,
+                        hintOriginY,
+                        &font->blues,
+                        translation );
+
+    /*
+     * Initialize state for width parsing.  From the CFF Spec:
+     *
+     *   The first stack-clearing operator, which must be one of hstem,
+     *   hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
+     *   rmoveto, or endchar, takes an additional argument - the width (as
+     *   described earlier), which may be expressed as zero or one numeric
+     *   argument.
+     *
+     * What we implement here uses the first validly specified width, but
+     * does not detect errors for specifying more than one width.
+     *
+     * If one of the above operators occurs without explicitly specifying
+     * a width, we assume the default width.
+     *
+     * CFF2 charstrings always return the default width (0).
+     *
+     */
+    haveWidth = font->isCFF2 ? TRUE : FALSE;
+    *width    = cf2_getDefaultWidthX( decoder );
+
+    /*
+     * Note: At this point, all pointers to resources must be NULL
+     *       and all local objects must be initialized.
+     *       There must be no branches to `exit:' above this point.
+     *
+     */
+
+    /* allocate an operand stack */
+    stackSize = font->isCFF2 ? cf2_getMaxstack( decoder )
+                             : CF2_OPERAND_STACK_SIZE;
+    opStack   = cf2_stack_init( memory, error, stackSize );
+
+    if ( !opStack )
+    {
+      lastError = FT_THROW( Out_Of_Memory );
+      goto exit;
+    }
+
+    /* initialize subroutine stack by placing top level charstring as */
+    /* first element (max depth plus one for the charstring)          */
+    /* Note: Caller owns and must finalize the first charstring.      */
+    /*       Our copy of it does not change that requirement.         */
+    cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
+
+    charstring  = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
+    *charstring = *buf;    /* structure copy */
+
+    charstringIndex = 0;       /* entry is valid now */
+
+    /* catch errors so far */
+    if ( *error )
+      goto exit;
+
+    /* main interpreter loop */
+    while ( 1 )
+    {
+      if ( cf2_buf_isEnd( charstring ) )
+      {
+        /* If we've reached the end of the charstring, simulate a */
+        /* cf2_cmdRETURN or cf2_cmdENDCHAR.                       */
+        /* We do this for both CFF and CFF2.                      */
+        if ( charstringIndex )
+          op1 = cf2_cmdRETURN;  /* end of buffer for subroutine */
+        else
+          op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
+      }
+      else
+      {
+        op1 = (FT_Byte)cf2_buf_readByte( charstring );
+
+        /* Explicit RETURN and ENDCHAR in CFF2 should be ignored. */
+        /* Note: Trace message will report 0 instead of 11 or 14. */
+        if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) &&
+             font->isCFF2                                      )
+          op1 = cf2_cmdRESERVED_0;
+      }
+
+      /* check for errors once per loop */
+      if ( *error )
+        goto exit;
+
+      instructionLimit--;
+      if ( instructionLimit == 0 )
+      {
+        lastError = FT_THROW( Invalid_Glyph_Format );
+        goto exit;
+      }
+
+      switch( op1 )
+      {
+      case cf2_cmdRESERVED_0:
+      case cf2_cmdRESERVED_2:
+      case cf2_cmdRESERVED_9:
+      case cf2_cmdRESERVED_13:
+      case cf2_cmdRESERVED_17:
+        /* we may get here if we have a prior error */
+        FT_TRACE4(( " unknown op (%d)\n", op1 ));
+        break;
+
+      case cf2_cmdVSINDEX:
+        FT_TRACE4(( " vsindex\n" ));
+
+        if ( !font->isCFF2 )
+          break;    /* clear stack & ignore */
+
+        if ( font->blend.usedBV )
+        {
+          /* vsindex not allowed after blend */
+          lastError = FT_THROW( Invalid_Glyph_Format );
+          goto exit;
+        }
+
+        {
+          FT_Int  temp = cf2_stack_popInt( opStack );
+
+
+          if ( temp >= 0 )
+            font->vsindex = (FT_UInt)temp;
+        }
+        break;
+
+      case cf2_cmdBLEND:
+        {
+          FT_UInt  numBlends;
+
+
+          FT_TRACE4(( " blend\n" ));
+
+          if ( !font->isCFF2 )
+            break;    /* clear stack & ignore */
+
+          /* do we have a `blend' op in a non-variant font? */
+          if ( !font->blend.font )
+          {
+            lastError = FT_THROW( Invalid_Glyph_Format );
+            goto exit;
+          }
+
+          /* check cached blend vector */
+          if ( font->cffload->blend_check_vector( &font->blend,
+                                                  font->vsindex,
+                                                  font->lenNDV,
+                                                  font->NDV ) )
+          {
+            lastError = font->cffload->blend_build_vector( &font->blend,
+                                                           font->vsindex,
+                                                           font->lenNDV,
+                                                           font->NDV );
+            if ( lastError )
+              goto exit;
+          }
+
+          /* do the blend */
+          numBlends = (FT_UInt)cf2_stack_popInt( opStack );
+          if ( numBlends > stackSize )
+          {
+            lastError = FT_THROW( Invalid_Glyph_Format );
+            goto exit;
+          }
+
+          cf2_doBlend( &font->blend, opStack, numBlends );
+
+          font->blend.usedBV = TRUE;
+        }
+        continue;     /* do not clear the stack */
+
+      case cf2_cmdHSTEMHM:
+      case cf2_cmdHSTEM:
+        FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
+
+        /* never add hints after the mask is computed */
+        if ( cf2_hintmask_isValid( &hintMask ) )
+        {
+          FT_TRACE4(( "cf2_interpT2CharString:"
+                      " invalid horizontal hint mask\n" ));
+          break;
+        }
+
+        cf2_doStems( font,
+                     opStack,
+                     &hStemHintArray,
+                     width,
+                     &haveWidth,
+                     0 );
+
+        if ( font->decoder->width_only )
+          goto exit;
+
+        break;
+
+      case cf2_cmdVSTEMHM:
+      case cf2_cmdVSTEM:
+        FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
+
+        /* never add hints after the mask is computed */
+        if ( cf2_hintmask_isValid( &hintMask ) )
+        {
+          FT_TRACE4(( "cf2_interpT2CharString:"
+                      " invalid vertical hint mask\n" ));
+          break;
+        }
+
+        cf2_doStems( font,
+                     opStack,
+                     &vStemHintArray,
+                     width,
+                     &haveWidth,
+                     0 );
+
+        if ( font->decoder->width_only )
+          goto exit;
+
+        break;
+
+      case cf2_cmdVMOVETO:
+        FT_TRACE4(( " vmoveto\n" ));
+
+        if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
+          *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
+                              nominalWidthX );
+
+        /* width is defined or default after this */
+        haveWidth = TRUE;
+
+        if ( font->decoder->width_only )
+          goto exit;
+
+        curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) );
+
+        cf2_glyphpath_moveTo( &glyphPath, curX, curY );
+
+        break;
+
+      case cf2_cmdRLINETO:
+        {
+          CF2_UInt  idx;
+          CF2_UInt  count = cf2_stack_count( opStack );
+
+
+          FT_TRACE4(( " rlineto\n" ));
+
+          for ( idx = 0; idx < count; idx += 2 )
+          {
+            curX = ADD_INT32( curX, cf2_stack_getReal( opStack,
+                                                       idx + 0 ) );
+            curY = ADD_INT32( curY, cf2_stack_getReal( opStack,
+                                                       idx + 1 ) );
+
+            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
+          }
+
+          cf2_stack_clear( opStack );
+        }
+        continue; /* no need to clear stack again */
+
+      case cf2_cmdHLINETO:
+      case cf2_cmdVLINETO:
+        {
+          CF2_UInt  idx;
+          CF2_UInt  count = cf2_stack_count( opStack );
+
+          FT_Bool  isX = FT_BOOL( op1 == cf2_cmdHLINETO );
+
+
+          FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
+
+          for ( idx = 0; idx < count; idx++ )
+          {
+            CF2_Fixed  v = cf2_stack_getReal( opStack, idx );
+
+
+            if ( isX )
+              curX = ADD_INT32( curX, v );
+            else
+              curY = ADD_INT32( curY, v );
+
+            isX = !isX;
+
+            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
+          }
+
+          cf2_stack_clear( opStack );
+        }
+        continue;
+
+      case cf2_cmdRCURVELINE:
+      case cf2_cmdRRCURVETO:
+        {
+          CF2_UInt  count = cf2_stack_count( opStack );
+          CF2_UInt  idx   = 0;
+
+
+          FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n"
+                                               : " rrcurveto\n" ));
+
+          while ( idx + 6 <= count )
+          {
+            CF2_Fixed  x1, y1, x2, y2, x3, y3;
+
+
+            x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
+            y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY );
+            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 );
+            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 );
+            x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 );
+            y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 );
+
+            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
+
+            curX  = x3;
+            curY  = y3;
+            idx  += 6;
+          }
+
+          if ( op1 == cf2_cmdRCURVELINE )
+          {
+            curX = ADD_INT32( curX, cf2_stack_getReal( opStack,
+                                                       idx + 0 ) );
+            curY = ADD_INT32( curY, cf2_stack_getReal( opStack,
+                                                       idx + 1 ) );
+
+            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
+          }
+
+          cf2_stack_clear( opStack );
+        }
+        continue; /* no need to clear stack again */
+
+      case cf2_cmdCALLGSUBR:
+      case cf2_cmdCALLSUBR:
+        {
+          CF2_Int  subrNum;
+
+
+          FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
+                                              : " callsubr" ));
+
+          if ( charstringIndex > CF2_MAX_SUBR )
+          {
+            /* max subr plus one for charstring */
+            lastError = FT_THROW( Invalid_Glyph_Format );
+            goto exit;                      /* overflow of stack */
+          }
+
+          /* push our current CFF charstring region on subrStack */
+          charstring = (CF2_Buffer)
+                         cf2_arrstack_getPointer(
+                           &subrStack,
+                           (size_t)charstringIndex + 1 );
+
+          /* set up the new CFF region and pointer */
+          subrNum = cf2_stack_popInt( opStack );
+
+          switch ( op1 )
+          {
+          case cf2_cmdCALLGSUBR:
+            FT_TRACE4(( " (idx %d, entering level %d)\n",
+                        subrNum + decoder->globals_bias,
+                        charstringIndex + 1 ));
+
+            if ( cf2_initGlobalRegionBuffer( decoder,
+                                             subrNum,
+                                             charstring ) )
+            {
+              lastError = FT_THROW( Invalid_Glyph_Format );
+              goto exit;  /* subroutine lookup or stream error */
+            }
+            break;
+
+          default:
+            /* cf2_cmdCALLSUBR */
+            FT_TRACE4(( " (idx %d, entering level %d)\n",
+                        subrNum + decoder->locals_bias,
+                        charstringIndex + 1 ));
+
+            if ( cf2_initLocalRegionBuffer( decoder,
+                                            subrNum,
+                                            charstring ) )
+            {
+              lastError = FT_THROW( Invalid_Glyph_Format );
+              goto exit;  /* subroutine lookup or stream error */
+            }
+          }
+
+          charstringIndex += 1;       /* entry is valid now */
+        }
+        continue; /* do not clear the stack */
+
+      case cf2_cmdRETURN:
+        FT_TRACE4(( " return (leaving level %d)\n", charstringIndex ));
+
+        if ( charstringIndex < 1 )
+        {
+          /* Note: cannot return from top charstring */
+          lastError = FT_THROW( Invalid_Glyph_Format );
+          goto exit;                      /* underflow of stack */
+        }
+
+        /* restore position in previous charstring */
+        charstring = (CF2_Buffer)
+                       cf2_arrstack_getPointer(
+                         &subrStack,
+                         (CF2_UInt)--charstringIndex );
+        continue;     /* do not clear the stack */
+
+      case cf2_cmdESC:
+        {
+          FT_Byte  op2 = (FT_Byte)cf2_buf_readByte( charstring );
+
+
+          /* first switch for 2-byte operators handles CFF2      */
+          /* and opcodes that are reserved for both CFF and CFF2 */
+          switch ( op2 )
+          {
+          case cf2_escHFLEX:
+            {
+              static const FT_Bool  readFromStack[12] =
+              {
+                TRUE /* dx1 */, FALSE /* dy1 */,
+                TRUE /* dx2 */, TRUE  /* dy2 */,
+                TRUE /* dx3 */, FALSE /* dy3 */,
+                TRUE /* dx4 */, FALSE /* dy4 */,
+                TRUE /* dx5 */, FALSE /* dy5 */,
+                TRUE /* dx6 */, FALSE /* dy6 */
+              };
+
+
+              FT_TRACE4(( " hflex\n" ));
+
+              cf2_doFlex( opStack,
+                          &curX,
+                          &curY,
+                          &glyphPath,
+                          readFromStack,
+                          FALSE /* doConditionalLastRead */ );
+            }
+            continue;
+
+          case cf2_escFLEX:
+            {
+              static const FT_Bool  readFromStack[12] =
+              {
+                TRUE /* dx1 */, TRUE /* dy1 */,
+                TRUE /* dx2 */, TRUE /* dy2 */,
+                TRUE /* dx3 */, TRUE /* dy3 */,
+                TRUE /* dx4 */, TRUE /* dy4 */,
+                TRUE /* dx5 */, TRUE /* dy5 */,
+                TRUE /* dx6 */, TRUE /* dy6 */
+              };
+
+
+              FT_TRACE4(( " flex\n" ));
+
+              cf2_doFlex( opStack,
+                          &curX,
+                          &curY,
+                          &glyphPath,
+                          readFromStack,
+                          FALSE /* doConditionalLastRead */ );
+            }
+            break;      /* TODO: why is this not a continue? */
+
+          case cf2_escHFLEX1:
+            {
+              static const FT_Bool  readFromStack[12] =
+              {
+                TRUE /* dx1 */, TRUE  /* dy1 */,
+                TRUE /* dx2 */, TRUE  /* dy2 */,
+                TRUE /* dx3 */, FALSE /* dy3 */,
+                TRUE /* dx4 */, FALSE /* dy4 */,
+                TRUE /* dx5 */, TRUE  /* dy5 */,
+                TRUE /* dx6 */, FALSE /* dy6 */
+              };
+
+
+              FT_TRACE4(( " hflex1\n" ));
+
+              cf2_doFlex( opStack,
+                          &curX,
+                          &curY,
+                          &glyphPath,
+                          readFromStack,
+                          FALSE /* doConditionalLastRead */ );
+            }
+            continue;
+
+          case cf2_escFLEX1:
+            {
+              static const FT_Bool  readFromStack[12] =
+              {
+                TRUE  /* dx1 */, TRUE  /* dy1 */,
+                TRUE  /* dx2 */, TRUE  /* dy2 */,
+                TRUE  /* dx3 */, TRUE  /* dy3 */,
+                TRUE  /* dx4 */, TRUE  /* dy4 */,
+                TRUE  /* dx5 */, TRUE  /* dy5 */,
+                FALSE /* dx6 */, FALSE /* dy6 */
+              };
+
+
+              FT_TRACE4(( " flex1\n" ));
+
+              cf2_doFlex( opStack,
+                          &curX,
+                          &curY,
+                          &glyphPath,
+                          readFromStack,
+                          TRUE /* doConditionalLastRead */ );
+            }
+            continue;
+
+          /* these opcodes are reserved in both CFF & CFF2 */
+          case cf2_escRESERVED_1:
+          case cf2_escRESERVED_2:
+          case cf2_escRESERVED_6:
+          case cf2_escRESERVED_7:
+          case cf2_escRESERVED_8:
+          case cf2_escRESERVED_13:
+          case cf2_escRESERVED_16:
+          case cf2_escRESERVED_17:
+          case cf2_escRESERVED_19:
+          case cf2_escRESERVED_25:
+          case cf2_escRESERVED_31:
+          case cf2_escRESERVED_32:
+          case cf2_escRESERVED_33:
+            FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
+            break;
+
+          default:
+            {
+              if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 )
+                FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
+              else
+              {
+                /* second switch for 2-byte operators handles just CFF */
+                switch ( op2 )
+                {
+
+                case cf2_escDOTSECTION:
+                  /* something about `flip type of locking' -- ignore it */
+                  FT_TRACE4(( " dotsection\n" ));
+
+                  break;
+
+                case cf2_escAND:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
+
+
+                    FT_TRACE4(( " and\n" ));
+
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushInt( opStack, arg1 && arg2 );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escOR:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
+
+
+                    FT_TRACE4(( " or\n" ));
+
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushInt( opStack, arg1 || arg2 );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escNOT:
+                  {
+                    CF2_F16Dot16  arg;
+
+
+                    FT_TRACE4(( " not\n" ));
+
+                    arg = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushInt( opStack, !arg );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escABS:
+                  {
+                    CF2_F16Dot16  arg;
+
+
+                    FT_TRACE4(( " abs\n" ));
+
+                    arg = cf2_stack_popFixed( opStack );
+
+                    if ( arg < -CF2_FIXED_MAX )
+                      cf2_stack_pushFixed( opStack, CF2_FIXED_MAX );
+                    else
+                      cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escADD:
+                  {
+                    CF2_F16Dot16  summand1;
+                    CF2_F16Dot16  summand2;
+
+
+                    FT_TRACE4(( " add\n" ));
+
+                    summand2 = cf2_stack_popFixed( opStack );
+                    summand1 = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushFixed( opStack,
+                                         ADD_INT32( summand1,
+                                                    summand2 ) );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escSUB:
+                  {
+                    CF2_F16Dot16  minuend;
+                    CF2_F16Dot16  subtrahend;
+
+
+                    FT_TRACE4(( " sub\n" ));
+
+                    subtrahend = cf2_stack_popFixed( opStack );
+                    minuend    = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushFixed( opStack,
+                                         SUB_INT32( minuend, subtrahend ) );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escDIV:
+                  {
+                    CF2_F16Dot16  dividend;
+                    CF2_F16Dot16  divisor;
+
+
+                    FT_TRACE4(( " div\n" ));
+
+                    divisor  = cf2_stack_popFixed( opStack );
+                    dividend = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushFixed( opStack,
+                                         FT_DivFix( dividend, divisor ) );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escNEG:
+                  {
+                    CF2_F16Dot16  arg;
+
+
+                    FT_TRACE4(( " neg\n" ));
+
+                    arg = cf2_stack_popFixed( opStack );
+
+                    if ( arg < -CF2_FIXED_MAX )
+                      cf2_stack_pushFixed( opStack, CF2_FIXED_MAX );
+                    else
+                      cf2_stack_pushFixed( opStack, -arg );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escEQ:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
+
+
+                    FT_TRACE4(( " eq\n" ));
+
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushInt( opStack, arg1 == arg2 );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escDROP:
+                  FT_TRACE4(( " drop\n" ));
+
+                  (void)cf2_stack_popFixed( opStack );
+                  continue; /* do not clear the stack */
+
+                case cf2_escPUT:
+                  {
+                    CF2_F16Dot16  val;
+                    CF2_Int       idx;
+
+
+                    FT_TRACE4(( " put\n" ));
+
+                    idx = cf2_stack_popInt( opStack );
+                    val = cf2_stack_popFixed( opStack );
+
+                    if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+                      storage[idx] = val;
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escGET:
+                  {
+                    CF2_Int  idx;
+
+
+                    FT_TRACE4(( " get\n" ));
+
+                    idx = cf2_stack_popInt( opStack );
+
+                    if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+                      cf2_stack_pushFixed( opStack, storage[idx] );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escIFELSE:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
+                    CF2_F16Dot16  cond1;
+                    CF2_F16Dot16  cond2;
+
+
+                    FT_TRACE4(( " ifelse\n" ));
+
+                    cond2 = cf2_stack_popFixed( opStack );
+                    cond1 = cf2_stack_popFixed( opStack );
+                    arg2  = cf2_stack_popFixed( opStack );
+                    arg1  = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushFixed( opStack,
+                                         cond1 <= cond2 ? arg1 : arg2 );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escRANDOM: /* in spec */
+                  {
+                    CF2_F16Dot16  r;
+
+
+                    FT_TRACE4(( " random\n" ));
+
+                    /* only use the lower 16 bits of `random'  */
+                    /* to generate a number in the range (0;1] */
+                    r = (CF2_F16Dot16)
+                          ( ( decoder->current_subfont->random & 0xFFFF ) + 1 );
+
+                    decoder->current_subfont->random =
+                      cff_random( decoder->current_subfont->random );
+
+                    cf2_stack_pushFixed( opStack, r );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escMUL:
+                  {
+                    CF2_F16Dot16  factor1;
+                    CF2_F16Dot16  factor2;
+
+
+                    FT_TRACE4(( " mul\n" ));
+
+                    factor2 = cf2_stack_popFixed( opStack );
+                    factor1 = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushFixed( opStack,
+                                         FT_MulFix( factor1, factor2 ) );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escSQRT:
+                  {
+                    CF2_F16Dot16  arg;
+
+
+                    FT_TRACE4(( " sqrt\n" ));
+
+                    arg = cf2_stack_popFixed( opStack );
+                    if ( arg > 0 )
+                    {
+                      /* use a start value that doesn't make */
+                      /* the algorithm's addition overflow   */
+                      FT_Fixed  root = arg < 10 ? arg : arg >> 1;
+                      FT_Fixed  new_root;
+
+
+                      /* Babylonian method */
+                      for (;;)
+                      {
+                        new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
+                        if ( new_root == root )
+                          break;
+                        root = new_root;
+                      }
+                      arg = new_root;
+                    }
+                    else
+                      arg = 0;
+
+                    cf2_stack_pushFixed( opStack, arg );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escDUP:
+                  {
+                    CF2_F16Dot16  arg;
+
+
+                    FT_TRACE4(( " dup\n" ));
+
+                    arg = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushFixed( opStack, arg );
+                    cf2_stack_pushFixed( opStack, arg );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escEXCH:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
+
+
+                    FT_TRACE4(( " exch\n" ));
+
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
+
+                    cf2_stack_pushFixed( opStack, arg2 );
+                    cf2_stack_pushFixed( opStack, arg1 );
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escINDEX:
+                  {
+                    CF2_Int   idx;
+                    CF2_UInt  size;
+
+
+                    FT_TRACE4(( " index\n" ));
+
+                    idx  = cf2_stack_popInt( opStack );
+                    size = cf2_stack_count( opStack );
+
+                    if ( size > 0 )
+                    {
+                      /* for `cf2_stack_getReal',   */
+                      /* index 0 is bottom of stack */
+                      CF2_UInt  gr_idx;
+
+
+                      if ( idx < 0 )
+                        gr_idx = size - 1;
+                      else if ( (CF2_UInt)idx >= size )
+                        gr_idx = 0;
+                      else
+                        gr_idx = size - 1 - (CF2_UInt)idx;
+
+                      cf2_stack_pushFixed( opStack,
+                                           cf2_stack_getReal( opStack,
+                                                              gr_idx ) );
+                    }
+                  }
+                  continue; /* do not clear the stack */
+
+                case cf2_escROLL:
+                  {
+                    CF2_Int  idx;
+                    CF2_Int  count;
+
+
+                    FT_TRACE4(( " roll\n" ));
+
+                    idx   = cf2_stack_popInt( opStack );
+                    count = cf2_stack_popInt( opStack );
+
+                    cf2_stack_roll( opStack, count, idx );
+                  }
+                  continue; /* do not clear the stack */
+
+                } /* end of 2nd switch checking op2 */
+              }
+            }
+          } /* end of 1st switch checking op2 */
+        } /* case cf2_cmdESC */
+
+        break;
+
+      case cf2_cmdENDCHAR:
+        FT_TRACE4(( " endchar\n" ));
+
+        if ( cf2_stack_count( opStack ) == 1 ||
+             cf2_stack_count( opStack ) == 5 )
+        {
+          if ( !haveWidth )
+            *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
+                                nominalWidthX );
+        }
+
+        /* width is defined or default after this */
+        haveWidth = TRUE;
+
+        if ( font->decoder->width_only )
+          goto exit;
+
+        /* close path if still open */
+        cf2_glyphpath_closeOpenPath( &glyphPath );
+
+        /* disable seac for CFF2 (charstring ending with args on stack) */
+        if ( !font->isCFF2 && cf2_stack_count( opStack ) > 1 )
+        {
+          /* must be either 4 or 5 --                       */
+          /* this is a (deprecated) implied `seac' operator */
+
+          CF2_Int        achar;
+          CF2_Int        bchar;
+          CF2_BufferRec  component;
+          CF2_Fixed      dummyWidth;   /* ignore component width */
+          FT_Error       error2;
+
+
+          if ( doingSeac )
+          {
+            lastError = FT_THROW( Invalid_Glyph_Format );
+            goto exit;      /* nested seac */
+          }
+
+          achar = cf2_stack_popInt( opStack );
+          bchar = cf2_stack_popInt( opStack );
+
+          curY = cf2_stack_popFixed( opStack );
+          curX = cf2_stack_popFixed( opStack );
+
+          error2 = cf2_getSeacComponent( decoder, achar, &component );
+          if ( error2 )
+          {
+            lastError = error2;      /* pass FreeType error through */
+            goto exit;
+          }
+          cf2_interpT2CharString( font,
+                                  &component,
+                                  callbacks,
+                                  translation,
+                                  TRUE,
+                                  curX,
+                                  curY,
+                                  &dummyWidth );
+          cf2_freeSeacComponent( decoder, &component );
+
+          error2 = cf2_getSeacComponent( decoder, bchar, &component );
+          if ( error2 )
+          {
+            lastError = error2;      /* pass FreeType error through */
+            goto exit;
+          }
+          cf2_interpT2CharString( font,
+                                  &component,
+                                  callbacks,
+                                  translation,
+                                  TRUE,
+                                  0,
+                                  0,
+                                  &dummyWidth );
+          cf2_freeSeacComponent( decoder, &component );
+        }
+        goto exit;
+
+      case cf2_cmdCNTRMASK:
+      case cf2_cmdHINTMASK:
+        /* the final \n in the tracing message gets added in      */
+        /* `cf2_hintmask_read' (which also traces the mask bytes) */
+        FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
+
+        /* never add hints after the mask is computed */
+        if ( cf2_stack_count( opStack ) > 1    &&
+             cf2_hintmask_isValid( &hintMask ) )
+        {
+          FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
+          break;
+        }
+
+        /* if there are arguments on the stack, there this is an */
+        /* implied cf2_cmdVSTEMHM                                */
+        cf2_doStems( font,
+                     opStack,
+                     &vStemHintArray,
+                     width,
+                     &haveWidth,
+                     0 );
+
+        if ( font->decoder->width_only )
+          goto exit;
+
+        if ( op1 == cf2_cmdHINTMASK )
+        {
+          /* consume the hint mask bytes which follow the operator */
+          cf2_hintmask_read( &hintMask,
+                             charstring,
+                             cf2_arrstack_size( &hStemHintArray ) +
+                               cf2_arrstack_size( &vStemHintArray ) );
+        }
+        else
+        {
+          /*
+           * Consume the counter mask bytes which follow the operator:
+           * Build a temporary hint map, just to place and lock those
+           * stems participating in the counter mask.  These are most
+           * likely the dominant hstems, and are grouped together in a
+           * few counter groups, not necessarily in correspondence
+           * with the hint groups.  This reduces the chances of
+           * conflicts between hstems that are initially placed in
+           * separate hint groups and then brought together.  The
+           * positions are copied back to `hStemHintArray', so we can
+           * discard `counterMask' and `counterHintMap'.
+           *
+           */
+          CF2_HintMapRec   counterHintMap;
+          CF2_HintMaskRec  counterMask;
+
+
+          cf2_hintmap_init( &counterHintMap,
+                            font,
+                            &glyphPath.initialHintMap,
+                            &glyphPath.hintMoves,
+                            scaleY );
+          cf2_hintmask_init( &counterMask, error );
+
+          cf2_hintmask_read( &counterMask,
+                             charstring,
+                             cf2_arrstack_size( &hStemHintArray ) +
+                               cf2_arrstack_size( &vStemHintArray ) );
+          cf2_hintmap_build( &counterHintMap,
+                             &hStemHintArray,
+                             &vStemHintArray,
+                             &counterMask,
+                             0,
+                             FALSE );
+        }
+        break;
+
+      case cf2_cmdRMOVETO:
+        FT_TRACE4(( " rmoveto\n" ));
+
+        if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
+          *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
+                              nominalWidthX );
+
+        /* width is defined or default after this */
+        haveWidth = TRUE;
+
+        if ( font->decoder->width_only )
+          goto exit;
+
+        curY = ADD_INT32( curY, cf2_stack_popFixed( opStack ) );
+        curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) );
+
+        cf2_glyphpath_moveTo( &glyphPath, curX, curY );
+
+        break;
+
+      case cf2_cmdHMOVETO:
+        FT_TRACE4(( " hmoveto\n" ));
+
+        if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
+          *width = ADD_INT32( cf2_stack_getReal( opStack, 0 ),
+                              nominalWidthX );
+
+        /* width is defined or default after this */
+        haveWidth = TRUE;
+
+        if ( font->decoder->width_only )
+          goto exit;
+
+        curX = ADD_INT32( curX, cf2_stack_popFixed( opStack ) );
+
+        cf2_glyphpath_moveTo( &glyphPath, curX, curY );
+
+        break;
+
+      case cf2_cmdRLINECURVE:
+        {
+          CF2_UInt  count = cf2_stack_count( opStack );
+          CF2_UInt  idx   = 0;
+
+
+          FT_TRACE4(( " rlinecurve\n" ));
+
+          while ( idx + 6 < count )
+          {
+            curX = ADD_INT32( curX, cf2_stack_getReal( opStack,
+                                                       idx + 0 ) );
+            curY = ADD_INT32( curY, cf2_stack_getReal( opStack,
+                                                       idx + 1 ) );
+
+            cf2_glyphpath_lineTo( &glyphPath, curX, curY );
+            idx += 2;
+          }
+
+          while ( idx < count )
+          {
+            CF2_Fixed  x1, y1, x2, y2, x3, y3;
+
+
+            x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
+            y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), curY );
+            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), x1 );
+            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y1 );
+            x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 );
+            y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 5 ), y2 );
+
+            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
+
+            curX  = x3;
+            curY  = y3;
+            idx  += 6;
+          }
+
+          cf2_stack_clear( opStack );
+        }
+        continue; /* no need to clear stack again */
+
+      case cf2_cmdVVCURVETO:
+        {
+          CF2_UInt  count, count1 = cf2_stack_count( opStack );
+          CF2_UInt  idx = 0;
+
+
+          /* 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 & ~2U;
+          idx  += count1 - count;
+
+          FT_TRACE4(( " vvcurveto\n" ));
+
+          while ( idx < count )
+          {
+            CF2_Fixed  x1, y1, x2, y2, x3, y3;
+
+
+            if ( ( count - idx ) & 1 )
+            {
+              x1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curX );
+
+              idx++;
+            }
+            else
+              x1 = curX;
+
+            y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY );
+            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
+            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
+            x3 = x2;
+            y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 );
+
+            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
+
+            curX  = x3;
+            curY  = y3;
+            idx  += 4;
+          }
+
+          cf2_stack_clear( opStack );
+        }
+        continue; /* no need to clear stack again */
+
+      case cf2_cmdHHCURVETO:
+        {
+          CF2_UInt  count, count1 = cf2_stack_count( opStack );
+          CF2_UInt  idx = 0;
+
+
+          /* 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 & ~2U;
+          idx  += count1 - count;
+
+          FT_TRACE4(( " hhcurveto\n" ));
+
+          while ( idx < count )
+          {
+            CF2_Fixed  x1, y1, x2, y2, x3, y3;
+
+
+            if ( ( count - idx ) & 1 )
+            {
+              y1 = ADD_INT32( cf2_stack_getReal( opStack, idx ), curY );
+
+              idx++;
+            }
+            else
+              y1 = curY;
+
+            x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
+            x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
+            y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
+            x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 );
+            y3 = y2;
+
+            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
+
+            curX  = x3;
+            curY  = y3;
+            idx  += 4;
+          }
+
+          cf2_stack_clear( opStack );
+        }
+        continue; /* no need to clear stack again */
+
+      case cf2_cmdVHCURVETO:
+      case cf2_cmdHVCURVETO:
+        {
+          CF2_UInt  count, count1 = cf2_stack_count( opStack );
+          CF2_UInt  idx = 0;
+
+          FT_Bool  alternate = FT_BOOL( op1 == cf2_cmdHVCURVETO );
+
+
+          /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */
+          /* 8n+4, or 8n+5, we enforce it by clearing the     */
+          /* second bit                                       */
+          /* (and sorting the stack indexing to suit)         */
+          count = count1 & ~2U;
+          idx  += count1 - count;
+
+          FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
+
+          while ( idx < count )
+          {
+            CF2_Fixed x1, x2, x3, y1, y2, y3;
+
+
+            if ( alternate )
+            {
+              x1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curX );
+              y1 = curY;
+              x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
+              y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
+              y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), y2 );
+
+              if ( count - idx == 5 )
+              {
+                x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), x2 );
+
+                idx++;
+              }
+              else
+                x3 = x2;
+
+              alternate = FALSE;
+            }
+            else
+            {
+              x1 = curX;
+              y1 = ADD_INT32( cf2_stack_getReal( opStack, idx + 0 ), curY );
+              x2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 1 ), x1 );
+              y2 = ADD_INT32( cf2_stack_getReal( opStack, idx + 2 ), y1 );
+              x3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 3 ), x2 );
+
+              if ( count - idx == 5 )
+              {
+                y3 = ADD_INT32( cf2_stack_getReal( opStack, idx + 4 ), y2 );
+
+                idx++;
+              }
+              else
+                y3 = y2;
+
+              alternate = TRUE;
+            }
+
+            cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
+
+            curX  = x3;
+            curY  = y3;
+            idx  += 4;
+          }
+
+          cf2_stack_clear( opStack );
+        }
+        continue;     /* no need to clear stack again */
+
+      case cf2_cmdEXTENDEDNMBR:
+        {
+          CF2_Int  v;
+
+          CF2_Int  byte1 = cf2_buf_readByte( charstring );
+          CF2_Int  byte2 = cf2_buf_readByte( charstring );
+
+
+          v = (FT_Short)( ( byte1 << 8 ) |
+                            byte2        );
+
+          FT_TRACE4(( " %d", v ));
+
+          cf2_stack_pushInt( opStack, v );
+        }
+        continue;
+
+      default:
+        /* numbers */
+        {
+          if ( /* op1 >= 32 && */ op1 <= 246 )
+          {
+            CF2_Int  v;
+
+
+            v = op1 - 139;
+
+            FT_TRACE4(( " %d", v ));
+
+            /* -107 .. 107 */
+            cf2_stack_pushInt( opStack, v );
+          }
+
+          else if ( /* op1 >= 247 && */ op1 <= 250 )
+          {
+            CF2_Int  v;
+
+
+            v  = op1;
+            v -= 247;
+            v *= 256;
+            v += cf2_buf_readByte( charstring );
+            v += 108;
+
+            FT_TRACE4(( " %d", v ));
+
+            /* 108 .. 1131 */
+            cf2_stack_pushInt( opStack, v );
+          }
+
+          else if ( /* op1 >= 251 && */ op1 <= 254 )
+          {
+            CF2_Int  v;
+
+
+            v  = op1;
+            v -= 251;
+            v *= 256;
+            v += cf2_buf_readByte( charstring );
+            v  = -v - 108;
+
+            FT_TRACE4(( " %d", v ));
+
+            /* -1131 .. -108 */
+            cf2_stack_pushInt( opStack, v );
+          }
+
+          else /* op1 == 255 */
+          {
+            CF2_Fixed  v;
+
+            FT_UInt32  byte1 = (FT_UInt32)cf2_buf_readByte( charstring );
+            FT_UInt32  byte2 = (FT_UInt32)cf2_buf_readByte( charstring );
+            FT_UInt32  byte3 = (FT_UInt32)cf2_buf_readByte( charstring );
+            FT_UInt32  byte4 = (FT_UInt32)cf2_buf_readByte( charstring );
+
+
+            v = (CF2_Fixed)( ( byte1 << 24 ) |
+                             ( byte2 << 16 ) |
+                             ( byte3 <<  8 ) |
+                               byte4         );
+
+            FT_TRACE4(( " %.5f", v / 65536.0 ));
+
+            cf2_stack_pushFixed( opStack, v );
+          }
+        }
+        continue;   /* don't clear stack */
+
+      } /* end of switch statement checking `op1' */
+
+      cf2_stack_clear( opStack );
+
+    } /* end of main interpreter loop */
+
+    /* we get here if the charstring ends without cf2_cmdENDCHAR */
+    FT_TRACE4(( "cf2_interpT2CharString:"
+                "  charstring ends without ENDCHAR\n" ));
+
+  exit:
+    /* check whether last error seen is also the first one */
+    cf2_setError( error, lastError );
+
+    if ( *error )
+      FT_TRACE4(( "charstring error %d\n", *error ));
+
+    /* free resources from objects we've used */
+    cf2_glyphpath_finalize( &glyphPath );
+    cf2_arrstack_finalize( &vStemHintArray );
+    cf2_arrstack_finalize( &hStemHintArray );
+    cf2_arrstack_finalize( &subrStack );
+    cf2_stack_free( opStack );
+
+    FT_TRACE4(( "\n" ));
+
+    return;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psintrp.h
@@ -1,0 +1,83 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2font.h                                                              */
+/*                                                                         */
+/*    Adobe's CFF Interpreter (specification).                             */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2INTRP_H_
+#define CF2INTRP_H_
+
+
+#include "psft.h"
+#include "pshints.h"
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( void )
+  cf2_hintmask_init( CF2_HintMask  hintmask,
+                     FT_Error*     error );
+  FT_LOCAL( FT_Bool )
+  cf2_hintmask_isValid( const CF2_HintMask  hintmask );
+  FT_LOCAL( FT_Bool )
+  cf2_hintmask_isNew( const CF2_HintMask  hintmask );
+  FT_LOCAL( void )
+  cf2_hintmask_setNew( CF2_HintMask  hintmask,
+                       FT_Bool       val );
+  FT_LOCAL( FT_Byte* )
+  cf2_hintmask_getMaskPtr( CF2_HintMask  hintmask );
+  FT_LOCAL( void )
+  cf2_hintmask_setAll( CF2_HintMask  hintmask,
+                       size_t        bitCount );
+
+  FT_LOCAL( void )
+  cf2_interpT2CharString( CF2_Font              font,
+                          CF2_Buffer            charstring,
+                          CF2_OutlineCallbacks  callbacks,
+                          const FT_Vector*      translation,
+                          FT_Bool               doingSeac,
+                          CF2_Fixed             curX,
+                          CF2_Fixed             curY,
+                          CF2_Fixed*            width );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2INTRP_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psread.c
@@ -1,0 +1,112 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2read.c                                                              */
+/*                                                                         */
+/*    Adobe's code for stream handling (body).                             */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include FT_INTERNAL_DEBUG_H
+
+#include "psglue.h"
+
+#include "pserror.h"
+
+
+  /* Define CF2_IO_FAIL as 1 to enable random errors and random */
+  /* value errors in I/O.                                       */
+#define CF2_IO_FAIL  0
+
+
+#if CF2_IO_FAIL
+
+  /* set the .00 value to a nonzero probability */
+  static int
+  randomError2( void )
+  {
+    /* for region buffer ReadByte (interp) function */
+    return (double)rand() / RAND_MAX < .00;
+  }
+
+  /* set the .00 value to a nonzero probability */
+  static CF2_Int
+  randomValue()
+  {
+    return (double)rand() / RAND_MAX < .00 ? rand() : 0;
+  }
+
+#endif /* CF2_IO_FAIL */
+
+
+  /* Region Buffer                                      */
+  /*                                                    */
+  /* Can be constructed from a copied buffer managed by */
+  /* `FCM_getDatablock'.                                */
+  /* Reads bytes with check for end of buffer.          */
+
+  /* reading past the end of the buffer sets error and returns zero */
+  FT_LOCAL_DEF( CF2_Int )
+  cf2_buf_readByte( CF2_Buffer  buf )
+  {
+    if ( buf->ptr < buf->end )
+    {
+#if CF2_IO_FAIL
+      if ( randomError2() )
+      {
+        CF2_SET_ERROR( buf->error, Invalid_Stream_Operation );
+        return 0;
+      }
+
+      return *(buf->ptr)++ + randomValue();
+#else
+      return *(buf->ptr)++;
+#endif
+    }
+    else
+    {
+      CF2_SET_ERROR( buf->error, Invalid_Stream_Operation );
+      return 0;
+    }
+  }
+
+
+  /* note: end condition can occur without error */
+  FT_LOCAL_DEF( FT_Bool )
+  cf2_buf_isEnd( CF2_Buffer  buf )
+  {
+    return (FT_Bool)( buf->ptr >= buf->end );
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psread.h
@@ -1,0 +1,68 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2read.h                                                              */
+/*                                                                         */
+/*    Adobe's code for stream handling (specification).                    */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2READ_H_
+#define CF2READ_H_
+
+
+FT_BEGIN_HEADER
+
+
+  typedef struct  CF2_BufferRec_
+  {
+    FT_Error*       error;
+    const FT_Byte*  start;
+    const FT_Byte*  end;
+    const FT_Byte*  ptr;
+
+  } CF2_BufferRec, *CF2_Buffer;
+
+
+  FT_LOCAL( CF2_Int )
+  cf2_buf_readByte( CF2_Buffer  buf );
+  FT_LOCAL( FT_Bool )
+  cf2_buf_isEnd( CF2_Buffer  buf );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2READ_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psstack.c
@@ -1,0 +1,328 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2stack.c                                                             */
+/*                                                                         */
+/*    Adobe's code for emulating a CFF stack (body).                       */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "psft.h"
+#include FT_INTERNAL_DEBUG_H
+
+#include "psglue.h"
+#include "psfont.h"
+#include "psstack.h"
+
+#include "pserror.h"
+
+
+  /* Allocate and initialize an instance of CF2_Stack.       */
+  /* Note: This function returns NULL on error (does not set */
+  /* `error').                                               */
+  FT_LOCAL_DEF( CF2_Stack )
+  cf2_stack_init( FT_Memory  memory,
+                  FT_Error*  e,
+                  FT_UInt    stackSize )
+  {
+    FT_Error  error = FT_Err_Ok;     /* for FT_NEW */
+
+    CF2_Stack  stack = NULL;
+
+
+    if ( !FT_NEW( stack ) )
+    {
+      /* initialize the structure; FT_NEW zeroes it */
+      stack->memory = memory;
+      stack->error  = e;
+    }
+
+    /* allocate the stack buffer */
+    if ( FT_NEW_ARRAY( stack->buffer, stackSize ) )
+    {
+      FT_FREE( stack );
+      return NULL;
+    }
+
+    stack->stackSize = stackSize;
+    stack->top       = stack->buffer;     /* empty stack */
+
+    return stack;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_stack_free( CF2_Stack  stack )
+  {
+    if ( stack )
+    {
+      FT_Memory  memory = stack->memory;
+
+      /* free the buffer */
+      FT_FREE( stack->buffer );
+
+      /* free the main structure */
+      FT_FREE( stack );
+    }
+  }
+
+
+  FT_LOCAL_DEF( CF2_UInt )
+  cf2_stack_count( CF2_Stack  stack )
+  {
+    return (CF2_UInt)( stack->top - stack->buffer );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_stack_pushInt( CF2_Stack  stack,
+                     CF2_Int    val )
+  {
+    if ( stack->top == stack->buffer + stack->stackSize )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Overflow );
+      return;     /* stack overflow */
+    }
+
+    stack->top->u.i  = val;
+    stack->top->type = CF2_NumberInt;
+    stack->top++;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_stack_pushFixed( CF2_Stack  stack,
+                       CF2_Fixed  val )
+  {
+    if ( stack->top == stack->buffer + stack->stackSize )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Overflow );
+      return;     /* stack overflow */
+    }
+
+    stack->top->u.r  = val;
+    stack->top->type = CF2_NumberFixed;
+    stack->top++;
+  }
+
+
+  /* this function is only allowed to pop an integer type */
+  FT_LOCAL_DEF( CF2_Int )
+  cf2_stack_popInt( CF2_Stack  stack )
+  {
+    if ( stack->top == stack->buffer )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Underflow );
+      return 0;   /* underflow */
+    }
+    if ( stack->top[-1].type != CF2_NumberInt )
+    {
+      CF2_SET_ERROR( stack->error, Syntax_Error );
+      return 0;   /* type mismatch */
+    }
+
+    stack->top--;
+
+    return stack->top->u.i;
+  }
+
+
+  /* Note: type mismatch is silently cast */
+  /* TODO: check this                     */
+  FT_LOCAL_DEF( CF2_Fixed )
+  cf2_stack_popFixed( CF2_Stack  stack )
+  {
+    if ( stack->top == stack->buffer )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Underflow );
+      return cf2_intToFixed( 0 );    /* underflow */
+    }
+
+    stack->top--;
+
+    switch ( stack->top->type )
+    {
+    case CF2_NumberInt:
+      return cf2_intToFixed( stack->top->u.i );
+    case CF2_NumberFrac:
+      return cf2_fracToFixed( stack->top->u.f );
+    default:
+      return stack->top->u.r;
+    }
+  }
+
+
+  /* Note: type mismatch is silently cast */
+  /* TODO: check this                     */
+  FT_LOCAL_DEF( CF2_Fixed )
+  cf2_stack_getReal( CF2_Stack  stack,
+                     CF2_UInt   idx )
+  {
+    FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize );
+
+    if ( idx >= cf2_stack_count( stack ) )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Overflow );
+      return cf2_intToFixed( 0 );    /* bounds error */
+    }
+
+    switch ( stack->buffer[idx].type )
+    {
+    case CF2_NumberInt:
+      return cf2_intToFixed( stack->buffer[idx].u.i );
+    case CF2_NumberFrac:
+      return cf2_fracToFixed( stack->buffer[idx].u.f );
+    default:
+      return stack->buffer[idx].u.r;
+    }
+  }
+
+
+  /* provide random access to stack */
+  FT_LOCAL_DEF( void )
+  cf2_stack_setReal( CF2_Stack  stack,
+                     CF2_UInt   idx,
+                     CF2_Fixed  val )
+  {
+    if ( idx > cf2_stack_count( stack ) )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Overflow );
+      return;
+    }
+
+    stack->buffer[idx].u.r  = val;
+    stack->buffer[idx].type = CF2_NumberFixed;
+  }
+
+
+  /* discard (pop) num values from stack */
+  FT_LOCAL_DEF( void )
+  cf2_stack_pop( CF2_Stack  stack,
+                 CF2_UInt   num )
+  {
+    if ( num > cf2_stack_count( stack ) )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Underflow );
+      return;
+    }
+    stack->top -= num;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_stack_roll( CF2_Stack  stack,
+                  CF2_Int    count,
+                  CF2_Int    shift )
+  {
+    /* we initialize this variable to avoid compiler warnings */
+    CF2_StackNumber  last = { { 0 }, CF2_NumberInt };
+
+    CF2_Int  start_idx, idx, i;
+
+
+    if ( count < 2 )
+      return; /* nothing to do (values 0 and 1), or undefined value */
+
+    if ( (CF2_UInt)count > cf2_stack_count( stack ) )
+    {
+      CF2_SET_ERROR( stack->error, Stack_Overflow );
+      return;
+    }
+
+    if ( shift < 0 )
+      shift = -( ( -shift ) % count );
+    else
+      shift %= count;
+
+    if ( shift == 0 )
+      return; /* nothing to do */
+
+    /* We use the following algorithm to do the rolling, */
+    /* which needs two temporary variables only.         */
+    /*                                                   */
+    /* Example:                                          */
+    /*                                                   */
+    /*   count = 8                                       */
+    /*   shift = 2                                       */
+    /*                                                   */
+    /*   stack indices before roll:  7 6 5 4 3 2 1 0     */
+    /*   stack indices after roll:   1 0 7 6 5 4 3 2     */
+    /*                                                   */
+    /* The value of index 0 gets moved to index 2, while */
+    /* the old value of index 2 gets moved to index 4,   */
+    /* and so on.  We thus have the following copying    */
+    /* chains for shift value 2.                         */
+    /*                                                   */
+    /*   0 -> 2 -> 4 -> 6 -> 0                           */
+    /*   1 -> 3 -> 5 -> 7 -> 1                           */
+    /*                                                   */
+    /* If `count' and `shift' are incommensurable, we    */
+    /* have a single chain only.  Otherwise, increase    */
+    /* the start index by 1 after the first chain, then  */
+    /* do the next chain until all elements in all       */
+    /* chains are handled.                               */
+
+    start_idx = -1;
+    idx       = -1;
+    for ( i = 0; i < count; i++ )
+    {
+      CF2_StackNumber  tmp;
+
+
+      if ( start_idx == idx )
+      {
+        start_idx++;
+        idx  = start_idx;
+        last = stack->buffer[idx];
+      }
+
+      idx += shift;
+      if ( idx >= count )
+        idx -= count;
+      else if ( idx < 0 )
+        idx += count;
+
+      tmp                = stack->buffer[idx];
+      stack->buffer[idx] = last;
+      last               = tmp;
+    }
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cf2_stack_clear( CF2_Stack  stack )
+  {
+    stack->top = stack->buffer;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/psstack.h
@@ -1,0 +1,121 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2stack.h                                                             */
+/*                                                                         */
+/*    Adobe's code for emulating a CFF stack (specification).              */
+/*                                                                         */
+/*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2STACK_H_
+#define CF2STACK_H_
+
+
+FT_BEGIN_HEADER
+
+
+  /* CFF operand stack; specified maximum of 48 or 192 values */
+  typedef struct  CF2_StackNumber_
+  {
+    union
+    {
+      CF2_Fixed  r;      /* 16.16 fixed point */
+      CF2_Frac   f;      /* 2.30 fixed point (for font matrix) */
+      CF2_Int    i;
+    } u;
+
+    CF2_NumberType  type;
+
+  } CF2_StackNumber;
+
+
+  typedef struct  CF2_StackRec_
+  {
+    FT_Memory         memory;
+    FT_Error*         error;
+    CF2_StackNumber*  buffer;
+    CF2_StackNumber*  top;
+    FT_UInt           stackSize;
+
+  } CF2_StackRec, *CF2_Stack;
+
+
+  FT_LOCAL( CF2_Stack )
+  cf2_stack_init( FT_Memory  memory,
+                  FT_Error*  error,
+                  FT_UInt    stackSize );
+  FT_LOCAL( void )
+  cf2_stack_free( CF2_Stack  stack );
+
+  FT_LOCAL( CF2_UInt )
+  cf2_stack_count( CF2_Stack  stack );
+
+  FT_LOCAL( void )
+  cf2_stack_pushInt( CF2_Stack  stack,
+                     CF2_Int    val );
+  FT_LOCAL( void )
+  cf2_stack_pushFixed( CF2_Stack  stack,
+                       CF2_Fixed  val );
+
+  FT_LOCAL( CF2_Int )
+  cf2_stack_popInt( CF2_Stack  stack );
+  FT_LOCAL( CF2_Fixed )
+  cf2_stack_popFixed( CF2_Stack  stack );
+
+  FT_LOCAL( CF2_Fixed )
+  cf2_stack_getReal( CF2_Stack  stack,
+                     CF2_UInt   idx );
+  FT_LOCAL( void )
+  cf2_stack_setReal( CF2_Stack  stack,
+                     CF2_UInt   idx,
+                     CF2_Fixed  val );
+
+  FT_LOCAL( void )
+  cf2_stack_pop( CF2_Stack  stack,
+                 CF2_UInt   num );
+
+  FT_LOCAL( void )
+  cf2_stack_roll( CF2_Stack  stack,
+                  CF2_Int    count,
+                  CF2_Int    idx );
+
+  FT_LOCAL( void )
+  cf2_stack_clear( CF2_Stack  stack );
+
+
+FT_END_HEADER
+
+
+#endif /* CF2STACK_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/psaux/pstypes.h
@@ -1,0 +1,78 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cf2types.h                                                             */
+/*                                                                         */
+/*    Adobe's code for defining data types (specification only).           */
+/*                                                                         */
+/*  Copyright 2011-2013 Adobe Systems Incorporated.                        */
+/*                                                                         */
+/*  This software, and all works of authorship, whether in source or       */
+/*  object code form as indicated by the copyright notice(s) included      */
+/*  herein (collectively, the "Work") is made available, and may only be   */
+/*  used, modified, and distributed under the FreeType Project License,    */
+/*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
+/*  FreeType Project License, each contributor to the Work hereby grants   */
+/*  to any individual or legal entity exercising permissions granted by    */
+/*  the FreeType Project License and this section (hereafter, "You" or     */
+/*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
+/*  royalty-free, irrevocable (except as stated in this section) patent    */
+/*  license to make, have made, use, offer to sell, sell, import, and      */
+/*  otherwise transfer the Work, where such license applies only to those  */
+/*  patent claims licensable by such contributor that are necessarily      */
+/*  infringed by their contribution(s) alone or by combination of their    */
+/*  contribution(s) with the Work to which such contribution(s) was        */
+/*  submitted.  If You institute patent litigation against any entity      */
+/*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
+/*  the Work or a contribution incorporated within the Work constitutes    */
+/*  direct or contributory patent infringement, then any patent licenses   */
+/*  granted to You under this License for that Work shall terminate as of  */
+/*  the date such litigation is filed.                                     */
+/*                                                                         */
+/*  By using, modifying, or distributing the Work you indicate that you    */
+/*  have read and understood the terms and conditions of the               */
+/*  FreeType Project License as well as those provided in this section,    */
+/*  and you accept them fully.                                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef CF2TYPES_H_
+#define CF2TYPES_H_
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*
+   * The data models that we expect to support are as follows:
+   *
+   *   name  char short int long long-long pointer example
+   *  -----------------------------------------------------
+   *   ILP32  8    16    32  32     64*      32    32-bit MacOS, x86
+   *   LLP64  8    16    32  32     64       64    x64
+   *   LP64   8    16    32  64     64       64    64-bit MacOS
+   *
+   *    *) type may be supported by emulation on a 32-bit architecture
+   *
+   */
+
+
+  /* integers at least 32 bits wide */
+#define CF2_UInt  FT_UFast
+#define CF2_Int   FT_Fast
+
+
+  /* fixed-float numbers */
+  typedef FT_Int32  CF2_F16Dot16;
+
+
+FT_END_HEADER
+
+
+#endif /* CF2TYPES_H_ */
+
+
+/* END */
--- a/src/psaux/rules.mk
+++ b/src/psaux/rules.mk
@@ -34,24 +34,24 @@
                  $(PSAUX_DIR)/afmparse.c \
                  $(PSAUX_DIR)/psconv.c   \
                  $(PSAUX_DIR)/psauxmod.c \
-                 $(PSAUX_DIR)/cf2arrst.c \
-                 $(PSAUX_DIR)/cf2blues.c \
-                 $(PSAUX_DIR)/cf2error.c \
-                 $(PSAUX_DIR)/cf2font.c  \
-                 $(PSAUX_DIR)/cf2ft.c    \
-                 $(PSAUX_DIR)/cf2hints.c \
-                 $(PSAUX_DIR)/cf2intrp.c \
-                 $(PSAUX_DIR)/cf2read.c  \
-                 $(PSAUX_DIR)/cf2stack.c \
-                 $(PSAUX_DIR)/cffdecode.c 
+                 $(PSAUX_DIR)/psarrst.c \
+                 $(PSAUX_DIR)/psblues.c \
+                 $(PSAUX_DIR)/pserror.c \
+                 $(PSAUX_DIR)/psfont.c  \
+                 $(PSAUX_DIR)/psft.c    \
+                 $(PSAUX_DIR)/pshints.c \
+                 $(PSAUX_DIR)/psintrp.c \
+                 $(PSAUX_DIR)/psread.c  \
+                 $(PSAUX_DIR)/psstack.c \
+                 $(PSAUX_DIR)/cffdecode.c
 
 # PSAUX driver headers
 #
 PSAUX_DRV_H := $(PSAUX_DRV_SRC:%c=%h)  \
                $(PSAUX_DIR)/psauxerr.h \
-               $(PSAUX_DIR)/cf2fixed.h \
-               $(PSAUX_DIR)/cf2glue.h  \
-               $(PSAUX_DIR)/cf2types.h
+               $(PSAUX_DIR)/psfixed.h \
+               $(PSAUX_DIR)/psglue.h  \
+               $(PSAUX_DIR)/pstypes.h
 
 
 # PSAUX driver object(s)