text:
/****************************************************************************
 *
 * t1cmap.h
 *
 *   Type 1 character map support (specification).
 *
 * Copyright (C) 2002-2020 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */

#ifndef T1CMAP_H_
#define T1CMAP_H_

#include <ft2build.h>
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_TYPE1_TYPES_H

FT_BEGIN_HEADER

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****          TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS           *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  /* standard (and expert) encoding cmaps */
  typedef struct T1_CMapStdRec_*  T1_CMapStd;

  typedef struct  T1_CMapStdRec_
  {
    FT_CMapRec                cmap;

    const FT_UShort*          code_to_sid;
    PS_Adobe_Std_StringsFunc  sid_to_string;

    FT_UInt                   num_glyphs;
    const char* const*        glyph_names;

  } T1_CMapStdRec;

  FT_CALLBACK_TABLE const FT_CMap_ClassRec
  t1_cmap_standard_class_rec;

  FT_CALLBACK_TABLE const FT_CMap_ClassRec
  t1_cmap_expert_class_rec;

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                  TYPE1 CUSTOM ENCODING CMAP                   *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  typedef struct T1_CMapCustomRec_*  T1_CMapCustom;

  typedef struct  T1_CMapCustomRec_
  {
    FT_CMapRec  cmap;
    FT_UInt     first;
    FT_UInt     count;
    FT_UShort*  indices;

  } T1_CMapCustomRec;

  FT_CALLBACK_TABLE const FT_CMap_ClassRec
  t1_cmap_custom_class_rec;

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****             TYPE1 SYNTHETIC UNICODE ENCODING CMAP             *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  /* unicode (synthetic) cmaps */

  FT_CALLBACK_TABLE const FT_CMap_ClassRec
  t1_cmap_unicode_class_rec;

 /* */

FT_END_HEADER

#endif /* T1CMAP_H_ */

/* END */

repo_language: C

mime_type: text/x-c


text:
/****************************************************************************
 *
 * afmparse.h
 *
 *   AFM parser (specification).
 *
 * Copyright (C) 2006-2020 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */

#ifndef AFMPARSE_H_
#define AFMPARSE_H_

#include <ft2build.h>
#include FT_INTERNAL_POSTSCRIPT_AUX_H

FT_BEGIN_HEADER

  FT_LOCAL( FT_Error )
  afm_parser_init( AFM_Parser  parser,
                   FT_Memory   memory,
                   FT_Byte*    base,
                   FT_Byte*    limit );

  FT_LOCAL( void )
  afm_parser_done( AFM_Parser  parser );

  FT_LOCAL( FT_Error )
  afm_parser_parse( AFM_Parser  parser );

  enum  AFM_ValueType_
  {
    AFM_VALUE_TYPE_STRING,
    AFM_VALUE_TYPE_NAME,
    AFM_VALUE_TYPE_FIXED,   /* real number */
    AFM_VALUE_TYPE_INTEGER,
    AFM_VALUE_TYPE_BOOL,
    AFM_VALUE_TYPE_INDEX    /* glyph index */
  };

  typedef struct  AFM_ValueRec_
  {
    enum AFM_ValueType_  type;
    union
    {
      char*     s;
      FT_Fixed  f;
      FT_Int    i;
      FT_UInt   u;
      FT_Bool   b;

    } u;

  } AFM_ValueRec, *AFM_Value;

#define  AFM_MAX_ARGUMENTS  5

  FT_LOCAL( FT_Int )
  afm_parser_read_vals( AFM_Parser  parser,
                        AFM_Value   vals,
                        FT_Int      n );

  /* read the next key from the next line or column */
  FT_LOCAL( char* )
  afm_parser_next_key( AFM_Parser  parser,
                       FT_Bool     line,
                       FT_Offset*  len );

FT_END_HEADER

#endif /* AFMPARSE_H_ */

/* END */


text:
/****************************************************************************
 *
 * psauxmod.c
 *
 *   FreeType auxiliary PostScript module implementation (body).
 *
 * Copyright (C) 2000-2020 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */

#include <ft2build.h>
#include "psauxmod.h"
#include "psobjs.h"
#include "t1decode.h"
#include "t1cmap.h"
#include "psft.h"
#include "cffdecode.h"

#ifndef T1_CONFIG_OPTION_NO_AFM
#include "afmparse.h"
#endif

  FT_CALLBACK_TABLE_DEF
  const PS_Table_FuncsRec  ps_table_funcs =
  {
    ps_table_new,     /* init    */
    ps_table_done,    /* done    */
    ps_table_add,     /* add     */
    ps_table_release  /* release */
  };

  FT_CALLBACK_TABLE_DEF
  const PS_Parser_FuncsRec  ps_parser_funcs =
  {
    ps_parser_init,             /* init             */
    ps_parser_done,             /* done             */

    ps_parser_skip_spaces,      /* skip_spaces      */
    ps_parser_skip_PS_token,    /* skip_PS_token    */

    ps_parser_to_int,           /* to_int           */
    ps_parser_to_fixed,         /* to_fixed         */
    ps_parser_to_bytes,         /* to_bytes         */
    ps_parser_to_coord_array,   /* to_coord_array   */
    ps_parser_to_fixed_array,   /* to_fixed_array   */
    ps_parser_to_token,         /* to_token         */
    ps_parser_to_token_array,   /* to_token_array   */

    ps_parser_load_field,       /* load_field       */
    ps_parser_load_field_table  /* load_field_table */
  };

  FT_CALLBACK_TABLE_DEF
  const PS_Builder_FuncsRec  ps_builder_funcs =
  {
    ps_builder_init,          /* init */
    ps_builder_done           /* done */
  };

  FT_CALLBACK_TABLE_DEF
  const T1_Builder_FuncsRec  t1_builder_funcs =
  {
    t1_builder_init,          /* init */
    t1_builder_done,          /* done */

    t1_builder_check_points,  /* check_points  */
    t1_builder_add_point,     /* add_point     */
    t1_builder_add_point1,    /* add_point1    */
    t1_builder_add_contour,   /* add_contour   */
    t1_builder_start_point,   /* start_point   */
    t1_builder_close_contour  /* close_contour */
  };

  FT_CALLBACK_TABLE_DEF
  const T1_Decoder_FuncsRec  t1_decoder_funcs =
  {
    t1_decoder_init,               /* init                  */
    t1_decoder_done,               /* done                  */
#ifdef T1_CONFIG_OPTION_OLD_ENGINE
    t1_decoder_parse_charstrings,  /* parse_charstrings_old */
#else
    t1_decoder_parse_metrics,      /* parse_metrics         */
#endif
    cf2_decoder_parse_charstrings  /* parse_charstrings     */
  };

