Edit

kc3-lang/freetype/src/type1/t1gload.c

Branch :

  • Show log

    Commit

  • Author : Alexei Podtelezhnikov
    Date : 2025-01-03 21:26:10
    Hash : 5245fd69
    Message : Delay FT_GLYPH_FORMAT_OUTLINE assignmets. This assignmets used to be done prematurely before errors were checked and outlines were actually loaded. Delaying the assignment provides certain protection against careless usage of malformed input that should now remain FT_GLYPH_FORMAT_NONE. * src/cff/cffgload.c (cff_slot_load): Ditto. * src/cid/cidgload.c (cid_slot_load_glyph): Ditto. * src/pfr/pfrobjs.c (pfr_slot_load): Ditto. * src/truetype/ttgload.c (TT_Load_Glyph): Ditto. * src/type1/t1gload.c (T1_Load_Glyph): Ditto.

  • src/type1/t1gload.c
  • /****************************************************************************
     *
     * t1gload.c
     *
     *   Type 1 Glyph Loader (body).
     *
     * Copyright (C) 1996-2024 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 "t1gload.h"
    #include <freetype/internal/ftcalc.h>
    #include <freetype/internal/ftdebug.h>
    #include <freetype/internal/ftstream.h>
    #include <freetype/ftoutln.h>
    #include <freetype/internal/psaux.h>
    #include <freetype/internal/cfftypes.h>
    #include <freetype/ftdriver.h>
    
    #include "t1errors.h"
    
    
      /**************************************************************************
       *
       * The macro FT_COMPONENT is used in trace mode.  It is an implicit
       * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
       * messages during execution.
       */
    #undef  FT_COMPONENT
    #define FT_COMPONENT  t1gload
    
    
      static FT_Error
      T1_Parse_Glyph_And_Get_Char_String( T1_Decoder  decoder,
                                          FT_UInt     glyph_index,
                                          FT_Data*    char_string,
                                          FT_Bool*    force_scaling )
      {
        T1_Face   face  = (T1_Face)decoder->builder.face;
        T1_Font   type1 = &face->type1;
        FT_Error  error = FT_Err_Ok;
    
        PSAux_Service           psaux         = (PSAux_Service)face->psaux;
        const T1_Decoder_Funcs  decoder_funcs = psaux->t1_decoder_funcs;
        PS_Decoder              psdecoder;
    
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
        FT_Incremental_InterfaceRec *inc =
                          face->root.internal->incremental_interface;
    #endif
    
    #ifdef T1_CONFIG_OPTION_OLD_ENGINE
        PS_Driver  driver = (PS_Driver)FT_FACE_DRIVER( face );
    #endif
    
    
        decoder->font_matrix = type1->font_matrix;
        decoder->font_offset = type1->font_offset;
    
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
    
        /* For incremental fonts get the character data using the */
        /* callback function.                                     */
        if ( inc )
          error = inc->funcs->get_glyph_data( inc->object,
                                              glyph_index, char_string );
        else
    
    #endif /* FT_CONFIG_OPTION_INCREMENTAL */
    
        /* For ordinary fonts get the character data stored in the face record. */
        {
          char_string->pointer = type1->charstrings[glyph_index];
          char_string->length  = type1->charstrings_len[glyph_index];
        }
    
        if ( !error )
        {
          /* choose which renderer to use */
    #ifdef T1_CONFIG_OPTION_OLD_ENGINE
          if ( driver->hinting_engine == FT_HINTING_FREETYPE ||
               decoder->builder.metrics_only                 )
            error = decoder_funcs->parse_charstrings_old(
                      decoder,
                      (FT_Byte*)char_string->pointer,
                      (FT_UInt)char_string->length );
    #else
          if ( decoder->builder.metrics_only )
            error = decoder_funcs->parse_metrics(
                      decoder,
                      (FT_Byte*)char_string->pointer,
                      (FT_UInt)char_string->length );
    #endif
          else
          {
            CFF_SubFontRec  subfont;
    
    
            psaux->ps_decoder_init( &psdecoder, decoder, TRUE );
    
            psaux->t1_make_subfont( FT_FACE( face ),
                                    &face->type1.private_dict, &subfont );
            psdecoder.current_subfont = &subfont;
    
            error = decoder_funcs->parse_charstrings(
                      &psdecoder,
                      (FT_Byte*)char_string->pointer,
                      (FT_ULong)char_string->length );
    
            /* Adobe's engine uses 16.16 numbers everywhere;              */
            /* as a consequence, glyphs larger than 2000ppem get rejected */
            if ( FT_ERR_EQ( error, Glyph_Too_Big ) )
            {
              /* this time, we retry unhinted and scale up the glyph later on */
              /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */
              /* 0x400 for both `x_scale' and `y_scale' in this case)         */
              ((T1_GlyphSlot)decoder->builder.glyph)->hint = FALSE;
    
              *force_scaling = TRUE;
    
              error = decoder_funcs->parse_charstrings(
                        &psdecoder,
                        (FT_Byte*)char_string->pointer,
                        (FT_ULong)char_string->length );
            }
          }
        }
    
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
    
        /* Incremental fonts can optionally override the metrics. */
        if ( !error && inc && inc->funcs->get_glyph_metrics )
        {
          FT_Incremental_MetricsRec  metrics;
    
    
          metrics.bearing_x = FIXED_TO_INT( decoder->builder.left_bearing.x );
          metrics.bearing_y = 0;
          metrics.advance   = FIXED_TO_INT( decoder->builder.advance.x );
          metrics.advance_v = FIXED_TO_INT( decoder->builder.advance.y );
    
          error = inc->funcs->get_glyph_metrics( inc->object,
                                                 glyph_index, FALSE, &metrics );
    
          decoder->builder.left_bearing.x = INT_TO_FIXED( metrics.bearing_x );
          decoder->builder.advance.x      = INT_TO_FIXED( metrics.advance );
          decoder->builder.advance.y      = INT_TO_FIXED( metrics.advance_v );
        }
    
    #endif /* FT_CONFIG_OPTION_INCREMENTAL */
    
        return error;
      }
    
    
      FT_CALLBACK_DEF( FT_Error )
      T1_Parse_Glyph( T1_Decoder  decoder,
                      FT_UInt     glyph_index )
      {
        FT_Data   glyph_data;
        FT_Bool   force_scaling = FALSE;
        FT_Error  error         = T1_Parse_Glyph_And_Get_Char_String(
                                    decoder, glyph_index, &glyph_data,
                                    &force_scaling );
    
    
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
    
        if ( !error )
        {
          T1_Face  face = (T1_Face)decoder->builder.face;
    
    
          if ( face->root.internal->incremental_interface )
            face->root.internal->incremental_interface->funcs->free_glyph_data(
              face->root.internal->incremental_interface->object,
              &glyph_data );
        }
    
    #endif /* FT_CONFIG_OPTION_INCREMENTAL */
    
        return error;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*************************************************************************/
      /**********                                                      *********/
      /**********            COMPUTE THE MAXIMUM ADVANCE WIDTH         *********/
      /**********                                                      *********/
      /**********    The following code is in charge of computing      *********/
      /**********    the maximum advance width of the font.  It        *********/
      /**********    quickly processes each glyph charstring to        *********/
      /**********    extract the value from either a `sbw' or `seac'   *********/
      /**********    operator.                                         *********/
      /**********                                                      *********/
      /*************************************************************************/
      /*************************************************************************/
      /*************************************************************************/
    
    
      FT_LOCAL_DEF( FT_Error )
      T1_Compute_Max_Advance( T1_Face  face,
                              FT_Pos*  max_advance )
      {
        FT_Error       error;
        T1_DecoderRec  decoder;
        FT_Int         glyph_index;
        T1_Font        type1 = &face->type1;
        PSAux_Service  psaux = (PSAux_Service)face->psaux;
    
    
        FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) );
    
        *max_advance = 0;
    
        /* initialize load decoder */
        error = psaux->t1_decoder_funcs->init( &decoder,
                                               (FT_Face)face,
                                               0, /* size       */
                                               0, /* glyph slot */
                                               (FT_Byte**)type1->glyph_names,
                                               face->blend,
                                               0,
                                               FT_RENDER_MODE_NORMAL,
                                               T1_Parse_Glyph );
        if ( error )
          return error;
    
        decoder.builder.metrics_only = 1;
        decoder.builder.load_points  = 0;
    
        decoder.num_subrs     = type1->num_subrs;
        decoder.subrs         = type1->subrs;
        decoder.subrs_len     = type1->subrs_len;
        decoder.subrs_hash    = type1->subrs_hash;
    
        decoder.buildchar     = face->buildchar;
        decoder.len_buildchar = face->len_buildchar;
    
        *max_advance = 0;
    
        FT_TRACE6(( "T1_Compute_Max_Advance:\n" ));
    
        /* for each glyph, parse the glyph charstring and extract */
        /* the advance width                                      */
        for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
        {
          /* now get load the unscaled outline */
          (void)T1_Parse_Glyph( &decoder, (FT_UInt)glyph_index );
          if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance )
            *max_advance = decoder.builder.advance.x;
    
          /* ignore the error if one occurred - skip to next glyph */
        }
    
        FT_TRACE6(( "T1_Compute_Max_Advance: max advance: %f\n",
                    (double)*max_advance / 65536 ));
    
        psaux->t1_decoder_funcs->done( &decoder );
    
        return FT_Err_Ok;
      }
    
    
      FT_LOCAL_DEF( FT_Error )
      T1_Get_Advances( FT_Face    t1face,        /* T1_Face */
                       FT_UInt    first,
                       FT_UInt    count,
                       FT_Int32   load_flags,
                       FT_Fixed*  advances )
      {
        T1_Face        face  = (T1_Face)t1face;
        T1_DecoderRec  decoder;
        T1_Font        type1 = &face->type1;
        PSAux_Service  psaux = (PSAux_Service)face->psaux;
        FT_UInt        nn;
        FT_Error       error;
    
    
        FT_TRACE5(( "T1_Get_Advances:\n" ));
    
        if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
        {
          for ( nn = 0; nn < count; nn++ )
          {
            advances[nn] = 0;
    
            FT_TRACE5(( "  idx %d: advance height 0 font units\n",
                        first + nn ));
          }
    
          return FT_Err_Ok;
        }
    
        error = psaux->t1_decoder_funcs->init( &decoder,
                                               (FT_Face)face,
                                               0, /* size       */
                                               0, /* glyph slot */
                                               (FT_Byte**)type1->glyph_names,
                                               face->blend,
                                               0,
                                               FT_RENDER_MODE_NORMAL,
                                               T1_Parse_Glyph );
        if ( error )
          return error;
    
        decoder.builder.metrics_only = 1;
        decoder.builder.load_points  = 0;
    
        decoder.num_subrs  = type1->num_subrs;
        decoder.subrs      = type1->subrs;
        decoder.subrs_len  = type1->subrs_len;
        decoder.subrs_hash = type1->subrs_hash;
    
        decoder.buildchar     = face->buildchar;
        decoder.len_buildchar = face->len_buildchar;
    
        for ( nn = 0; nn < count; nn++ )
        {
          error = T1_Parse_Glyph( &decoder, first + nn );
          if ( !error )
            advances[nn] = FIXED_TO_INT( decoder.builder.advance.x );
          else
            advances[nn] = 0;
    
          FT_TRACE5(( "  idx %d: advance width %ld font unit%s\n",
                      first + nn,
                      advances[nn],
                      advances[nn] == 1 ? "" : "s" ));
        }
    
        return FT_Err_Ok;
      }
    
    
      FT_LOCAL_DEF( FT_Error )
      T1_Load_Glyph( FT_GlyphSlot  t1glyph,          /* T1_GlyphSlot */
                     FT_Size       t1size,           /* T1_Size      */
                     FT_UInt       glyph_index,
                     FT_Int32      load_flags )
      {
        T1_GlyphSlot            glyph = (T1_GlyphSlot)t1glyph;
        FT_Error                error;
        T1_DecoderRec           decoder;
        T1_Face                 face = (T1_Face)t1glyph->face;
        FT_Bool                 hinting;
        FT_Bool                 scaled;
        FT_Bool                 force_scaling = FALSE;
        T1_Font                 type1         = &face->type1;
        PSAux_Service           psaux         = (PSAux_Service)face->psaux;
        const T1_Decoder_Funcs  decoder_funcs = psaux->t1_decoder_funcs;
    
        FT_Matrix               font_matrix;
        FT_Vector               font_offset;
        FT_Data                 glyph_data;
        FT_Bool                 must_finish_decoder = FALSE;
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
        FT_Bool                 glyph_data_loaded = 0;
    #endif
    
    
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
        if ( glyph_index >= (FT_UInt)face->root.num_glyphs &&
             !face->root.internal->incremental_interface   )
    #else
        if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
    #endif /* FT_CONFIG_OPTION_INCREMENTAL */
        {
          error = FT_THROW( Invalid_Argument );
          goto Exit;
        }
    
        FT_TRACE1(( "T1_Load_Glyph: glyph index %d\n", glyph_index ));
    
        FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) );
    
        if ( load_flags & FT_LOAD_NO_RECURSE )
          load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
    
        if ( t1size )
        {
          glyph->x_scale = t1size->metrics.x_scale;
          glyph->y_scale = t1size->metrics.y_scale;
        }
        else
        {
          glyph->x_scale = 0x10000L;
          glyph->y_scale = 0x10000L;
        }
    
        hinting = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE   ) &&
                           !( load_flags & FT_LOAD_NO_HINTING ) );
        scaled  = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE   ) );
    
        glyph->hint     = hinting;
        glyph->scaled   = scaled;
    
        error = decoder_funcs->init( &decoder,
                                     t1glyph->face,
                                     t1size,
                                     t1glyph,
                                     (FT_Byte**)type1->glyph_names,
                                     face->blend,
                                     hinting,
                                     FT_LOAD_TARGET_MODE( load_flags ),
                                     T1_Parse_Glyph );
        if ( error )
          goto Exit;
    
        must_finish_decoder = TRUE;
    
        decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE );
    
        decoder.num_subrs     = type1->num_subrs;
        decoder.subrs         = type1->subrs;
        decoder.subrs_len     = type1->subrs_len;
        decoder.subrs_hash    = type1->subrs_hash;
    
        decoder.buildchar     = face->buildchar;
        decoder.len_buildchar = face->len_buildchar;
    
        /* now load the unscaled outline */
        error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index,
                                                    &glyph_data,
                                                    &force_scaling );
        if ( error )
          goto Exit;
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
        glyph_data_loaded = 1;
    #endif
    
        hinting     = glyph->hint;
        font_matrix = decoder.font_matrix;
        font_offset = decoder.font_offset;
    
        /* save new glyph tables */
        decoder_funcs->done( &decoder );
    
        must_finish_decoder = FALSE;
    
        if ( !error )
        {
          /* now, set the metrics -- this is rather simple, as   */
          /* the left side bearing is the xMin, and the top side */
          /* bearing the yMax; for composite glyphs, return only */
          /* left side bearing and advance width                 */
          if ( load_flags & FT_LOAD_NO_RECURSE )
          {
            FT_Slot_Internal  internal = t1glyph->internal;
    
    
            t1glyph->metrics.horiBearingX =
              FIXED_TO_INT( decoder.builder.left_bearing.x );
            t1glyph->metrics.horiAdvance  =
              FIXED_TO_INT( decoder.builder.advance.x );
    
            internal->glyph_matrix      = font_matrix;
            internal->glyph_delta       = font_offset;
            internal->glyph_transformed = 1;
          }
          else
          {
            FT_BBox            cbox;
            FT_Glyph_Metrics*  metrics = &t1glyph->metrics;
    
    
            t1glyph->format = FT_GLYPH_FORMAT_OUTLINE;
    
            t1glyph->outline.flags &= FT_OUTLINE_OWNER;
            t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL;
            if ( t1size && t1size->metrics.y_ppem < 24 )
              t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
    
            /* copy the _unscaled_ advance width */
            metrics->horiAdvance =
              FIXED_TO_INT( decoder.builder.advance.x );
            t1glyph->linearHoriAdvance =
              FIXED_TO_INT( decoder.builder.advance.x );
            t1glyph->internal->glyph_transformed = 0;
    
            if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
            {
              /* make up vertical ones */
              metrics->vertAdvance = ( face->type1.font_bbox.yMax -
                                       face->type1.font_bbox.yMin ) >> 16;
              t1glyph->linearVertAdvance = metrics->vertAdvance;
            }
            else
            {
              metrics->vertAdvance =
                FIXED_TO_INT( decoder.builder.advance.y );
              t1glyph->linearVertAdvance =
                FIXED_TO_INT( decoder.builder.advance.y );
            }
    
    #if 1
            /* apply the font matrix, if any */
            if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L ||
                 font_matrix.xy != 0        || font_matrix.yx != 0        )
            {
              FT_Outline_Transform( &t1glyph->outline, &font_matrix );
    
              metrics->horiAdvance = FT_MulFix( metrics->horiAdvance,
                                                font_matrix.xx );
              metrics->vertAdvance = FT_MulFix( metrics->vertAdvance,
                                                font_matrix.yy );
            }
    
            if ( font_offset.x || font_offset.y )
            {
              FT_Outline_Translate( &t1glyph->outline,
                                    font_offset.x,
                                    font_offset.y );
    
              metrics->horiAdvance += font_offset.x;
              metrics->vertAdvance += font_offset.y;
            }
    #endif
    
            if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
            {
              /* scale the outline and the metrics */
              FT_Int       n;
              FT_Outline*  cur = decoder.builder.base;
              FT_Vector*   vec = cur->points;
              FT_Fixed     x_scale = glyph->x_scale;
              FT_Fixed     y_scale = glyph->y_scale;
    
    
              /* First of all, scale the points, if we are not hinting */
              if ( !hinting || !decoder.builder.hints_funcs )
                for ( n = cur->n_points; n > 0; n--, vec++ )
                {
                  vec->x = FT_MulFix( vec->x, x_scale );
                  vec->y = FT_MulFix( vec->y, y_scale );
                }
    
              /* Then scale the metrics */
              metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
              metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
            }
    
            /* compute the other metrics */
            FT_Outline_Get_CBox( &t1glyph->outline, &cbox );
    
            metrics->width  = cbox.xMax - cbox.xMin;
            metrics->height = cbox.yMax - cbox.yMin;
    
            metrics->horiBearingX = cbox.xMin;
            metrics->horiBearingY = cbox.yMax;
    
            if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
            {
              /* make up vertical ones */
              ft_synthesize_vertical_metrics( metrics,
                                              metrics->vertAdvance );
            }
          }
    
          /* Set control data to the glyph charstrings.  Note that this is */
          /* _not_ zero-terminated.                                        */
          t1glyph->control_data = (FT_Byte*)glyph_data.pointer;
          t1glyph->control_len  = glyph_data.length;
        }
    
    
      Exit:
    
    #ifdef FT_CONFIG_OPTION_INCREMENTAL
        if ( glyph_data_loaded && face->root.internal->incremental_interface )
        {
          face->root.internal->incremental_interface->funcs->free_glyph_data(
            face->root.internal->incremental_interface->object,
            &glyph_data );
    
          /* Set the control data to null - it is no longer available if   */
          /* loaded incrementally.                                         */
          t1glyph->control_data = NULL;
          t1glyph->control_len  = 0;
        }
    #endif
    
        if ( must_finish_decoder )
          decoder_funcs->done( &decoder );
    
        return error;
      }
    
    
    /* END */