Edit

kc3-lang/freetype/src/base/ftmm.c

Branch :

  • Show log

    Commit

  • Author : Werner Lemberg
    Date : 2023-04-27 11:40:46
    Hash : c8a24209
    Message : [truetype] Fix PostScript name handling for variation fonts. A variation font's PostScript name of a named instance is usually different from the PostScript name of an unnamed instance. However, if a change between a named instance and an unnamed instance with exactly the same design axis values happened, it was possible that the PostScript name wasn't correctly updated. This commit reorganizes the code to handle this issue within the top-level API functions, using a new service to trigger recomputation of the PostScript name. * include/freetype/internal/services/svmm.h (FT_Construct_PS_Name_Func): New typedef. (FT_Service_MultiMasters): New field `construct_ps_name`. (FT_DEFINE_SERVICE_MULTIMASTERSREC): Updated. * src/base/ftmm.c (FT_Set_Var_Design_Coordinates, FT_Set_MM_Blend_Coordinates, FT_Set_Var_Blend_Coordinates): Call `mm->construct_ps_name` to handle `postscript_name`. (FT_Set_Named_Instance): Call `mm->construct_ps_name` to handle `postscript_name`. Use shortcut. * src/cff/cffdrivr.c (cff_construct_ps_name): New function. (cff_service_multi_masters): Updated. * src/truetype/ttgxvar.c (tt_set_mm_blend): Don't handle `postscript_name`. (TT_Set_MM_Blend): Simplify. (TT_Set_Named_Instance): Return -1 if axis values haven't changed. Don't set `face_index`. (tt_construct_ps_name): New function. * src/truetype/ttgxvar.h: Updated. * src/truetype/ttdriver.c (tt_service_gx_multi_masters): Updated. * src/type1/t1driver.c (t1_service_multi_masters): Updated. * src/type1/t1load.c (T1_Set_MM_Blend): Simplify.

  • src/base/ftmm.c
  • /****************************************************************************
     *
     * ftmm.c
     *
     *   Multiple Master font support (body).
     *
     * Copyright (C) 1996-2023 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 <freetype/internal/ftdebug.h>
    
    #include <freetype/ftmm.h>
    #include <freetype/internal/ftobjs.h>
    #include <freetype/internal/services/svmm.h>
    #include <freetype/internal/services/svmetric.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  mm
    
    
      static FT_Error
      ft_face_get_mm_service( FT_Face                   face,
                              FT_Service_MultiMasters  *aservice )
      {
        FT_Error  error;
    
    
        *aservice = NULL;
    
        if ( !face )
          return FT_THROW( Invalid_Face_Handle );
    
        error = FT_ERR( Invalid_Argument );
    
        if ( FT_HAS_MULTIPLE_MASTERS( face ) )
        {
          FT_FACE_LOOKUP_SERVICE( face,
                                  *aservice,
                                  MULTI_MASTERS );
    
          if ( *aservice )
            error = FT_Err_Ok;
        }
    
        return error;
      }
    
    
      static FT_Error
      ft_face_get_mvar_service( FT_Face                        face,
                                FT_Service_MetricsVariations  *aservice )
      {
        FT_Error  error;
    
    
        *aservice = NULL;
    
        if ( !face )
          return FT_THROW( Invalid_Face_Handle );
    
        error = FT_ERR( Invalid_Argument );
    
        if ( FT_HAS_MULTIPLE_MASTERS( face ) )
        {
          FT_FACE_LOOKUP_SERVICE( face,
                                  *aservice,
                                  METRICS_VARIATIONS );
    
          if ( *aservice )
            error = FT_Err_Ok;
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_Multi_Master( FT_Face           face,
                           FT_Multi_Master  *amaster )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( !amaster )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->get_mm )
            error = service->get_mm( face, amaster );
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_MM_Var( FT_Face      face,
                     FT_MM_Var*  *amaster )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( !amaster )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->get_mm_var )
            error = service->get_mm_var( face, amaster );
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Done_MM_Var( FT_Library  library,
                      FT_MM_Var*  amaster )
      {
        FT_Memory  memory;
    
    
        if ( !library )
          return FT_THROW( Invalid_Library_Handle );
    
        memory = library->memory;
        FT_FREE( amaster );
    
        return FT_Err_Ok;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Set_MM_Design_Coordinates( FT_Face   face,
                                    FT_UInt   num_coords,
                                    FT_Long*  coords )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( num_coords && !coords )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->set_mm_design )
            error = service->set_mm_design( face, num_coords, coords );
    
          if ( !error )
          {
            if ( num_coords )
              face->face_flags |= FT_FACE_FLAG_VARIATION;
            else
              face->face_flags &= ~FT_FACE_FLAG_VARIATION;
          }
        }
    
        /* enforce recomputation of auto-hinting data */
        if ( !error && face->autohint.finalizer )
        {
          face->autohint.finalizer( face->autohint.data );
          face->autohint.data = NULL;
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Set_MM_WeightVector( FT_Face    face,
                              FT_UInt    len,
                              FT_Fixed*  weightvector )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( len && !weightvector )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->set_mm_weightvector )
            error = service->set_mm_weightvector( face, len, weightvector );
    
          if ( !error )
          {
            if ( len )
              face->face_flags |= FT_FACE_FLAG_VARIATION;
            else
              face->face_flags &= ~FT_FACE_FLAG_VARIATION;
          }
        }
    
        /* enforce recomputation of auto-hinting data */
        if ( !error && face->autohint.finalizer )
        {
          face->autohint.finalizer( face->autohint.data );
          face->autohint.data = NULL;
        }
    
        return error;
      }
    
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_MM_WeightVector( FT_Face    face,
                              FT_UInt*   len,
                              FT_Fixed*  weightvector )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( len && !weightvector )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->get_mm_weightvector )
            error = service->get_mm_weightvector( face, len, weightvector );
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Set_Var_Design_Coordinates( FT_Face    face,
                                     FT_UInt    num_coords,
                                     FT_Fixed*  coords )
      {
        FT_Error                      error;
        FT_Service_MultiMasters       service_mm   = NULL;
        FT_Service_MetricsVariations  service_mvar = NULL;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( num_coords && !coords )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service_mm );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service_mm->set_var_design )
            error = service_mm->set_var_design( face, num_coords, coords );
    
          if ( !error || error == -1 )
          {
            FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    
    
            if ( num_coords )
              face->face_flags |= FT_FACE_FLAG_VARIATION;
            else
              face->face_flags &= ~FT_FACE_FLAG_VARIATION;
    
            if ( service_mm->construct_ps_name )
            {
              if ( error == -1 )
              {
                /* The PS name of a named instance and a non-named instance */
                /* usually differs, even if the axis values are identical.  */
                if ( is_variation_old != FT_IS_VARIATION( face ) )
                  service_mm->construct_ps_name( face );
              }
              else
                service_mm->construct_ps_name( face );
            }
          }
    
          /* internal error code -1 means `no change'; we can exit immediately */
          if ( error == -1 )
            return FT_Err_Ok;
        }
    
        if ( !error )
        {
          (void)ft_face_get_mvar_service( face, &service_mvar );
    
          if ( service_mvar && service_mvar->metrics_adjust )
            service_mvar->metrics_adjust( face );
        }
    
        /* enforce recomputation of auto-hinting data */
        if ( !error && face->autohint.finalizer )
        {
          face->autohint.finalizer( face->autohint.data );
          face->autohint.data = NULL;
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_Var_Design_Coordinates( FT_Face    face,
                                     FT_UInt    num_coords,
                                     FT_Fixed*  coords )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( !coords )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->get_var_design )
            error = service->get_var_design( face, num_coords, coords );
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Set_MM_Blend_Coordinates( FT_Face    face,
                                   FT_UInt    num_coords,
                                   FT_Fixed*  coords )
      {
        FT_Error                      error;
        FT_Service_MultiMasters       service_mm   = NULL;
        FT_Service_MetricsVariations  service_mvar = NULL;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( num_coords && !coords )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service_mm );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service_mm->set_mm_blend )
            error = service_mm->set_mm_blend( face, num_coords, coords );
    
          if ( !error || error == -1 )
          {
            FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    
    
            if ( num_coords )
              face->face_flags |= FT_FACE_FLAG_VARIATION;
            else
              face->face_flags &= ~FT_FACE_FLAG_VARIATION;
    
            if ( service_mm->construct_ps_name )
            {
              if ( error == -1 )
              {
                /* The PS name of a named instance and a non-named instance */
                /* usually differs, even if the axis values are identical.  */
                if ( is_variation_old != FT_IS_VARIATION( face ) )
                  service_mm->construct_ps_name( face );
              }
              else
                service_mm->construct_ps_name( face );
            }
          }
    
          /* internal error code -1 means `no change'; we can exit immediately */
          if ( error == -1 )
            return FT_Err_Ok;
        }
    
        if ( !error )
        {
          (void)ft_face_get_mvar_service( face, &service_mvar );
    
          if ( service_mvar && service_mvar->metrics_adjust )
            service_mvar->metrics_adjust( face );
        }
    
        /* enforce recomputation of auto-hinting data */
        if ( !error && face->autohint.finalizer )
        {
          face->autohint.finalizer( face->autohint.data );
          face->autohint.data = NULL;
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      /* This is exactly the same as the previous function.  It exists for */
      /* orthogonality.                                                    */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Set_Var_Blend_Coordinates( FT_Face    face,
                                    FT_UInt    num_coords,
                                    FT_Fixed*  coords )
      {
        FT_Error                      error;
        FT_Service_MultiMasters       service_mm   = NULL;
        FT_Service_MetricsVariations  service_mvar = NULL;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( num_coords && !coords )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service_mm );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service_mm->set_mm_blend )
            error = service_mm->set_mm_blend( face, num_coords, coords );
    
          if ( !error || error == -1 )
          {
            FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    
    
            if ( num_coords )
              face->face_flags |= FT_FACE_FLAG_VARIATION;
            else
              face->face_flags &= ~FT_FACE_FLAG_VARIATION;
    
            if ( service_mm->construct_ps_name )
            {
              if ( error == -1 )
              {
                /* The PS name of a named instance and a non-named instance */
                /* usually differs, even if the axis values are identical.  */
                if ( is_variation_old != FT_IS_VARIATION( face ) )
                  service_mm->construct_ps_name( face );
              }
              else
                service_mm->construct_ps_name( face );
            }
          }
    
          /* internal error code -1 means `no change'; we can exit immediately */
          if ( error == -1 )
            return FT_Err_Ok;
        }
    
        if ( !error )
        {
          (void)ft_face_get_mvar_service( face, &service_mvar );
    
          if ( service_mvar && service_mvar->metrics_adjust )
            service_mvar->metrics_adjust( face );
        }
    
        /* enforce recomputation of auto-hinting data */
        if ( !error && face->autohint.finalizer )
        {
          face->autohint.finalizer( face->autohint.data );
          face->autohint.data = NULL;
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_MM_Blend_Coordinates( FT_Face    face,
                                   FT_UInt    num_coords,
                                   FT_Fixed*  coords )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( !coords )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->get_mm_blend )
            error = service->get_mm_blend( face, num_coords, coords );
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      /* This is exactly the same as the previous function.  It exists for */
      /* orthogonality.                                                    */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_Var_Blend_Coordinates( FT_Face    face,
                                    FT_UInt    num_coords,
                                    FT_Fixed*  coords )
      {
        FT_Error                 error;
        FT_Service_MultiMasters  service;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        if ( !coords )
          return FT_THROW( Invalid_Argument );
    
        error = ft_face_get_mm_service( face, &service );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service->get_mm_blend )
            error = service->get_mm_blend( face, num_coords, coords );
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
                             FT_UInt     axis_index,
                             FT_UInt*    flags )
      {
        FT_UShort*  axis_flags;
    
    
        if ( !master || !flags )
          return FT_THROW( Invalid_Argument );
    
        if ( axis_index >= master->num_axis )
          return FT_THROW( Invalid_Argument );
    
        /* the axis flags array immediately follows the data of `master' */
        axis_flags = (FT_UShort*)&( master[1] );
        *flags     = axis_flags[axis_index];
    
        return FT_Err_Ok;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Set_Named_Instance( FT_Face  face,
                             FT_UInt  instance_index )
      {
        FT_Error  error;
    
        FT_Service_MultiMasters       service_mm   = NULL;
        FT_Service_MetricsVariations  service_mvar = NULL;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        error = ft_face_get_mm_service( face, &service_mm );
        if ( !error )
        {
          error = FT_ERR( Invalid_Argument );
          if ( service_mm->set_named_instance )
            error = service_mm->set_named_instance( face, instance_index );
    
          if ( !error || error == -1 )
          {
            FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    
    
            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
            face->face_index  = ( instance_index << 16 )        |
                                ( face->face_index & 0xFFFFL );
    
            if ( service_mm->construct_ps_name )
            {
              if ( error == -1 )
              {
                /* The PS name of a named instance and a non-named instance */
                /* usually differs, even if the axis values are identical.  */
                if ( is_variation_old != FT_IS_VARIATION( face ) )
                  service_mm->construct_ps_name( face );
              }
              else
                service_mm->construct_ps_name( face );
            }
          }
    
          /* internal error code -1 means `no change'; we can exit immediately */
          if ( error == -1 )
            return FT_Err_Ok;
        }
    
        if ( !error )
        {
          (void)ft_face_get_mvar_service( face, &service_mvar );
    
          if ( service_mvar && service_mvar->metrics_adjust )
            service_mvar->metrics_adjust( face );
        }
    
        /* enforce recomputation of auto-hinting data */
        if ( !error && face->autohint.finalizer )
        {
          face->autohint.finalizer( face->autohint.data );
          face->autohint.data = NULL;
        }
    
        return error;
      }
    
    
      /* documentation is in ftmm.h */
    
      FT_EXPORT_DEF( FT_Error )
      FT_Get_Default_Named_Instance( FT_Face   face,
                                     FT_UInt  *instance_index )
      {
        FT_Error  error;
    
        FT_Service_MultiMasters  service_mm = NULL;
    
    
        /* check of `face' delayed to `ft_face_get_mm_service' */
    
        error = ft_face_get_mm_service( face, &service_mm );
        if ( !error )
        {
          /* no error if `get_default_named_instance` is not available */
          if ( service_mm->get_default_named_instance )
            error = service_mm->get_default_named_instance( face,
                                                            instance_index );
          else
            error = FT_Err_Ok;
        }
    
        return error;
      }
    
    
    /* END */