#ifndef T1_CONFIG_OPTION_NO_AFM
  FT_CALLBACK_TABLE_DEF
  const AFM_Parser_FuncsRec  afm_parser_funcs =
  {
    afm_parser_init,  /* init  */
    afm_parser_done,  /* done  */
    afm_parser_parse  /* parse */
  };
#endif

  FT_CALLBACK_TABLE_DEF
  const T1_CMap_ClassesRec  t1_cmap_classes =
  {
    &t1_cmap_standard_class_rec,
    &t1_cmap_expert_class_rec,
    &t1_cmap_custom_class_rec,
    &t1_cmap_unicode_class_rec
  };

  FT_CALLBACK_TABLE_DEF
  const CFF_Builder_FuncsRec  cff_builder_funcs =
  {
    cff_builder_init,          /* init */
    cff_builder_done,          /* done */

    cff_check_points,          /* check_points  */
    cff_builder_add_point,     /* add_point     */
    cff_builder_add_point1,    /* add_point1    */
    cff_builder_add_contour,   /* add_contour   */
    cff_builder_start_point,   /* start_point   */
    cff_builder_close_contour  /* close_contour */
  };

  FT_CALLBACK_TABLE_DEF
  const CFF_Decoder_FuncsRec  cff_decoder_funcs =
  {
    cff_decoder_init,              /* init    */
    cff_decoder_prepare,           /* prepare */

#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
    cff_decoder_parse_charstrings, /* parse_charstrings_old */
#endif
    cf2_decoder_parse_charstrings  /* parse_charstrings     */
  };

  static
  const PSAux_Interface  psaux_interface =
  {
    &ps_table_funcs,
    &ps_parser_funcs,
    &t1_builder_funcs,
    &t1_decoder_funcs,
    t1_decrypt,
    cff_random,
    ps_decoder_init,
    t1_make_subfont,

    (const T1_CMap_ClassesRec*) &t1_cmap_classes,

#ifndef T1_CONFIG_OPTION_NO_AFM
    &afm_parser_funcs,
#else
    0,
#endif

    &cff_decoder_funcs,
  };

  FT_CALLBACK_TABLE_DEF
  const FT_Module_Class  psaux_module_class =
  {
    0,
    sizeof ( FT_ModuleRec ),
    "psaux",
    0x20000L,
    0x20000L,

    &psaux_interface,  /* module-specific interface */

    (FT_Module_Constructor)NULL,  /* module_init   */
    (FT_Module_Destructor) NULL,  /* module_done   */
    (FT_Module_Requester)  NULL   /* get_interface */
  };

/* END */


text:
/****************************************************************************
 *
 * psintrp.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 PSINTRP_H_
#define PSINTRP_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 /* PSINTRP_H_ */

/* END */


text:
/****************************************************************************
 *
 * psread.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 PSREAD_H_
#define PSREAD_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 /* PSREAD_H_ */

/* END */


text:
/****************************************************************************
 *
 * pstypes.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 PSTYPES_H_
#define PSTYPES_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 /* PSTYPES_H_ */

/* END */


text:
/****************************************************************************
 *
 * psaux.c
 *
 *   FreeType auxiliary PostScript driver component (body only).
 *
 * Copyright (C) 1996-2020 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */

#define FT_MAKE_OPTION_SINGLE_OBJECT
#include <ft2build.h>

#include "afmparse.c"
#include "psauxmod.c"
#include "psconv.c"
#include "psobjs.c"
#include "t1cmap.c"
#include "t1decode.c"
#include "cffdecode.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 */


