(root)/
freetype-2.13.2/
src/
base/
ftmm.c
       1  /****************************************************************************
       2   *
       3   * ftmm.c
       4   *
       5   *   Multiple Master font support (body).
       6   *
       7   * Copyright (C) 1996-2023 by
       8   * David Turner, Robert Wilhelm, and Werner Lemberg.
       9   *
      10   * This file is part of the FreeType project, and may only be used,
      11   * modified, and distributed under the terms of the FreeType project
      12   * license, LICENSE.TXT.  By continuing to use, modify, or distribute
      13   * this file you indicate that you have read the license and
      14   * understand and accept it fully.
      15   *
      16   */
      17  
      18  
      19  #include <freetype/internal/ftdebug.h>
      20  
      21  #include <freetype/ftmm.h>
      22  #include <freetype/internal/ftobjs.h>
      23  #include <freetype/internal/services/svmm.h>
      24  #include <freetype/internal/services/svmetric.h>
      25  
      26  
      27    /**************************************************************************
      28     *
      29     * The macro FT_COMPONENT is used in trace mode.  It is an implicit
      30     * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
      31     * messages during execution.
      32     */
      33  #undef  FT_COMPONENT
      34  #define FT_COMPONENT  mm
      35  
      36  
      37    static FT_Error
      38    ft_face_get_mm_service( FT_Face                   face,
      39                            FT_Service_MultiMasters  *aservice )
      40    {
      41      FT_Error  error;
      42  
      43  
      44      *aservice = NULL;
      45  
      46      if ( !face )
      47        return FT_THROW( Invalid_Face_Handle );
      48  
      49      error = FT_ERR( Invalid_Argument );
      50  
      51      if ( FT_HAS_MULTIPLE_MASTERS( face ) )
      52      {
      53        FT_FACE_LOOKUP_SERVICE( face,
      54                                *aservice,
      55                                MULTI_MASTERS );
      56  
      57        if ( *aservice )
      58          error = FT_Err_Ok;
      59      }
      60  
      61      return error;
      62    }
      63  
      64  
      65    static FT_Error
      66    ft_face_get_mvar_service( FT_Face                        face,
      67                              FT_Service_MetricsVariations  *aservice )
      68    {
      69      FT_Error  error;
      70  
      71  
      72      *aservice = NULL;
      73  
      74      if ( !face )
      75        return FT_THROW( Invalid_Face_Handle );
      76  
      77      error = FT_ERR( Invalid_Argument );
      78  
      79      if ( FT_HAS_MULTIPLE_MASTERS( face ) )
      80      {
      81        FT_FACE_LOOKUP_SERVICE( face,
      82                                *aservice,
      83                                METRICS_VARIATIONS );
      84  
      85        if ( *aservice )
      86          error = FT_Err_Ok;
      87      }
      88  
      89      return error;
      90    }
      91  
      92  
      93    /* documentation is in ftmm.h */
      94  
      95    FT_EXPORT_DEF( FT_Error )
      96    FT_Get_Multi_Master( FT_Face           face,
      97                         FT_Multi_Master  *amaster )
      98    {
      99      FT_Error                 error;
     100      FT_Service_MultiMasters  service;
     101  
     102  
     103      /* check of `face' delayed to `ft_face_get_mm_service' */
     104  
     105      if ( !amaster )
     106        return FT_THROW( Invalid_Argument );
     107  
     108      error = ft_face_get_mm_service( face, &service );
     109      if ( !error )
     110      {
     111        error = FT_ERR( Invalid_Argument );
     112        if ( service->get_mm )
     113          error = service->get_mm( face, amaster );
     114      }
     115  
     116      return error;
     117    }
     118  
     119  
     120    /* documentation is in ftmm.h */
     121  
     122    FT_EXPORT_DEF( FT_Error )
     123    FT_Get_MM_Var( FT_Face      face,
     124                   FT_MM_Var*  *amaster )
     125    {
     126      FT_Error                 error;
     127      FT_Service_MultiMasters  service;
     128  
     129  
     130      /* check of `face' delayed to `ft_face_get_mm_service' */
     131  
     132      if ( !amaster )
     133        return FT_THROW( Invalid_Argument );
     134  
     135      error = ft_face_get_mm_service( face, &service );
     136      if ( !error )
     137      {
     138        error = FT_ERR( Invalid_Argument );
     139        if ( service->get_mm_var )
     140          error = service->get_mm_var( face, amaster );
     141      }
     142  
     143      return error;
     144    }
     145  
     146  
     147    /* documentation is in ftmm.h */
     148  
     149    FT_EXPORT_DEF( FT_Error )
     150    FT_Done_MM_Var( FT_Library  library,
     151                    FT_MM_Var*  amaster )
     152    {
     153      FT_Memory  memory;
     154  
     155  
     156      if ( !library )
     157        return FT_THROW( Invalid_Library_Handle );
     158  
     159      memory = library->memory;
     160      FT_FREE( amaster );
     161  
     162      return FT_Err_Ok;
     163    }
     164  
     165  
     166    /* documentation is in ftmm.h */
     167  
     168    FT_EXPORT_DEF( FT_Error )
     169    FT_Set_MM_Design_Coordinates( FT_Face   face,
     170                                  FT_UInt   num_coords,
     171                                  FT_Long*  coords )
     172    {
     173      FT_Error                 error;
     174      FT_Service_MultiMasters  service;
     175  
     176  
     177      /* check of `face' delayed to `ft_face_get_mm_service' */
     178  
     179      if ( num_coords && !coords )
     180        return FT_THROW( Invalid_Argument );
     181  
     182      error = ft_face_get_mm_service( face, &service );
     183      if ( !error )
     184      {
     185        error = FT_ERR( Invalid_Argument );
     186        if ( service->set_mm_design )
     187          error = service->set_mm_design( face, num_coords, coords );
     188  
     189        if ( !error )
     190        {
     191          if ( num_coords )
     192            face->face_flags |= FT_FACE_FLAG_VARIATION;
     193          else
     194            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
     195        }
     196      }
     197  
     198      /* enforce recomputation of auto-hinting data */
     199      if ( !error && face->autohint.finalizer )
     200      {
     201        face->autohint.finalizer( face->autohint.data );
     202        face->autohint.data = NULL;
     203      }
     204  
     205      return error;
     206    }
     207  
     208  
     209    /* documentation is in ftmm.h */
     210  
     211    FT_EXPORT_DEF( FT_Error )
     212    FT_Set_MM_WeightVector( FT_Face    face,
     213                            FT_UInt    len,
     214                            FT_Fixed*  weightvector )
     215    {
     216      FT_Error                 error;
     217      FT_Service_MultiMasters  service;
     218  
     219  
     220      /* check of `face' delayed to `ft_face_get_mm_service' */
     221  
     222      if ( len && !weightvector )
     223        return FT_THROW( Invalid_Argument );
     224  
     225      error = ft_face_get_mm_service( face, &service );
     226      if ( !error )
     227      {
     228        error = FT_ERR( Invalid_Argument );
     229        if ( service->set_mm_weightvector )
     230          error = service->set_mm_weightvector( face, len, weightvector );
     231  
     232        if ( !error )
     233        {
     234          if ( len )
     235            face->face_flags |= FT_FACE_FLAG_VARIATION;
     236          else
     237            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
     238        }
     239      }
     240  
     241      /* enforce recomputation of auto-hinting data */
     242      if ( !error && face->autohint.finalizer )
     243      {
     244        face->autohint.finalizer( face->autohint.data );
     245        face->autohint.data = NULL;
     246      }
     247  
     248      return error;
     249    }
     250  
     251  
     252    FT_EXPORT_DEF( FT_Error )
     253    FT_Get_MM_WeightVector( FT_Face    face,
     254                            FT_UInt*   len,
     255                            FT_Fixed*  weightvector )
     256    {
     257      FT_Error                 error;
     258      FT_Service_MultiMasters  service;
     259  
     260  
     261      /* check of `face' delayed to `ft_face_get_mm_service' */
     262  
     263      if ( len && !weightvector )
     264        return FT_THROW( Invalid_Argument );
     265  
     266      error = ft_face_get_mm_service( face, &service );
     267      if ( !error )
     268      {
     269        error = FT_ERR( Invalid_Argument );
     270        if ( service->get_mm_weightvector )
     271          error = service->get_mm_weightvector( face, len, weightvector );
     272      }
     273  
     274      return error;
     275    }
     276  
     277  
     278    /* documentation is in ftmm.h */
     279  
     280    FT_EXPORT_DEF( FT_Error )
     281    FT_Set_Var_Design_Coordinates( FT_Face    face,
     282                                   FT_UInt    num_coords,
     283                                   FT_Fixed*  coords )
     284    {
     285      FT_Error                      error;
     286      FT_Service_MultiMasters       service_mm   = NULL;
     287      FT_Service_MetricsVariations  service_mvar = NULL;
     288  
     289  
     290      /* check of `face' delayed to `ft_face_get_mm_service' */
     291  
     292      if ( num_coords && !coords )
     293        return FT_THROW( Invalid_Argument );
     294  
     295      error = ft_face_get_mm_service( face, &service_mm );
     296      if ( !error )
     297      {
     298        error = FT_ERR( Invalid_Argument );
     299        if ( service_mm->set_var_design )
     300          error = service_mm->set_var_design( face, num_coords, coords );
     301  
     302        if ( !error || error == -1 )
     303        {
     304          FT_Bool  is_variation_old = FT_IS_VARIATION( face );
     305  
     306  
     307          if ( num_coords )
     308            face->face_flags |= FT_FACE_FLAG_VARIATION;
     309          else
     310            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
     311  
     312          if ( service_mm->construct_ps_name )
     313          {
     314            if ( error == -1 )
     315            {
     316              /* The PS name of a named instance and a non-named instance */
     317              /* usually differs, even if the axis values are identical.  */
     318              if ( is_variation_old != FT_IS_VARIATION( face ) )
     319                service_mm->construct_ps_name( face );
     320            }
     321            else
     322              service_mm->construct_ps_name( face );
     323          }
     324        }
     325  
     326        /* internal error code -1 means `no change'; we can exit immediately */
     327        if ( error == -1 )
     328          return FT_Err_Ok;
     329      }
     330  
     331      if ( !error )
     332      {
     333        (void)ft_face_get_mvar_service( face, &service_mvar );
     334  
     335        if ( service_mvar && service_mvar->metrics_adjust )
     336          service_mvar->metrics_adjust( face );
     337      }
     338  
     339      /* enforce recomputation of auto-hinting data */
     340      if ( !error && face->autohint.finalizer )
     341      {
     342        face->autohint.finalizer( face->autohint.data );
     343        face->autohint.data = NULL;
     344      }
     345  
     346      return error;
     347    }
     348  
     349  
     350    /* documentation is in ftmm.h */
     351  
     352    FT_EXPORT_DEF( FT_Error )
     353    FT_Get_Var_Design_Coordinates( FT_Face    face,
     354                                   FT_UInt    num_coords,
     355                                   FT_Fixed*  coords )
     356    {
     357      FT_Error                 error;
     358      FT_Service_MultiMasters  service;
     359  
     360  
     361      /* check of `face' delayed to `ft_face_get_mm_service' */
     362  
     363      if ( !coords )
     364        return FT_THROW( Invalid_Argument );
     365  
     366      error = ft_face_get_mm_service( face, &service );
     367      if ( !error )
     368      {
     369        error = FT_ERR( Invalid_Argument );
     370        if ( service->get_var_design )
     371          error = service->get_var_design( face, num_coords, coords );
     372      }
     373  
     374      return error;
     375    }
     376  
     377  
     378    /* documentation is in ftmm.h */
     379  
     380    FT_EXPORT_DEF( FT_Error )
     381    FT_Set_MM_Blend_Coordinates( FT_Face    face,
     382                                 FT_UInt    num_coords,
     383                                 FT_Fixed*  coords )
     384    {
     385      FT_Error                      error;
     386      FT_Service_MultiMasters       service_mm   = NULL;
     387      FT_Service_MetricsVariations  service_mvar = NULL;
     388  
     389  
     390      /* check of `face' delayed to `ft_face_get_mm_service' */
     391  
     392      if ( num_coords && !coords )
     393        return FT_THROW( Invalid_Argument );
     394  
     395      error = ft_face_get_mm_service( face, &service_mm );
     396      if ( !error )
     397      {
     398        error = FT_ERR( Invalid_Argument );
     399        if ( service_mm->set_mm_blend )
     400          error = service_mm->set_mm_blend( face, num_coords, coords );
     401  
     402        if ( !error || error == -1 )
     403        {
     404          FT_Bool  is_variation_old = FT_IS_VARIATION( face );
     405  
     406  
     407          if ( num_coords )
     408            face->face_flags |= FT_FACE_FLAG_VARIATION;
     409          else
     410            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
     411  
     412          if ( service_mm->construct_ps_name )
     413          {
     414            if ( error == -1 )
     415            {
     416              /* The PS name of a named instance and a non-named instance */
     417              /* usually differs, even if the axis values are identical.  */
     418              if ( is_variation_old != FT_IS_VARIATION( face ) )
     419                service_mm->construct_ps_name( face );
     420            }
     421            else
     422              service_mm->construct_ps_name( face );
     423          }
     424        }
     425  
     426        /* internal error code -1 means `no change'; we can exit immediately */
     427        if ( error == -1 )
     428          return FT_Err_Ok;
     429      }
     430  
     431      if ( !error )
     432      {
     433        (void)ft_face_get_mvar_service( face, &service_mvar );
     434  
     435        if ( service_mvar && service_mvar->metrics_adjust )
     436          service_mvar->metrics_adjust( face );
     437      }
     438  
     439      /* enforce recomputation of auto-hinting data */
     440      if ( !error && face->autohint.finalizer )
     441      {
     442        face->autohint.finalizer( face->autohint.data );
     443        face->autohint.data = NULL;
     444      }
     445  
     446      return error;
     447    }
     448  
     449  
     450    /* documentation is in ftmm.h */
     451  
     452    /* This is exactly the same as the previous function.  It exists for */
     453    /* orthogonality.                                                    */
     454  
     455    FT_EXPORT_DEF( FT_Error )
     456    FT_Set_Var_Blend_Coordinates( FT_Face    face,
     457                                  FT_UInt    num_coords,
     458                                  FT_Fixed*  coords )
     459    {
     460      FT_Error                      error;
     461      FT_Service_MultiMasters       service_mm   = NULL;
     462      FT_Service_MetricsVariations  service_mvar = NULL;
     463  
     464  
     465      /* check of `face' delayed to `ft_face_get_mm_service' */
     466  
     467      if ( num_coords && !coords )
     468        return FT_THROW( Invalid_Argument );
     469  
     470      error = ft_face_get_mm_service( face, &service_mm );
     471      if ( !error )
     472      {
     473        error = FT_ERR( Invalid_Argument );
     474        if ( service_mm->set_mm_blend )
     475          error = service_mm->set_mm_blend( face, num_coords, coords );
     476  
     477        if ( !error || error == -1 )
     478        {
     479          FT_Bool  is_variation_old = FT_IS_VARIATION( face );
     480  
     481  
     482          if ( num_coords )
     483            face->face_flags |= FT_FACE_FLAG_VARIATION;
     484          else
     485            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
     486  
     487          if ( service_mm->construct_ps_name )
     488          {
     489            if ( error == -1 )
     490            {
     491              /* The PS name of a named instance and a non-named instance */
     492              /* usually differs, even if the axis values are identical.  */
     493              if ( is_variation_old != FT_IS_VARIATION( face ) )
     494                service_mm->construct_ps_name( face );
     495            }
     496            else
     497              service_mm->construct_ps_name( face );
     498          }
     499        }
     500  
     501        /* internal error code -1 means `no change'; we can exit immediately */
     502        if ( error == -1 )
     503          return FT_Err_Ok;
     504      }
     505  
     506      if ( !error )
     507      {
     508        (void)ft_face_get_mvar_service( face, &service_mvar );
     509  
     510        if ( service_mvar && service_mvar->metrics_adjust )
     511          service_mvar->metrics_adjust( face );
     512      }
     513  
     514      /* enforce recomputation of auto-hinting data */
     515      if ( !error && face->autohint.finalizer )
     516      {
     517        face->autohint.finalizer( face->autohint.data );
     518        face->autohint.data = NULL;
     519      }
     520  
     521      return error;
     522    }
     523  
     524  
     525    /* documentation is in ftmm.h */
     526  
     527    FT_EXPORT_DEF( FT_Error )
     528    FT_Get_MM_Blend_Coordinates( FT_Face    face,
     529                                 FT_UInt    num_coords,
     530                                 FT_Fixed*  coords )
     531    {
     532      FT_Error                 error;
     533      FT_Service_MultiMasters  service;
     534  
     535  
     536      /* check of `face' delayed to `ft_face_get_mm_service' */
     537  
     538      if ( !coords )
     539        return FT_THROW( Invalid_Argument );
     540  
     541      error = ft_face_get_mm_service( face, &service );
     542      if ( !error )
     543      {
     544        error = FT_ERR( Invalid_Argument );
     545        if ( service->get_mm_blend )
     546          error = service->get_mm_blend( face, num_coords, coords );
     547      }
     548  
     549      return error;
     550    }
     551  
     552  
     553    /* documentation is in ftmm.h */
     554  
     555    /* This is exactly the same as the previous function.  It exists for */
     556    /* orthogonality.                                                    */
     557  
     558    FT_EXPORT_DEF( FT_Error )
     559    FT_Get_Var_Blend_Coordinates( FT_Face    face,
     560                                  FT_UInt    num_coords,
     561                                  FT_Fixed*  coords )
     562    {
     563      FT_Error                 error;
     564      FT_Service_MultiMasters  service;
     565  
     566  
     567      /* check of `face' delayed to `ft_face_get_mm_service' */
     568  
     569      if ( !coords )
     570        return FT_THROW( Invalid_Argument );
     571  
     572      error = ft_face_get_mm_service( face, &service );
     573      if ( !error )
     574      {
     575        error = FT_ERR( Invalid_Argument );
     576        if ( service->get_mm_blend )
     577          error = service->get_mm_blend( face, num_coords, coords );
     578      }
     579  
     580      return error;
     581    }
     582  
     583  
     584    /* documentation is in ftmm.h */
     585  
     586    FT_EXPORT_DEF( FT_Error )
     587    FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
     588                           FT_UInt     axis_index,
     589                           FT_UInt*    flags )
     590    {
     591      FT_UShort*  axis_flags;
     592  
     593  
     594      if ( !master || !flags )
     595        return FT_THROW( Invalid_Argument );
     596  
     597      if ( axis_index >= master->num_axis )
     598        return FT_THROW( Invalid_Argument );
     599  
     600      /* the axis flags array immediately follows the data of `master' */
     601      axis_flags = (FT_UShort*)&( master[1] );
     602      *flags     = axis_flags[axis_index];
     603  
     604      return FT_Err_Ok;
     605    }
     606  
     607  
     608    /* documentation is in ftmm.h */
     609  
     610    FT_EXPORT_DEF( FT_Error )
     611    FT_Set_Named_Instance( FT_Face  face,
     612                           FT_UInt  instance_index )
     613    {
     614      FT_Error  error;
     615  
     616      FT_Service_MultiMasters       service_mm   = NULL;
     617      FT_Service_MetricsVariations  service_mvar = NULL;
     618  
     619  
     620      /* check of `face' delayed to `ft_face_get_mm_service' */
     621  
     622      error = ft_face_get_mm_service( face, &service_mm );
     623      if ( !error )
     624      {
     625        error = FT_ERR( Invalid_Argument );
     626        if ( service_mm->set_named_instance )
     627          error = service_mm->set_named_instance( face, instance_index );
     628  
     629        if ( !error || error == -1 )
     630        {
     631          FT_Bool  is_variation_old = FT_IS_VARIATION( face );
     632  
     633  
     634          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
     635          face->face_index  = ( instance_index << 16 )        |
     636                              ( face->face_index & 0xFFFFL );
     637  
     638          if ( service_mm->construct_ps_name )
     639          {
     640            if ( error == -1 )
     641            {
     642              /* The PS name of a named instance and a non-named instance */
     643              /* usually differs, even if the axis values are identical.  */
     644              if ( is_variation_old != FT_IS_VARIATION( face ) )
     645                service_mm->construct_ps_name( face );
     646            }
     647            else
     648              service_mm->construct_ps_name( face );
     649          }
     650        }
     651  
     652        /* internal error code -1 means `no change'; we can exit immediately */
     653        if ( error == -1 )
     654          return FT_Err_Ok;
     655      }
     656  
     657      if ( !error )
     658      {
     659        (void)ft_face_get_mvar_service( face, &service_mvar );
     660  
     661        if ( service_mvar && service_mvar->metrics_adjust )
     662          service_mvar->metrics_adjust( face );
     663      }
     664  
     665      /* enforce recomputation of auto-hinting data */
     666      if ( !error && face->autohint.finalizer )
     667      {
     668        face->autohint.finalizer( face->autohint.data );
     669        face->autohint.data = NULL;
     670      }
     671  
     672      return error;
     673    }
     674  
     675  
     676    /* documentation is in ftmm.h */
     677  
     678    FT_EXPORT_DEF( FT_Error )
     679    FT_Get_Default_Named_Instance( FT_Face   face,
     680                                   FT_UInt  *instance_index )
     681    {
     682      FT_Error  error;
     683  
     684      FT_Service_MultiMasters  service_mm = NULL;
     685  
     686  
     687      /* check of `face' delayed to `ft_face_get_mm_service' */
     688  
     689      error = ft_face_get_mm_service( face, &service_mm );
     690      if ( !error )
     691      {
     692        /* no error if `get_default_named_instance` is not available */
     693        if ( service_mm->get_default_named_instance )
     694          error = service_mm->get_default_named_instance( face,
     695                                                          instance_index );
     696        else
     697          error = FT_Err_Ok;
     698      }
     699  
     700      return error;
     701    }
     702  
     703  
     704  /* END */