tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ftmm.c (18518B)


      1 /****************************************************************************
      2 *
      3 * ftmm.c
      4 *
      5 *   Multiple Master font support (body).
      6 *
      7 * Copyright (C) 1996-2025 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    if ( !num_coords && !FT_IS_VARIATION( face ) )
    296      return FT_Err_Ok;  /* nothing to be done */
    297 
    298    error = ft_face_get_mm_service( face, &service_mm );
    299    if ( !error )
    300    {
    301      error = FT_ERR( Invalid_Argument );
    302      if ( service_mm->set_var_design )
    303        error = service_mm->set_var_design( face, num_coords, coords );
    304 
    305      if ( !error || error == -1 || error == -2 )
    306      {
    307        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    308 
    309 
    310        if ( error != -1 )
    311        {
    312          if ( error == -2 ) /* -2 means is_variable. */
    313          {
    314            face->face_flags |= FT_FACE_FLAG_VARIATION;
    315            error             = FT_Err_Ok;
    316          }
    317          else
    318            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
    319        }
    320 
    321        if ( service_mm->construct_ps_name )
    322        {
    323          if ( error == -1 )
    324          {
    325            /* The PS name of a named instance and a non-named instance */
    326            /* usually differs, even if the axis values are identical.  */
    327            if ( is_variation_old != FT_IS_VARIATION( face ) )
    328              service_mm->construct_ps_name( face );
    329          }
    330          else
    331            service_mm->construct_ps_name( face );
    332        }
    333      }
    334 
    335      /* internal error code -1 means `no change'; we can exit immediately */
    336      if ( error == -1 )
    337        return FT_Err_Ok;
    338    }
    339 
    340    if ( !error )
    341    {
    342      (void)ft_face_get_mvar_service( face, &service_mvar );
    343 
    344      if ( service_mvar && service_mvar->metrics_adjust )
    345        service_mvar->metrics_adjust( face );
    346    }
    347 
    348    /* enforce recomputation of auto-hinting data */
    349    if ( !error && face->autohint.finalizer )
    350    {
    351      face->autohint.finalizer( face->autohint.data );
    352      face->autohint.data = NULL;
    353    }
    354 
    355    return error;
    356  }
    357 
    358 
    359  /* documentation is in ftmm.h */
    360 
    361  FT_EXPORT_DEF( FT_Error )
    362  FT_Get_Var_Design_Coordinates( FT_Face    face,
    363                                 FT_UInt    num_coords,
    364                                 FT_Fixed*  coords )
    365  {
    366    FT_Error                 error;
    367    FT_Service_MultiMasters  service;
    368 
    369 
    370    /* check of `face' delayed to `ft_face_get_mm_service' */
    371 
    372    if ( !coords )
    373      return FT_THROW( Invalid_Argument );
    374 
    375    error = ft_face_get_mm_service( face, &service );
    376    if ( !error )
    377    {
    378      error = FT_ERR( Invalid_Argument );
    379      if ( service->get_var_design )
    380        error = service->get_var_design( face, num_coords, coords );
    381    }
    382 
    383    return error;
    384  }
    385 
    386 
    387  /* documentation is in ftmm.h */
    388 
    389  FT_EXPORT_DEF( FT_Error )
    390  FT_Set_MM_Blend_Coordinates( FT_Face    face,
    391                               FT_UInt    num_coords,
    392                               FT_Fixed*  coords )
    393  {
    394    FT_Error                      error;
    395    FT_Service_MultiMasters       service_mm   = NULL;
    396    FT_Service_MetricsVariations  service_mvar = NULL;
    397 
    398 
    399    /* check of `face' delayed to `ft_face_get_mm_service' */
    400 
    401    if ( num_coords && !coords )
    402      return FT_THROW( Invalid_Argument );
    403 
    404    error = ft_face_get_mm_service( face, &service_mm );
    405    if ( !error )
    406    {
    407      error = FT_ERR( Invalid_Argument );
    408      if ( service_mm->set_mm_blend )
    409        error = service_mm->set_mm_blend( face, num_coords, coords );
    410 
    411      if ( !error || error == -1 )
    412      {
    413        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    414 
    415 
    416        if ( num_coords )
    417          face->face_flags |= FT_FACE_FLAG_VARIATION;
    418        else
    419          face->face_flags &= ~FT_FACE_FLAG_VARIATION;
    420 
    421        if ( service_mm->construct_ps_name )
    422        {
    423          if ( error == -1 )
    424          {
    425            /* The PS name of a named instance and a non-named instance */
    426            /* usually differs, even if the axis values are identical.  */
    427            if ( is_variation_old != FT_IS_VARIATION( face ) )
    428              service_mm->construct_ps_name( face );
    429          }
    430          else
    431            service_mm->construct_ps_name( face );
    432        }
    433      }
    434 
    435      /* internal error code -1 means `no change'; we can exit immediately */
    436      if ( error == -1 )
    437        return FT_Err_Ok;
    438    }
    439 
    440    if ( !error )
    441    {
    442      (void)ft_face_get_mvar_service( face, &service_mvar );
    443 
    444      if ( service_mvar && service_mvar->metrics_adjust )
    445        service_mvar->metrics_adjust( face );
    446    }
    447 
    448    /* enforce recomputation of auto-hinting data */
    449    if ( !error && face->autohint.finalizer )
    450    {
    451      face->autohint.finalizer( face->autohint.data );
    452      face->autohint.data = NULL;
    453    }
    454 
    455    return error;
    456  }
    457 
    458 
    459  /* documentation is in ftmm.h */
    460 
    461  /* This is exactly the same as the previous function.  It exists for */
    462  /* orthogonality.                                                    */
    463 
    464  FT_EXPORT_DEF( FT_Error )
    465  FT_Set_Var_Blend_Coordinates( FT_Face    face,
    466                                FT_UInt    num_coords,
    467                                FT_Fixed*  coords )
    468  {
    469    FT_Error                      error;
    470    FT_Service_MultiMasters       service_mm   = NULL;
    471    FT_Service_MetricsVariations  service_mvar = NULL;
    472 
    473 
    474    /* check of `face' delayed to `ft_face_get_mm_service' */
    475 
    476    if ( num_coords && !coords )
    477      return FT_THROW( Invalid_Argument );
    478 
    479    error = ft_face_get_mm_service( face, &service_mm );
    480    if ( !error )
    481    {
    482      error = FT_ERR( Invalid_Argument );
    483      if ( service_mm->set_mm_blend )
    484        error = service_mm->set_mm_blend( face, num_coords, coords );
    485 
    486      if ( !error || error == -1 || error == -2 )
    487      {
    488        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    489 
    490 
    491        if ( error != -1 )
    492        {
    493          if ( error == -2 ) /* -2 means is_variable. */
    494          {
    495            face->face_flags |= FT_FACE_FLAG_VARIATION;
    496            error             = FT_Err_Ok;
    497          }
    498          else
    499            face->face_flags &= ~FT_FACE_FLAG_VARIATION;
    500        }
    501 
    502        if ( service_mm->construct_ps_name )
    503        {
    504          if ( error == -1 )
    505          {
    506            /* The PS name of a named instance and a non-named instance */
    507            /* usually differs, even if the axis values are identical.  */
    508            if ( is_variation_old != FT_IS_VARIATION( face ) )
    509              service_mm->construct_ps_name( face );
    510          }
    511          else
    512            service_mm->construct_ps_name( face );
    513        }
    514      }
    515 
    516      /* internal error code -1 means `no change'; we can exit immediately */
    517      if ( error == -1 )
    518        return FT_Err_Ok;
    519    }
    520 
    521    if ( !error )
    522    {
    523      (void)ft_face_get_mvar_service( face, &service_mvar );
    524 
    525      if ( service_mvar && service_mvar->metrics_adjust )
    526        service_mvar->metrics_adjust( face );
    527    }
    528 
    529    /* enforce recomputation of auto-hinting data */
    530    if ( !error && face->autohint.finalizer )
    531    {
    532      face->autohint.finalizer( face->autohint.data );
    533      face->autohint.data = NULL;
    534    }
    535 
    536    return error;
    537  }
    538 
    539 
    540  /* documentation is in ftmm.h */
    541 
    542  FT_EXPORT_DEF( FT_Error )
    543  FT_Get_MM_Blend_Coordinates( FT_Face    face,
    544                               FT_UInt    num_coords,
    545                               FT_Fixed*  coords )
    546  {
    547    FT_Error                 error;
    548    FT_Service_MultiMasters  service;
    549 
    550 
    551    /* check of `face' delayed to `ft_face_get_mm_service' */
    552 
    553    if ( !coords )
    554      return FT_THROW( Invalid_Argument );
    555 
    556    error = ft_face_get_mm_service( face, &service );
    557    if ( !error )
    558    {
    559      error = FT_ERR( Invalid_Argument );
    560      if ( service->get_mm_blend )
    561        error = service->get_mm_blend( face, num_coords, coords );
    562    }
    563 
    564    return error;
    565  }
    566 
    567 
    568  /* documentation is in ftmm.h */
    569 
    570  /* This is exactly the same as the previous function.  It exists for */
    571  /* orthogonality.                                                    */
    572 
    573  FT_EXPORT_DEF( FT_Error )
    574  FT_Get_Var_Blend_Coordinates( FT_Face    face,
    575                                FT_UInt    num_coords,
    576                                FT_Fixed*  coords )
    577  {
    578    FT_Error                 error;
    579    FT_Service_MultiMasters  service;
    580 
    581 
    582    /* check of `face' delayed to `ft_face_get_mm_service' */
    583 
    584    if ( !coords )
    585      return FT_THROW( Invalid_Argument );
    586 
    587    error = ft_face_get_mm_service( face, &service );
    588    if ( !error )
    589    {
    590      error = FT_ERR( Invalid_Argument );
    591      if ( service->get_mm_blend )
    592        error = service->get_mm_blend( face, num_coords, coords );
    593    }
    594 
    595    return error;
    596  }
    597 
    598 
    599  /* documentation is in ftmm.h */
    600 
    601  FT_EXPORT_DEF( FT_Error )
    602  FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
    603                         FT_UInt     axis_index,
    604                         FT_UInt*    flags )
    605  {
    606    FT_UShort*  axis_flags;
    607 
    608 
    609    if ( !master || !flags )
    610      return FT_THROW( Invalid_Argument );
    611 
    612    if ( axis_index >= master->num_axis )
    613      return FT_THROW( Invalid_Argument );
    614 
    615    /* the axis flags array immediately follows the data of `master' */
    616    axis_flags = (FT_UShort*)&( master[1] );
    617    *flags     = axis_flags[axis_index];
    618 
    619    return FT_Err_Ok;
    620  }
    621 
    622 
    623  /* documentation is in ftmm.h */
    624 
    625  FT_EXPORT_DEF( FT_Error )
    626  FT_Set_Named_Instance( FT_Face  face,
    627                         FT_UInt  instance_index )
    628  {
    629    FT_Error  error;
    630 
    631    FT_Service_MultiMasters       service_mm   = NULL;
    632    FT_Service_MetricsVariations  service_mvar = NULL;
    633 
    634 
    635    /* check of `face' delayed to `ft_face_get_mm_service' */
    636 
    637    error = ft_face_get_mm_service( face, &service_mm );
    638    if ( !error )
    639    {
    640      error = FT_ERR( Invalid_Argument );
    641      if ( service_mm->set_named_instance )
    642        error = service_mm->set_named_instance( face, instance_index );
    643 
    644      if ( !error || error == -1 )
    645      {
    646        FT_Bool  is_variation_old = FT_IS_VARIATION( face );
    647 
    648 
    649        face->face_flags &= ~FT_FACE_FLAG_VARIATION;
    650        face->face_index  = ( instance_index << 16 )        |
    651                            ( face->face_index & 0xFFFFL );
    652 
    653        if ( service_mm->construct_ps_name )
    654        {
    655          if ( error == -1 )
    656          {
    657            /* The PS name of a named instance and a non-named instance */
    658            /* usually differs, even if the axis values are identical.  */
    659            if ( is_variation_old != FT_IS_VARIATION( face ) )
    660              service_mm->construct_ps_name( face );
    661          }
    662          else
    663            service_mm->construct_ps_name( face );
    664        }
    665      }
    666 
    667      /* internal error code -1 means `no change'; we can exit immediately */
    668      if ( error == -1 )
    669        return FT_Err_Ok;
    670    }
    671 
    672    if ( !error )
    673    {
    674      (void)ft_face_get_mvar_service( face, &service_mvar );
    675 
    676      if ( service_mvar && service_mvar->metrics_adjust )
    677        service_mvar->metrics_adjust( face );
    678    }
    679 
    680    /* enforce recomputation of auto-hinting data */
    681    if ( !error && face->autohint.finalizer )
    682    {
    683      face->autohint.finalizer( face->autohint.data );
    684      face->autohint.data = NULL;
    685    }
    686 
    687    return error;
    688  }
    689 
    690 
    691  /* documentation is in ftmm.h */
    692 
    693  FT_EXPORT_DEF( FT_Error )
    694  FT_Get_Default_Named_Instance( FT_Face   face,
    695                                 FT_UInt  *instance_index )
    696  {
    697    FT_Error  error;
    698 
    699    FT_Service_MultiMasters  service_mm = NULL;
    700 
    701 
    702    /* check of `face' delayed to `ft_face_get_mm_service' */
    703 
    704    error = ft_face_get_mm_service( face, &service_mm );
    705    if ( !error )
    706    {
    707      /* no error if `get_default_named_instance` is not available */
    708      if ( service_mm->get_default_named_instance )
    709        error = service_mm->get_default_named_instance( face,
    710                                                        instance_index );
    711      else
    712        error = FT_Err_Ok;
    713    }
    714 
    715    return error;
    716  }
    717 
    718 
    719 /* END */