(root)/
freetype-2.13.2/
src/
autofit/
afmodule.c
       1  /****************************************************************************
       2   *
       3   * afmodule.c
       4   *
       5   *   Auto-fitter module implementation (body).
       6   *
       7   * Copyright (C) 2003-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 "afglobal.h"
      20  #include "afmodule.h"
      21  #include "afloader.h"
      22  #include "aferrors.h"
      23  
      24  #ifdef FT_DEBUG_AUTOFIT
      25  
      26  #ifndef FT_MAKE_OPTION_SINGLE_OBJECT
      27  
      28  #ifdef __cplusplus
      29    extern "C" {
      30  #endif
      31    extern void
      32    af_glyph_hints_dump_segments( AF_GlyphHints  hints,
      33                                  FT_Bool        to_stdout );
      34    extern void
      35    af_glyph_hints_dump_points( AF_GlyphHints  hints,
      36                                FT_Bool        to_stdout );
      37    extern void
      38    af_glyph_hints_dump_edges( AF_GlyphHints  hints,
      39                               FT_Bool        to_stdout );
      40  #ifdef __cplusplus
      41    }
      42  #endif
      43  
      44  #endif
      45  
      46    int  af_debug_disable_horz_hints_;
      47    int  af_debug_disable_vert_hints_;
      48    int  af_debug_disable_blue_hints_;
      49  
      50    /* we use a global object instead of a local one for debugging */
      51    static AF_GlyphHintsRec  af_debug_hints_rec_[1];
      52  
      53    void*  af_debug_hints_ = af_debug_hints_rec_;
      54  #endif
      55  
      56  #include <freetype/internal/ftobjs.h>
      57  #include <freetype/internal/ftdebug.h>
      58  #include <freetype/ftdriver.h>
      59  #include <freetype/internal/services/svprop.h>
      60  
      61  
      62    /**************************************************************************
      63     *
      64     * The macro FT_COMPONENT is used in trace mode.  It is an implicit
      65     * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
      66     * messages during execution.
      67     */
      68  #undef  FT_COMPONENT
      69  #define FT_COMPONENT  afmodule
      70  
      71  
      72    static FT_Error
      73    af_property_get_face_globals( FT_Face          face,
      74                                  AF_FaceGlobals*  aglobals,
      75                                  AF_Module        module )
      76    {
      77      FT_Error        error = FT_Err_Ok;
      78      AF_FaceGlobals  globals;
      79  
      80  
      81      if ( !face )
      82        return FT_THROW( Invalid_Face_Handle );
      83  
      84      globals = (AF_FaceGlobals)face->autohint.data;
      85      if ( !globals )
      86      {
      87        /* trigger computation of the global style data */
      88        /* in case it hasn't been done yet              */
      89        error = af_face_globals_new( face, &globals, module );
      90        if ( !error )
      91        {
      92          face->autohint.data      = (FT_Pointer)globals;
      93          face->autohint.finalizer = af_face_globals_free;
      94        }
      95      }
      96  
      97      if ( !error )
      98        *aglobals = globals;
      99  
     100      return error;
     101    }
     102  
     103  
     104    static FT_Error
     105    af_property_set( FT_Module    ft_module,
     106                     const char*  property_name,
     107                     const void*  value,
     108                     FT_Bool      value_is_string )
     109    {
     110      FT_Error   error  = FT_Err_Ok;
     111      AF_Module  module = (AF_Module)ft_module;
     112  
     113  #ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
     114      FT_UNUSED( value_is_string );
     115  #endif
     116  
     117  
     118      if ( !ft_strcmp( property_name, "fallback-script" ) )
     119      {
     120        AF_Script*  fallback_script;
     121        FT_UInt     ss;
     122  
     123  
     124  #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
     125        if ( value_is_string )
     126          return FT_THROW( Invalid_Argument );
     127  #endif
     128  
     129        fallback_script = (AF_Script*)value;
     130  
     131        /* We translate the fallback script to a fallback style that uses */
     132        /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its  */
     133        /* coverage value.                                                */
     134        for ( ss = 0; af_style_classes[ss]; ss++ )
     135        {
     136          AF_StyleClass  style_class = af_style_classes[ss];
     137  
     138  
     139          if ( style_class->script   == *fallback_script    &&
     140               style_class->coverage == AF_COVERAGE_DEFAULT )
     141          {
     142            module->fallback_style = ss;
     143            break;
     144          }
     145        }
     146  
     147        if ( !af_style_classes[ss] )
     148        {
     149          FT_TRACE2(( "af_property_set: Invalid value %d for property `%s'\n",
     150                      *fallback_script, property_name ));
     151          return FT_THROW( Invalid_Argument );
     152        }
     153  
     154        return error;
     155      }
     156      else if ( !ft_strcmp( property_name, "default-script" ) )
     157      {
     158        AF_Script*  default_script;
     159  
     160  
     161  #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
     162        if ( value_is_string )
     163          return FT_THROW( Invalid_Argument );
     164  #endif
     165  
     166        default_script = (AF_Script*)value;
     167  
     168        module->default_script = *default_script;
     169  
     170        return error;
     171      }
     172      else if ( !ft_strcmp( property_name, "increase-x-height" ) )
     173      {
     174        FT_Prop_IncreaseXHeight*  prop;
     175        AF_FaceGlobals            globals;
     176  
     177  
     178  #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
     179        if ( value_is_string )
     180          return FT_THROW( Invalid_Argument );
     181  #endif
     182  
     183        prop = (FT_Prop_IncreaseXHeight*)value;
     184  
     185        error = af_property_get_face_globals( prop->face, &globals, module );
     186        if ( !error )
     187          globals->increase_x_height = prop->limit;
     188  
     189        return error;
     190      }
     191      else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
     192      {
     193        FT_Int*  darken_params;
     194        FT_Int   x1, y1, x2, y2, x3, y3, x4, y4;
     195  
     196  #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
     197        FT_Int   dp[8];
     198  
     199  
     200        if ( value_is_string )
     201        {
     202          const char*  s = (const char*)value;
     203          char*        ep;
     204          int          i;
     205  
     206  
     207          /* eight comma-separated numbers */
     208          for ( i = 0; i < 7; i++ )
     209          {
     210            dp[i] = (FT_Int)ft_strtol( s, &ep, 10 );
     211            if ( *ep != ',' || s == ep )
     212              return FT_THROW( Invalid_Argument );
     213  
     214            s = ep + 1;
     215          }
     216  
     217          dp[7] = (FT_Int)ft_strtol( s, &ep, 10 );
     218          if ( !( *ep == '\0' || *ep == ' ' ) || s == ep )
     219            return FT_THROW( Invalid_Argument );
     220  
     221          darken_params = dp;
     222        }
     223        else
     224  #endif
     225          darken_params = (FT_Int*)value;
     226  
     227        x1 = darken_params[0];
     228        y1 = darken_params[1];
     229        x2 = darken_params[2];
     230        y2 = darken_params[3];
     231        x3 = darken_params[4];
     232        y3 = darken_params[5];
     233        x4 = darken_params[6];
     234        y4 = darken_params[7];
     235  
     236        if ( x1 < 0   || x2 < 0   || x3 < 0   || x4 < 0   ||
     237             y1 < 0   || y2 < 0   || y3 < 0   || y4 < 0   ||
     238             x1 > x2  || x2 > x3  || x3 > x4              ||
     239             y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 )
     240          return FT_THROW( Invalid_Argument );
     241  
     242        module->darken_params[0] = x1;
     243        module->darken_params[1] = y1;
     244        module->darken_params[2] = x2;
     245        module->darken_params[3] = y2;
     246        module->darken_params[4] = x3;
     247        module->darken_params[5] = y3;
     248        module->darken_params[6] = x4;
     249        module->darken_params[7] = y4;
     250  
     251        return error;
     252      }
     253      else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
     254      {
     255  #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
     256        if ( value_is_string )
     257        {
     258          const char*  s   = (const char*)value;
     259          long         nsd = ft_strtol( s, NULL, 10 );
     260  
     261  
     262          if ( !nsd )
     263            module->no_stem_darkening = FALSE;
     264          else
     265            module->no_stem_darkening = TRUE;
     266        }
     267        else
     268  #endif
     269        {
     270          FT_Bool*  no_stem_darkening = (FT_Bool*)value;
     271  
     272  
     273          module->no_stem_darkening = *no_stem_darkening;
     274        }
     275  
     276        return error;
     277      }
     278  
     279      FT_TRACE2(( "af_property_set: missing property `%s'\n",
     280                  property_name ));
     281      return FT_THROW( Missing_Property );
     282    }
     283  
     284  
     285    static FT_Error
     286    af_property_get( FT_Module    ft_module,
     287                     const char*  property_name,
     288                     void*        value )
     289    {
     290      FT_Error   error          = FT_Err_Ok;
     291      AF_Module  module         = (AF_Module)ft_module;
     292  
     293  
     294      if ( !ft_strcmp( property_name, "glyph-to-script-map" ) )
     295      {
     296        FT_Prop_GlyphToScriptMap*  prop = (FT_Prop_GlyphToScriptMap*)value;
     297        AF_FaceGlobals             globals;
     298  
     299  
     300        error = af_property_get_face_globals( prop->face, &globals, module );
     301        if ( !error )
     302          prop->map = globals->glyph_styles;
     303  
     304        return error;
     305      }
     306      else if ( !ft_strcmp( property_name, "fallback-script" ) )
     307      {
     308        AF_Script*  val = (AF_Script*)value;
     309  
     310        AF_StyleClass  style_class = af_style_classes[module->fallback_style];
     311  
     312  
     313        *val = style_class->script;
     314  
     315        return error;
     316      }
     317      else if ( !ft_strcmp( property_name, "default-script" ) )
     318      {
     319        AF_Script*  val = (AF_Script*)value;
     320  
     321  
     322        *val = module->default_script;
     323  
     324        return error;
     325      }
     326      else if ( !ft_strcmp( property_name, "increase-x-height" ) )
     327      {
     328        FT_Prop_IncreaseXHeight*  prop = (FT_Prop_IncreaseXHeight*)value;
     329        AF_FaceGlobals            globals;
     330  
     331  
     332        error = af_property_get_face_globals( prop->face, &globals, module );
     333        if ( !error )
     334          prop->limit = globals->increase_x_height;
     335  
     336        return error;
     337      }
     338      else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
     339      {
     340        FT_Int*  darken_params = module->darken_params;
     341        FT_Int*  val           = (FT_Int*)value;
     342  
     343  
     344        val[0] = darken_params[0];
     345        val[1] = darken_params[1];
     346        val[2] = darken_params[2];
     347        val[3] = darken_params[3];
     348        val[4] = darken_params[4];
     349        val[5] = darken_params[5];
     350        val[6] = darken_params[6];
     351        val[7] = darken_params[7];
     352  
     353        return error;
     354      }
     355      else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
     356      {
     357        FT_Bool   no_stem_darkening = module->no_stem_darkening;
     358        FT_Bool*  val               = (FT_Bool*)value;
     359  
     360  
     361        *val = no_stem_darkening;
     362  
     363        return error;
     364      }
     365  
     366      FT_TRACE2(( "af_property_get: missing property `%s'\n",
     367                  property_name ));
     368      return FT_THROW( Missing_Property );
     369    }
     370  
     371  
     372    FT_DEFINE_SERVICE_PROPERTIESREC(
     373      af_service_properties,
     374  
     375      af_property_set,  /* FT_Properties_SetFunc set_property */
     376      af_property_get   /* FT_Properties_GetFunc get_property */
     377    )
     378  
     379  
     380    FT_DEFINE_SERVICEDESCREC1(
     381      af_services,
     382  
     383      FT_SERVICE_ID_PROPERTIES, &af_service_properties )
     384  
     385  
     386    FT_CALLBACK_DEF( FT_Module_Interface )
     387    af_get_interface( FT_Module    module,
     388                      const char*  module_interface )
     389    {
     390      FT_UNUSED( module );
     391  
     392      return ft_service_list_lookup( af_services, module_interface );
     393    }
     394  
     395  
     396    FT_CALLBACK_DEF( FT_Error )
     397    af_autofitter_init( FT_Module  ft_module )      /* AF_Module */
     398    {
     399      AF_Module  module = (AF_Module)ft_module;
     400  
     401  
     402      module->fallback_style    = AF_STYLE_FALLBACK;
     403      module->default_script    = AF_SCRIPT_DEFAULT;
     404      module->no_stem_darkening = TRUE;
     405  
     406      module->darken_params[0]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
     407      module->darken_params[1]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
     408      module->darken_params[2]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2;
     409      module->darken_params[3]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2;
     410      module->darken_params[4]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3;
     411      module->darken_params[5]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3;
     412      module->darken_params[6]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
     413      module->darken_params[7]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
     414  
     415      return FT_Err_Ok;
     416    }
     417  
     418  
     419    FT_CALLBACK_DEF( void )
     420    af_autofitter_done( FT_Module  ft_module )      /* AF_Module */
     421    {
     422      FT_UNUSED( ft_module );
     423  
     424  #ifdef FT_DEBUG_AUTOFIT
     425      if ( af_debug_hints_rec_->memory )
     426        af_glyph_hints_done( af_debug_hints_rec_ );
     427  #endif
     428    }
     429  
     430  
     431    FT_CALLBACK_DEF( FT_Error )
     432    af_autofitter_load_glyph( FT_AutoHinter  module_,
     433                              FT_GlyphSlot   slot,
     434                              FT_Size        size,
     435                              FT_UInt        glyph_index,
     436                              FT_Int32       load_flags )
     437    {
     438      AF_Module  module = (AF_Module)module_;
     439  
     440      FT_Error   error  = FT_Err_Ok;
     441      FT_Memory  memory = module->root.library->memory;
     442  
     443  #ifdef FT_DEBUG_AUTOFIT
     444  
     445      /* in debug mode, we use a global object that survives this routine */
     446  
     447      AF_GlyphHints  hints = af_debug_hints_rec_;
     448      AF_LoaderRec   loader[1];
     449  
     450      FT_UNUSED( size );
     451  
     452  
     453      if ( hints->memory )
     454        af_glyph_hints_done( hints );
     455  
     456      af_glyph_hints_init( hints, memory );
     457      af_loader_init( loader, hints );
     458  
     459      error = af_loader_load_glyph( loader, module, slot->face,
     460                                    glyph_index, load_flags );
     461  
     462  #ifdef FT_DEBUG_LEVEL_TRACE
     463      if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] )
     464      {
     465  #endif
     466        af_glyph_hints_dump_points( hints, 0 );
     467        af_glyph_hints_dump_segments( hints, 0 );
     468        af_glyph_hints_dump_edges( hints, 0 );
     469  #ifdef FT_DEBUG_LEVEL_TRACE
     470      }
     471  #endif
     472  
     473      af_loader_done( loader );
     474  
     475      return error;
     476  
     477  #else /* !FT_DEBUG_AUTOFIT */
     478  
     479      AF_GlyphHintsRec  hints[1];
     480      AF_LoaderRec      loader[1];
     481  
     482      FT_UNUSED( size );
     483  
     484  
     485      af_glyph_hints_init( hints, memory );
     486      af_loader_init( loader, hints );
     487  
     488      error = af_loader_load_glyph( loader, module, slot->face,
     489                                    glyph_index, load_flags );
     490  
     491      af_loader_done( loader );
     492      af_glyph_hints_done( hints );
     493  
     494      return error;
     495  
     496  #endif /* !FT_DEBUG_AUTOFIT */
     497    }
     498  
     499  
     500    FT_DEFINE_AUTOHINTER_INTERFACE(
     501      af_autofitter_interface,
     502  
     503      NULL,                     /* FT_AutoHinter_GlobalResetFunc reset_face        */
     504      NULL,                     /* FT_AutoHinter_GlobalGetFunc   get_global_hints  */
     505      NULL,                     /* FT_AutoHinter_GlobalDoneFunc  done_global_hints */
     506      af_autofitter_load_glyph  /* FT_AutoHinter_GlyphLoadFunc   load_glyph        */
     507    )
     508  
     509    FT_DEFINE_MODULE(
     510      autofit_module_class,
     511  
     512      FT_MODULE_HINTER,
     513      sizeof ( AF_ModuleRec ),
     514  
     515      "autofitter",
     516      0x10000L,   /* version 1.0 of the autofitter  */
     517      0x20000L,   /* requires FreeType 2.0 or above */
     518  
     519      (const void*)&af_autofitter_interface,
     520  
     521      af_autofitter_init,  /* FT_Module_Constructor module_init   */
     522      af_autofitter_done,  /* FT_Module_Destructor  module_done   */
     523      af_get_interface     /* FT_Module_Requester   get_interface */
     524    )
     525  
     526  
     527  /* END */