Edit

kc3-lang/freetype/src/cff/cf2ft.c

Branch :

  • Show log

    Commit

  • Author : Werner Lemberg
    Date : 2017-03-12 20:46:56
    Hash : 5eb0fd5e
    Message : [truetype] Store and use design coordinates also. * include/freetype/internal/services/svmm.h (FT_Get_Var_Blend_Func): Add `normalizedcoords' argument. * src/truetype/ttgxvar.h (GX_BlendRec): Add `coords' field to store the design coordinates of the current instance. Updated. * src/truetype/ttgxvar.c (TT_Set_MM_Blend): Move functionality to... (tt_set_mm_blend): ... New function. Convert data in `normalizedcoords' array to `coords' array on demand. (TT_Set_Var_Design): Store argument data in `coords' array. (TT_Get_Var_Design): Get data from `coords' array. (tt_get_var_blend): Updated. (tt_done_blend): Updated. * src/cff/cffload.c, src/cff/cffload.h (cff_get_var_blend): Updated. * src/cff/cf2ft.c (cf2_getNormalizedVector): Updated. * src/cff/cffobjs.c (cff_face_init): Updated.

  • src/cff/cf2ft.c
  • /***************************************************************************/
    /*                                                                         */
    /*  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"
    
    
    #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 = ( decoder->builder.glyph->x_scale + 32 ) / 64;
          *y_scale = ( 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;
    
          /* 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 )
      {
        FT_ASSERT( decoder && decoder->builder.face );
        FT_ASSERT( vec && len );
    
        return cff_get_var_blend( decoder->builder.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 = cff_get_glyph_data( 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 );
    
        cff_free_glyph_data( 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 */