text:
/****************************************************************************
 *
 * psfont.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 */
    PS_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;

    /* 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;
    }

    if ( !font->isT1 )
    {
      /* check for variation vectors */
      vstore        = cf2_getVStore( decoder );
      hasVariations = ( vstore->dataCount != 0 );

      if ( hasVariations )
      {
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
        FT_Service_CFFLoad  cffload = (FT_Service_CFFLoad)font->cffload;

        /* 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 */


text:
/****************************************************************************
 *
 * cffdecode.h
 *
 *   PostScript CFF (Type 2) decoding routines (specification).
 *
 * Copyright (C) 2017-2020 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */

#ifndef CFFDECODE_H_
#define CFFDECODE_H_

#include <ft2build.h>
#include FT_INTERNAL_POSTSCRIPT_AUX_H

FT_BEGIN_HEADER

  FT_LOCAL( void )
  cff_decoder_init( CFF_Decoder*                     decoder,
                    TT_Face                          face,
                    CFF_Size                         size,
                    CFF_GlyphSlot                    slot,
                    FT_Bool                          hinting,
                    FT_Render_Mode                   hint_mode,
                    CFF_Decoder_Get_Glyph_Callback   get_callback,
                    CFF_Decoder_Free_Glyph_Callback  free_callback );

  FT_LOCAL( FT_Error )
  cff_decoder_prepare( CFF_Decoder*  decoder,
                       CFF_Size      size,
                       FT_UInt       glyph_index );

  FT_LOCAL( FT_Int )
  cff_lookup_glyph_by_stdcharcode( CFF_Font  cff,
                                   FT_Int    charcode );

#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
  FT_LOCAL( FT_Error )
  cff_decoder_parse_charstrings( CFF_Decoder*  decoder,
                                 FT_Byte*      charstring_base,
                                 FT_ULong      charstring_len,
                                 FT_Bool       in_dict );
#endif

FT_END_HEADER

#endif

/* END */


text:
/****************************************************************************
 *
 * t1cmap.c
 *
 *   Type 1 character map support (body).
 *
 * Copyright (C) 2002-2020 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */

#include "t1cmap.h"

#include FT_INTERNAL_DEBUG_H

#include "psauxerr.h"

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****          TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS           *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  static void
  t1_cmap_std_init( T1_CMapStd  cmap,
                    FT_Int      is_expert )
  {
    T1_Face             face    = (T1_Face)FT_CMAP_FACE( cmap );
    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;

    cmap->num_glyphs    = (FT_UInt)face->type1.num_glyphs;
    cmap->glyph_names   = (const char* const*)face->type1.glyph_names;
    cmap->sid_to_string = psnames->adobe_std_strings;
    cmap->code_to_sid   = is_expert ? psnames->adobe_expert_encoding
                                    : psnames->adobe_std_encoding;

    FT_ASSERT( cmap->code_to_sid );
  }

  FT_CALLBACK_DEF( void )
  t1_cmap_std_done( T1_CMapStd  cmap )
  {
    cmap->num_glyphs    = 0;
    cmap->glyph_names   = NULL;
    cmap->sid_to_string = NULL;
    cmap->code_to_sid   = NULL;
  }

  FT_CALLBACK_DEF( FT_UInt )
  t1_cmap_std_char_index( T1_CMapStd  cmap,
                          FT_UInt32   char_code )
  {
    FT_UInt  result = 0;

    if ( char_code < 256 )
    {
      FT_UInt      code, n;
      const char*  glyph_name;

      /* convert character code to Adobe SID string */
      code       = cmap->code_to_sid[char_code];
      glyph_name = cmap->sid_to_string( code );

      /* look for the corresponding glyph name */
      for ( n = 0; n < cmap->num_glyphs; n++ )
      {
        const char* gname = cmap->glyph_names[n];

        if ( gname && gname[0] == glyph_name[0]  &&
             ft_strcmp( gname, glyph_name ) == 0 )
        {
          result = n;
          break;
        }
      }
    }

    return result;
  }

  FT_CALLBACK_DEF( FT_UInt32 )
  t1_cmap_std_char_next( T1_CMapStd   cmap,
                         FT_UInt32   *pchar_code )
  {
    FT_UInt    result    = 0;
    FT_UInt32  char_code = *pchar_code + 1;

    while ( char_code < 256 )
    {
      result = t1_cmap_std_char_index( cmap, char_code );
      if ( result != 0 )
        goto Exit;

      char_code++;
    }
    char_code = 0;

  Exit:
    *pchar_code = char_code;
    return result;
  }

  FT_CALLBACK_DEF( FT_Error )
  t1_cmap_standard_init( T1_CMapStd  cmap,
                         FT_Pointer  pointer )
  {
    FT_UNUSED( pointer );

    t1_cmap_std_init( cmap, 0 );
    return 0;
  }

  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
  t1_cmap_standard_class_rec =
  {
    sizeof ( T1_CMapStdRec ),

    (FT_CMap_InitFunc)     t1_cmap_standard_init,   /* init       */
    (FT_CMap_DoneFunc)     t1_cmap_std_done,        /* done       */
    (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,  /* char_index */
    (FT_CMap_CharNextFunc) t1_cmap_std_char_next,   /* char_next  */

    (FT_CMap_CharVarIndexFunc)    NULL,  /* char_var_index   */
    (FT_CMap_CharVarIsDefaultFunc)NULL,  /* char_var_default */
    (FT_CMap_VariantListFunc)     NULL,  /* variant_list     */
    (FT_CMap_CharVariantListFunc) NULL,  /* charvariant_list */
    (FT_CMap_VariantCharListFunc) NULL   /* variantchar_list */
  };

  FT_CALLBACK_DEF( FT_Error )
  t1_cmap_expert_init( T1_CMapStd  cmap,
                       FT_Pointer  pointer )
  {
    FT_UNUSED( pointer );

    t1_cmap_std_init( cmap, 1 );
    return 0;
  }

  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
  t1_cmap_expert_class_rec =
  {
    sizeof ( T1_CMapStdRec ),

    (FT_CMap_InitFunc)     t1_cmap_expert_init,     /* init       */
    (FT_CMap_DoneFunc)     t1_cmap_std_done,        /* done       */
    (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,  /* char_index */
    (FT_CMap_CharNextFunc) t1_cmap_std_char_next,   /* char_next  */

    (FT_CMap_CharVarIndexFunc)    NULL,  /* char_var_index   */
    (FT_CMap_CharVarIsDefaultFunc)NULL,  /* char_var_default */
    (FT_CMap_VariantListFunc)     NULL,  /* variant_list     */
    (FT_CMap_CharVariantListFunc) NULL,  /* charvariant_list */
    (FT_CMap_VariantCharListFunc) NULL   /* variantchar_list */
  };

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                    TYPE1 CUSTOM ENCODING CMAP                 *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  FT_CALLBACK_DEF( FT_Error )
  t1_cmap_custom_init( T1_CMapCustom  cmap,
                       FT_Pointer     pointer )
  {
    T1_Face      face     = (T1_Face)FT_CMAP_FACE( cmap );
    T1_Encoding  encoding = &face->type1.encoding;

    FT_UNUSED( pointer );

    cmap->first   = (FT_UInt)encoding->code_first;
    cmap->count   = (FT_UInt)encoding->code_last - cmap->first;
    cmap->indices = encoding->char_index;

    FT_ASSERT( cmap->indices );
    FT_ASSERT( encoding->code_first <= encoding->code_last );

    return 0;
  }

  FT_CALLBACK_DEF( void )
  t1_cmap_custom_done( T1_CMapCustom  cmap )
  {
    cmap->indices = NULL;
    cmap->first   = 0;
    cmap->count   = 0;
  }

  FT_CALLBACK_DEF( FT_UInt )
  t1_cmap_custom_char_index( T1_CMapCustom  cmap,
                             FT_UInt32      char_code )
  {
    FT_UInt    result = 0;

    if ( ( char_code >= cmap->first )                  &&
         ( char_code < ( cmap->first + cmap->count ) ) )
      result = cmap->indices[char_code];

    return result;
  }

  FT_CALLBACK_DEF( FT_UInt32 )
  t1_cmap_custom_char_next( T1_CMapCustom  cmap,
                            FT_UInt32     *pchar_code )
  {
    FT_UInt    result = 0;
    FT_UInt32  char_code = *pchar_code;

    char_code++;

    if ( char_code < cmap->first )
      char_code = cmap->first;

    for ( ; char_code < ( cmap->first + cmap->count ); char_code++ )
    {
      result = cmap->indices[char_code];
      if ( result != 0 )
        goto Exit;
    }

    char_code = 0;

  Exit:
    *pchar_code = char_code;
    return result;
  }

  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
  t1_cmap_custom_class_rec =
  {
    sizeof ( T1_CMapCustomRec ),

    (FT_CMap_InitFunc)     t1_cmap_custom_init,        /* init       */
    (FT_CMap_DoneFunc)     t1_cmap_custom_done,        /* done       */
    (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index,  /* char_index */
    (FT_CMap_CharNextFunc) t1_cmap_custom_char_next,   /* char_next  */

    (FT_CMap_CharVarIndexFunc)    NULL,  /* char_var_index   */
    (FT_CMap_CharVarIsDefaultFunc)NULL,  /* char_var_default */
    (FT_CMap_VariantListFunc)     NULL,  /* variant_list     */
    (FT_CMap_CharVariantListFunc) NULL,  /* charvariant_list */
    (FT_CMap_VariantCharListFunc) NULL   /* variantchar_list */
  };

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****            TYPE1 SYNTHETIC UNICODE ENCODING CMAP              *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  FT_CALLBACK_DEF( const char * )
  psaux_get_glyph_name( T1_Face  face,
                        FT_UInt  idx )
  {
    return face->type1.glyph_names[idx];
  }

  FT_CALLBACK_DEF( FT_Error )
  t1_cmap_unicode_init( PS_Unicodes  unicodes,
                        FT_Pointer   pointer )
  {
    T1_Face             face    = (T1_Face)FT_CMAP_FACE( unicodes );
    FT_Memory           memory  = FT_FACE_MEMORY( face );
    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;

    FT_UNUSED( pointer );

    if ( !psnames->unicodes_init )
      return FT_THROW( Unimplemented_Feature );

    return psnames->unicodes_init( memory,
                                   unicodes,
                                   (FT_UInt)face->type1.num_glyphs,
                                   (PS_GetGlyphNameFunc)&psaux_get_glyph_name,
                                   (PS_FreeGlyphNameFunc)NULL,
                                   (FT_Pointer)face );
  }

  FT_CALLBACK_DEF( void )
  t1_cmap_unicode_done( PS_Unicodes  unicodes )
  {
    FT_Face    face   = FT_CMAP_FACE( unicodes );
    FT_Memory  memory = FT_FACE_MEMORY( face );

    FT_FREE( unicodes->maps );
    unicodes->num_maps = 0;
  }

  FT_CALLBACK_DEF( FT_UInt )
  t1_cmap_unicode_char_index( PS_Unicodes  unicodes,
                              FT_UInt32    char_code )
  {
    T1_Face             face    = (T1_Face)FT_CMAP_FACE( unicodes );
    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;

    return psnames->unicodes_char_index( unicodes, char_code );
  }

  FT_CALLBACK_DEF( FT_UInt32 )
  t1_cmap_unicode_char_next( PS_Unicodes  unicodes,
                             FT_UInt32   *pchar_code )
  {
    T1_Face             face    = (T1_Face)FT_CMAP_FACE( unicodes );
    FT_Service_PsCMaps  psnames = (FT_Service_PsCMaps)face->psnames;

    return psnames->unicodes_char_next( unicodes, pchar_code );
  }

  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
  t1_cmap_unicode_class_rec =
  {
    sizeof ( PS_UnicodesRec ),

    (FT_CMap_InitFunc)     t1_cmap_unicode_init,        /* init       */
    (FT_CMap_DoneFunc)     t1_cmap_unicode_done,        /* done       */
    (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index,  /* char_index */
    (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next,   /* char_next  */

    (FT_CMap_CharVarIndexFunc)    NULL,  /* char_var_index   */
    (FT_CMap_CharVarIsDefaultFunc)NULL,  /* char_var_default */
    (FT_CMap_VariantListFunc)     NULL,  /* variant_list     */
    (FT_CMap_CharVariantListFunc) NULL,  /* charvariant_list */
    (FT_CMap_VariantCharListFunc) NULL   /* variantchar_list */
  };

/* END */


text:
# FreeType 2 src/psaux Jamfile
#
# Copyright (C) 2001-2020 by
# David Turner, Robert Wilhelm, and Werner Lemberg.
#
# This file is part of the FreeType project, and may only be used, modified,
# and distributed under the terms of the FreeType project license,
# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
# indicate that you have read the license and understand and accept it
# fully.

SubDir  FT2_TOP $(FT2_SRC_DIR) psaux ;

{
  local  _sources ;

  if $(FT2_MULTI)
  {
    _sources = afmparse
               psauxmod
               psconv
               psobjs
               t1cmap
               t1decode
               cffdecode
               psarrst
               psblues
               pserror
               psfont
               psft
               pshints
               psintrp
               psread
               psstack
               ;
  }
  else
  {
    _sources = psaux ;
  }

  Library  $(FT2_LIB) : $(_sources).c ;
}

# end of src/psaux Jamfile


text:
#
# FreeType 2 PSaux module definition
#

# Copyright (C) 1996-2020 by
# David Turner, Robert Wilhelm, and Werner Lemberg.
#
# This file is part of the FreeType project, and may only be used, modified,
# and distributed under the terms of the FreeType project license,
# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
# indicate that you have read the license and understand and accept it
# fully.

FTMODULE_H_COMMANDS += PSAUX_MODULE

define PSAUX_MODULE
$(OPEN_DRIVER) FT_Module_Class, psaux_module_class $(CLOSE_DRIVER)
$(ECHO_DRIVER)psaux     $(ECHO_DRIVER_DESC)Postscript Type 1 & Type 2 helper module$(ECHO_DRIVER_DONE)
endef

# EOF


text:
/****************************************************************************
 *
 * psfont.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 PSFONT_H_
#define PSFONT_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             isT1;
    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 */
    PS_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 /* PSFONT_H_ */

/* END */


text:
/****************************************************************************
 *
 * afmparse.c
 *
 *   AFM parser (body).
 *
 * Copyright (C) 2006-2020 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_POSTSCRIPT_AUX_H

#ifndef T1_CONFIG_OPTION_NO_AFM

#include "afmparse.h"
#include "psconv.h"

#include "psauxerr.h"

  /**************************************************************************
   *
   * AFM_Stream
   *
   * The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib.
   *
   */

  enum
  {
    AFM_STREAM_STATUS_NORMAL,
    AFM_STREAM_STATUS_EOC,
    AFM_STREAM_STATUS_EOL,
    AFM_STREAM_STATUS_EOF
  };

  typedef struct  AFM_StreamRec_
  {
    FT_Byte*  cursor;
    FT_Byte*  base;
    FT_Byte*  limit;

    FT_Int    status;

  } AFM_StreamRec;

#ifndef EOF
#define EOF -1
#endif

  /* this works because empty lines are ignored */
#define AFM_IS_NEWLINE( ch )  ( (ch) == '\r' || (ch) == '\n' )

#define AFM_IS_EOF( ch )      ( (ch) == EOF  || (ch) == '\x1a' )
#define AFM_IS_SPACE( ch )    ( (ch) == ' '  || (ch) == '\t' )

  /* column separator; there is no `column' in the spec actually */
#define AFM_IS_SEP( ch )      ( (ch) == ';' )

#define AFM_GETC()                                                       \
          ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \
                                                   : EOF )

#define AFM_STREAM_KEY_BEGIN( stream )    \
          (char*)( (stream)->cursor - 1 )

#define AFM_STREAM_KEY_LEN( stream, key )           \
          (FT_Offset)( (char*)(stream)->cursor - key - 1 )

#define AFM_STATUS_EOC( stream ) \
          ( (stream)->status >= AFM_STREAM_STATUS_EOC )

#define AFM_STATUS_EOL( stream ) \
          ( (stream)->status >= AFM_STREAM_STATUS_EOL )

#define AFM_STATUS_EOF( stream ) \
          ( (stream)->status >= AFM_STREAM_STATUS_EOF )

  static int
  afm_stream_skip_spaces( AFM_Stream  stream )
  {
    int  ch = 0;  /* make stupid compiler happy */

    if ( AFM_STATUS_EOC( stream ) )
      return ';';

    while ( 1 )
    {
      ch = AFM_GETC();
      if ( !AFM_IS_SPACE( ch ) )
        break;
    }

    if ( AFM_IS_NEWLINE( ch ) )
      stream->status = AFM_STREAM_STATUS_EOL;
    else if ( AFM_IS_SEP( ch ) )
      stream->status = AFM_STREAM_STATUS_EOC;
    else if ( AFM_IS_EOF( ch ) )
      stream->status = AFM_STREAM_STATUS_EOF;

    return ch;
  }

  /* read a key or value in current column */
  static char*
  afm_stream_read_one( AFM_Stream  stream )
  {
    char*  str;

    afm_stream_skip_spaces( stream );
    if ( AFM_STATUS_EOC( stream ) )
      return NULL;

    str = AFM_STREAM_KEY_BEGIN( stream );

    while ( 1 )
    {
      int  ch = AFM_GETC();

      if ( AFM_IS_SPACE( ch ) )
        break;
      else if ( AFM_IS_NEWLINE( ch ) )
      {
        stream->status = AFM_STREAM_STATUS_EOL;
        break;
      }
      else if ( AFM_IS_SEP( ch ) )
      {
        stream->status = AFM_STREAM_STATUS_EOC;
        break;
      }
      else if ( AFM_IS_EOF( ch ) )
      {
        stream->status = AFM_STREAM_STATUS_EOF;
        break;
      }
    }

    return str;
  }

  /* read a string (i.e., read to EOL) */
  static char*
  afm_stream_read_string( AFM_Stream  stream )
  {
    char*  str;

    afm_stream_skip_spaces( stream );
    if ( AFM_STATUS_EOL( stream ) )
      return NULL;

    str = AFM_STREAM_KEY_BEGIN( stream );

    /* scan to eol */
    while ( 1 )
    {
      int  ch = AFM_GETC();

      if ( AFM_IS_NEWLINE( ch ) )
      {
        stream->status = AFM_STREAM_STATUS_EOL;
        break;
      }
      else if ( AFM_IS_EOF( ch ) )
      {
        stream->status = AFM_STREAM_STATUS_EOF;
        break;
      }
    }

    return str;
  }

  /**************************************************************************
   *
   * AFM_Parser
   *
   */

  /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
  typedef enum  AFM_Token_
  {
    AFM_TOKEN_ASCENDER,
    AFM_TOKEN_AXISLABEL,
    AFM_TOKEN_AXISTYPE,
    AFM_TOKEN_B,
    AFM_TOKEN_BLENDAXISTYPES,
    AFM_TOKEN_BLENDDESIGNMAP,
    AFM_TOKEN_BLENDDESIGNPOSITIONS,
    AFM_TOKEN_C,
    AFM_TOKEN_CC,
    AFM_TOKEN_CH,
    AFM_TOKEN_CAPHEIGHT,
    AFM_TOKEN_CHARWIDTH,
    AFM_TOKEN_CHARACTERSET,
    AFM_TOKEN_CHARACTERS,
    AFM_TOKEN_DESCENDER,
    AFM_TOKEN_ENCODINGSCHEME,
    AFM_TOKEN_ENDAXIS,
    AFM_TOKEN_ENDCHARMETRICS,
    AFM_TOKEN_ENDCOMPOSITES,
    AFM_TOKEN_ENDDIRECTION,
    AFM_TOKEN_ENDFONTMETRICS,
    AFM_TOKEN_ENDKERNDATA,
    AFM_TOKEN_ENDKERNPAIRS,
    AFM_TOKEN_ENDTRACKKERN,
    AFM_TOKEN_ESCCHAR,
    AFM_TOKEN_FAMILYNAME,
    AFM_TOKEN_FONTBBOX,
    AFM_TOKEN_FONTNAME,
    AFM_TOKEN_FULLNAME,
    AFM_TOKEN_ISBASEFONT,
    AFM_TOKEN_ISCIDFONT,
    AFM_TOKEN_ISFIXEDPITCH,
    AFM_TOKEN_ISFIXEDV,
    AFM_TOKEN_ITALICANGLE,
    AFM_TOKEN_KP,
    AFM_TOKEN_KPH,
    AFM_TOKEN_KPX,
    AFM_TOKEN_KPY,
    AFM_TOKEN_L,
    AFM_TOKEN_MAPPINGSCHEME,
    AFM_TOKEN_METRICSSETS,
    AFM_TOKEN_N,
    AFM_TOKEN_NOTICE,
    AFM_TOKEN_PCC,
    AFM_TOKEN_STARTAXIS,
    AFM_TOKEN_STARTCHARMETRICS,
    AFM_TOKEN_STARTCOMPOSITES,
    AFM_TOKEN_STARTDIRECTION,
    AFM_TOKEN_STARTFONTMETRICS,
    AFM_TOKEN_STARTKERNDATA,
    AFM_TOKEN_STARTKERNPAIRS,
    AFM_TOKEN_STARTKERNPAIRS0,
    AFM_TOKEN_STARTKERNPAIRS1,
    AFM_TOKEN_STARTTRACKKERN,
    AFM_TOKEN_STDHW,
    AFM_TOKEN_STDVW,
    AFM_TOKEN_TRACKKERN,
    AFM_TOKEN_UNDERLINEPOSITION,
    AFM_TOKEN_UNDERLINETHICKNESS,
    AFM_TOKEN_VV,
    AFM_TOKEN_VVECTOR,
    AFM_TOKEN_VERSION,
    AFM_TOKEN_W,
    AFM_TOKEN_W0,
    AFM_TOKEN_W0X,
    AFM_TOKEN_W0Y,
    AFM_TOKEN_W1,
    AFM_TOKEN_W1X,
    AFM_TOKEN_W1Y,
    AFM_TOKEN_WX,
    AFM_TOKEN_WY,
    AFM_TOKEN_WEIGHT,
    AFM_TOKEN_WEIGHTVECTOR,
    AFM_TOKEN_XHEIGHT,
    N_AFM_TOKENS,
    AFM_TOKEN_UNKNOWN

  } AFM_Token;

  static const char*  const afm_key_table[N_AFM_TOKENS] =
  {
    "Ascender",
    "AxisLabel",
    "AxisType",
    "B",
    "BlendAxisTypes",
    "BlendDesignMap",
    "BlendDesignPositions",
    "C",
    "CC",
    "CH",
    "CapHeight",
    "CharWidth",
    "CharacterSet",
    "Characters",
    "Descender",
    "EncodingScheme",
    "EndAxis",
    "EndCharMetrics",
    "EndComposites",
    "EndDirection",
    "EndFontMetrics",
    "EndKernData",
    "EndKernPairs",
    "EndTrackKern",
    "EscChar",
    "FamilyName",
    "FontBBox",
    "FontName",
    "FullName",
    "IsBaseFont",
    "IsCIDFont",
    "IsFixedPitch",
    "IsFixedV",
    "ItalicAngle",
    "KP",
    "KPH",
    "KPX",
    "KPY",
    "L",
    "MappingScheme",
    "MetricsSets",
    "N",
    "Notice",
    "PCC",
    "StartAxis",
    "StartCharMetrics",
    "StartComposites",
    "StartDirection",
    "StartFontMetrics",
    "StartKernData",
    "StartKernPairs",
    "StartKernPairs0",
    "StartKernPairs1",
    "StartTrackKern",
    "StdHW",
    "StdVW",
    "TrackKern",
    "UnderlinePosition",
    "UnderlineThickness",
    "VV",
    "VVector",
    "Version",
    "W",
    "W0",
    "W0X",
    "W0Y",
    "W1",
    "W1X",
    "W1Y",
    "WX",
    "WY",
    "Weight",
    "WeightVector",
    "XHeight"
  };

  /*
   * `afm_parser_read_vals' and `afm_parser_next_key' provide
   * high-level operations to an AFM_Stream.  The rest of the
   * parser functions should use them without accessing the
   * AFM_Stream directly.
   */

  FT_LOCAL_DEF( FT_Int )
  afm_parser_read_vals( AFM_Parser  parser,
                        AFM_Value   vals,
                        FT_Int      n )
  {
    AFM_Stream  stream = parser->stream;
    char*       str;
    FT_Int      i;

    if ( n > AFM_MAX_ARGUMENTS )
      return 0;

    for ( i = 0; i < n; i++ )
    {
      FT_Offset  len;
      AFM_Value  val = vals + i;

      if ( val->type == AFM_VALUE_TYPE_STRING )
        str = afm_stream_read_string( stream );
      else
        str = afm_stream_read_one( stream );

      if ( !str )
        break;

      len = AFM_STREAM_KEY_LEN( stream, str );

      switch ( val->type )
      {
      case AFM_VALUE_TYPE_STRING:
      case AFM_VALUE_TYPE_NAME:
        {
          FT_Memory  memory = parser->memory;
          FT_Error   error;

          if ( !FT_QALLOC( val->u.s, len + 1 ) )
          {
            ft_memcpy( val->u.s, str, len );
            val->u.s[len] = '\0';
          }
        }
        break;

      case AFM_VALUE_TYPE_FIXED:
        val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str,
                                    (FT_Byte*)str + len, 0 );
        break;

      case AFM_VALUE_TYPE_INTEGER:
        val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str,
                                  (FT_Byte*)str + len );
        break;

      case AFM_VALUE_TYPE_BOOL:
        val->u.b = FT_BOOL( len == 4                      &&
                            !ft_strncmp( str, "true", 4 ) );
        break;

      case AFM_VALUE_TYPE_INDEX:
        if ( parser->get_index )
          val->u.i = parser->get_index( str, len, parser->user_data );
        else
          val->u.i = 0;
        break;
      }
    }

    return i;
  }

  FT_LOCAL_DEF( char* )
  afm_parser_next_key( AFM_Parser  parser,
                       FT_Bool     line,
                       FT_Offset*  len )
  {
    AFM_Stream  stream = parser->stream;
    char*       key    = NULL;  /* make stupid compiler happy */

    if ( line )
    {
      while ( 1 )
      {
        /* skip current line */
        if ( !AFM_STATUS_EOL( stream ) )
          afm_stream_read_string( stream );

        stream->status = AFM_STREAM_STATUS_NORMAL;
        key = afm_stream_read_one( stream );

        /* skip empty line */
        if ( !key                      &&
             !AFM_STATUS_EOF( stream ) &&
             AFM_STATUS_EOL( stream )  )
          continue;

        break;
      }
    }
    else
    {
      while ( 1 )
      {
        /* skip current column */
        while ( !AFM_STATUS_EOC( stream ) )
          afm_stream_read_one( stream );

        stream->status = AFM_STREAM_STATUS_NORMAL;
        key = afm_stream_read_one( stream );

        /* skip empty column */
        if ( !key                      &&
             !AFM_STATUS_EOF( stream ) &&
             AFM_STATUS_EOC( stream )  )
          continue;

        break;
      }
    }

    if ( len )
      *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key )
                     : 0;

    return key;
  }

  static AFM_Token
  afm_tokenize( const char*  key,
                FT_Offset    len )
  {
    int  n;

    for ( n = 0; n < N_AFM_TOKENS; n++ )
    {
      if ( *( afm_key_table[n] ) == *key )
      {
        for ( ; n < N_AFM_TOKENS; n++ )
        {
          if ( *( afm_key_table[n] ) != *key )
            return AFM_TOKEN_UNKNOWN;

          if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
            return (AFM_Token) n;
        }
      }
    }

    return AFM_TOKEN_UNKNOWN;
  }

  FT_LOCAL_DEF( FT_Error )
  afm_parser_init( AFM_Parser  parser,
                   FT_Memory   memory,
                   FT_Byte*    base,
                   FT_Byte*    limit )
  {
    AFM_Stream  stream = NULL;
    FT_Error    error;

    if ( FT_NEW( stream ) )
      return error;

    stream->cursor = stream->base = base;
    stream->limit  = limit;

    /* don't skip the first line during the first call */
    stream->status = AFM_STREAM_STATUS_EOL;

    parser->memory    = memory;
    parser->stream    = stream;
    parser->FontInfo  = NULL;
    parser->get_index = NULL;

    return FT_Err_Ok;
  }

  FT_LOCAL( void )
  afm_parser_done( AFM_Parser  parser )
  {
    FT_Memory  memory = parser->memory;

    FT_FREE( parser->stream );
  }

  static FT_Error
  afm_parser_read_int( AFM_Parser  parser,
                       FT_Int*     aint )
  {
    AFM_ValueRec  val;

    val.type = AFM_VALUE_TYPE_INTEGER;

    if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
    {
      *aint = val.u.i;

      return FT_Err_Ok;
    }
    else
      return FT_THROW( Syntax_Error );
  }

  static FT_Error
  afm_parse_track_kern( AFM_Parser  parser )
  {
    AFM_FontInfo   fi = parser->FontInfo;
    AFM_TrackKern  tk;
    char*          key;
    FT_Offset      len;
    int            n = -1;
    FT_Int         tmp;

    if ( afm_parser_read_int( parser, &tmp ) )
        goto Fail;

    if ( tmp < 0 )
      goto Fail;

    fi->NumTrackKern = (FT_UInt)tmp;

    if ( fi->NumTrackKern )
    {
      FT_Memory  memory = parser->memory;
      FT_Error   error;

      if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
        return error;
    }

    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    {
      AFM_ValueRec  shared_vals[5];

      switch ( afm_tokenize( key, len ) )
      {
      case AFM_TOKEN_TRACKKERN:
        n++;

        if ( n >= (int)fi->NumTrackKern )
          goto Fail;

        tk = fi->TrackKerns + n;

        shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
        shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
        shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
        shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
        shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
        if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
          goto Fail;

        tk->degree     = shared_vals[0].u.i;
        tk->min_ptsize = shared_vals[1].u.f;
        tk->min_kern   = shared_vals[2].u.f;
        tk->max_ptsize = shared_vals[3].u.f;
        tk->max_kern   = shared_vals[4].u.f;

        break;

      case AFM_TOKEN_ENDTRACKKERN:
      case AFM_TOKEN_ENDKERNDATA:
      case AFM_TOKEN_ENDFONTMETRICS:
        fi->NumTrackKern = (FT_UInt)( n + 1 );
        return FT_Err_Ok;

      case AFM_TOKEN_UNKNOWN:
        break;

      default:
        goto Fail;
      }
    }

  Fail:
    return FT_THROW( Syntax_Error );
  }

#undef  KERN_INDEX
#define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )

  /* compare two kerning pairs */
  FT_CALLBACK_DEF( int )
  afm_compare_kern_pairs( const void*  a,
                          const void*  b )
  {
    AFM_KernPair  kp1 = (AFM_KernPair)a;
    AFM_KernPair  kp2 = (AFM_KernPair)b;

    FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
    FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );

    if ( index1 > index2 )
      return 1;
    else if ( index1 < index2 )
      return -1;
    else
      return 0;
  }

  static FT_Error
  afm_parse_kern_pairs( AFM_Parser  parser )
  {
    AFM_FontInfo  fi = parser->FontInfo;
    AFM_KernPair  kp;
    char*         key;
    FT_Offset     len;
    int           n = -1;
    FT_Int        tmp;

    if ( afm_parser_read_int( parser, &tmp ) )
      goto Fail;

    if ( tmp < 0 )
      goto Fail;

    fi->NumKernPair = (FT_UInt)tmp;

    if ( fi->NumKernPair )
    {
      FT_Memory  memory = parser->memory;
      FT_Error   error;

      if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
        return error;
    }

    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    {
      AFM_Token  token = afm_tokenize( key, len );

      switch ( token )
      {
      case AFM_TOKEN_KP:
      case AFM_TOKEN_KPX:
      case AFM_TOKEN_KPY:
        {
          FT_Int        r;
          AFM_ValueRec  shared_vals[4];

          n++;

          if ( n >= (int)fi->NumKernPair )
            goto Fail;

          kp = fi->KernPairs + n;

          shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
          shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
          shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
          shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
          r = afm_parser_read_vals( parser, shared_vals, 4 );
          if ( r < 3 )
            goto Fail;

          /* index values can't be negative */
          kp->index1 = shared_vals[0].u.u;
          kp->index2 = shared_vals[1].u.u;
          if ( token == AFM_TOKEN_KPY )
          {
            kp->x = 0;
            kp->y = shared_vals[2].u.i;
          }
          else
          {
            kp->x = shared_vals[2].u.i;
            kp->y = ( token == AFM_TOKEN_KP && r == 4 )
                      ? shared_vals[3].u.i : 0;
          }
        }
        break;

      case AFM_TOKEN_ENDKERNPAIRS:
      case AFM_TOKEN_ENDKERNDATA:
      case AFM_TOKEN_ENDFONTMETRICS:
        fi->NumKernPair = (FT_UInt)( n + 1 );
        ft_qsort( fi->KernPairs, fi->NumKernPair,
                  sizeof ( AFM_KernPairRec ),
                  afm_compare_kern_pairs );
        return FT_Err_Ok;

      case AFM_TOKEN_UNKNOWN:
        break;

      default:
        goto Fail;
      }
    }

  Fail:
    return FT_THROW( Syntax_Error );
  }

  static FT_Error
  afm_parse_kern_data( AFM_Parser  parser )
  {
    FT_Error   error;
    char*      key;
    FT_Offset  len;

    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    {
      switch ( afm_tokenize( key, len ) )
      {
      case AFM_TOKEN_STARTTRACKKERN:
        error = afm_parse_track_kern( parser );
        if ( error )
          return error;
        break;

      case AFM_TOKEN_STARTKERNPAIRS:
      case AFM_TOKEN_STARTKERNPAIRS0:
        error = afm_parse_kern_pairs( parser );
        if ( error )
          return error;
        break;

      case AFM_TOKEN_ENDKERNDATA:
      case AFM_TOKEN_ENDFONTMETRICS:
        return FT_Err_Ok;

      case AFM_TOKEN_UNKNOWN:
        break;

      default:
        goto Fail;
      }
    }

  Fail:
    return FT_THROW( Syntax_Error );
  }

  static FT_Error
  afm_parser_skip_section( AFM_Parser  parser,
                           FT_Int      n,
                           AFM_Token   end_section )
  {
    char*      key;
    FT_Offset  len;

    while ( n-- > 0 )
    {
      key = afm_parser_next_key( parser, 1, NULL );
      if ( !key )
        goto Fail;
    }

    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    {
      AFM_Token  token = afm_tokenize( key, len );

      if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
        return FT_Err_Ok;
    }

  Fail:
    return FT_THROW( Syntax_Error );
  }

  FT_LOCAL_DEF( FT_Error )
  afm_parser_parse( AFM_Parser  parser )
  {
    FT_Memory     memory = parser->memory;
    AFM_FontInfo  fi     = parser->FontInfo;
    FT_Error      error  = FT_ERR( Syntax_Error );
    char*         key;
    FT_Offset     len;
    FT_Int        metrics_sets = 0;

    if ( !fi )
      return FT_THROW( Invalid_Argument );

    key = afm_parser_next_key( parser, 1, &len );
    if ( !key || len != 16                              ||
         ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
      return FT_THROW( Unknown_File_Format );

    while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
    {
      AFM_ValueRec  shared_vals[4];

      switch ( afm_tokenize( key, len ) )
      {
      case AFM_TOKEN_METRICSSETS:
        if ( afm_parser_read_int( parser, &metrics_sets ) )
          goto Fail;

        if ( metrics_sets != 0 && metrics_sets != 2 )
        {
          error = FT_THROW( Unimplemented_Feature );

          goto Fail;
        }
        break;

      case AFM_TOKEN_ISCIDFONT:
        shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
          goto Fail;

        fi->IsCIDFont = shared_vals[0].u.b;
        break;

      case AFM_TOKEN_FONTBBOX:
        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
        shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
        shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
        shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
        if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
          goto Fail;

        fi->FontBBox.xMin = shared_vals[0].u.f;
        fi->FontBBox.yMin = shared_vals[1].u.f;
        fi->FontBBox.xMax = shared_vals[2].u.f;
        fi->FontBBox.yMax = shared_vals[3].u.f;
        break;

      case AFM_TOKEN_ASCENDER:
        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
          goto Fail;

        fi->Ascender = shared_vals[0].u.f;
        break;

      case AFM_TOKEN_DESCENDER:
        shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
        if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
          goto Fail;

        fi->Descender = shared_vals[0].u.f;
        break;

      case AFM_TOKEN_STARTCHARMETRICS:
        {
          FT_Int  n = 0;

          if ( afm_parser_read_int( parser, &n ) )
            goto Fail;

          error = afm_parser_skip_section( parser, n,
                                           AFM_TOKEN_ENDCHARMETRICS );
          if ( error )
            return error;
        }
        break;

      case AFM_TOKEN_STARTKERNDATA:
        error = afm_parse_kern_data( parser );
        if ( error )
          goto Fail;
        /* we only support kern data, so ... */
        /* fall through                      */

      case AFM_TOKEN_ENDFONTMETRICS:
        return FT_Err_Ok;

      default:
        break;
      }
    }

  Fail:
    FT_FREE( fi->TrackKerns );
    fi->NumTrackKern = 0;

    FT_FREE( fi->KernPairs );
    fi->NumKernPair = 0;

    fi->IsCIDFont = 0;

    return error;
  }

#else /* T1_CONFIG_OPTION_NO_AFM */

  /* ANSI C doesn't like empty source files */
  typedef int  _afm_parse_dummy;

#endif /* T1_CONFIG_OPTION_NO_AFM */

/* END */