Home | History | Annotate | Download | only in autofit
      1 /****************************************************************************
      2  *
      3  * afmodule.c
      4  *
      5  *   Auto-fitter module implementation (body).
      6  *
      7  * Copyright 2003-2018 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   AF_GlyphHintsRec  _af_debug_hints_rec[1];
     52 
     53   void*  _af_debug_hints = _af_debug_hints_rec;
     54 #endif
     55 
     56 #include FT_INTERNAL_OBJECTS_H
     57 #include FT_INTERNAL_DEBUG_H
     58 #include FT_DRIVER_H
     59 #include FT_SERVICE_PROPERTIES_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  trace_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 =
     93           (FT_Pointer)globals;
     94         face->autohint.finalizer =
     95           (FT_Generic_Finalizer)af_face_globals_free;
     96       }
     97     }
     98 
     99     if ( !error )
    100       *aglobals = globals;
    101 
    102     return error;
    103   }
    104 
    105 
    106   static FT_Error
    107   af_property_set( FT_Module    ft_module,
    108                    const char*  property_name,
    109                    const void*  value,
    110                    FT_Bool      value_is_string )
    111   {
    112     FT_Error   error  = FT_Err_Ok;
    113     AF_Module  module = (AF_Module)ft_module;
    114 
    115 #ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    116     FT_UNUSED( value_is_string );
    117 #endif
    118 
    119 
    120     if ( !ft_strcmp( property_name, "fallback-script" ) )
    121     {
    122       FT_UInt*  fallback_script;
    123       FT_UInt   ss;
    124 
    125 
    126 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    127       if ( value_is_string )
    128         return FT_THROW( Invalid_Argument );
    129 #endif
    130 
    131       fallback_script = (FT_UInt*)value;
    132 
    133       /* We translate the fallback script to a fallback style that uses */
    134       /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its  */
    135       /* coverage value.                                                */
    136       for ( ss = 0; af_style_classes[ss]; ss++ )
    137       {
    138         AF_StyleClass  style_class = af_style_classes[ss];
    139 
    140 
    141         if ( (FT_UInt)style_class->script == *fallback_script &&
    142              style_class->coverage == AF_COVERAGE_DEFAULT     )
    143         {
    144           module->fallback_style = ss;
    145           break;
    146         }
    147       }
    148 
    149       if ( !af_style_classes[ss] )
    150       {
    151         FT_TRACE0(( "af_property_set: Invalid value %d for property `%s'\n",
    152                     fallback_script, property_name ));
    153         return FT_THROW( Invalid_Argument );
    154       }
    155 
    156       return error;
    157     }
    158     else if ( !ft_strcmp( property_name, "default-script" ) )
    159     {
    160       FT_UInt*  default_script;
    161 
    162 
    163 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    164       if ( value_is_string )
    165         return FT_THROW( Invalid_Argument );
    166 #endif
    167 
    168       default_script = (FT_UInt*)value;
    169 
    170       module->default_script = *default_script;
    171 
    172       return error;
    173     }
    174     else if ( !ft_strcmp( property_name, "increase-x-height" ) )
    175     {
    176       FT_Prop_IncreaseXHeight*  prop;
    177       AF_FaceGlobals            globals;
    178 
    179 
    180 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    181       if ( value_is_string )
    182         return FT_THROW( Invalid_Argument );
    183 #endif
    184 
    185       prop = (FT_Prop_IncreaseXHeight*)value;
    186 
    187       error = af_property_get_face_globals( prop->face, &globals, module );
    188       if ( !error )
    189         globals->increase_x_height = prop->limit;
    190 
    191       return error;
    192     }
    193 #ifdef AF_CONFIG_OPTION_USE_WARPER
    194     else if ( !ft_strcmp( property_name, "warping" ) )
    195     {
    196 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    197       if ( value_is_string )
    198       {
    199         const char*  s = (const char*)value;
    200         long         w = ft_strtol( s, NULL, 10 );
    201 
    202 
    203         if ( w == 0 )
    204           module->warping = 0;
    205         else if ( w == 1 )
    206           module->warping = 1;
    207         else
    208           return FT_THROW( Invalid_Argument );
    209       }
    210       else
    211 #endif
    212       {
    213         FT_Bool*  warping = (FT_Bool*)value;
    214 
    215 
    216         module->warping = *warping;
    217       }
    218 
    219       return error;
    220     }
    221 #endif /* AF_CONFIG_OPTION_USE_WARPER */
    222     else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
    223     {
    224       FT_Int*  darken_params;
    225       FT_Int   x1, y1, x2, y2, x3, y3, x4, y4;
    226 
    227 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    228       FT_Int   dp[8];
    229 
    230 
    231       if ( value_is_string )
    232       {
    233         const char*  s = (const char*)value;
    234         char*        ep;
    235         int          i;
    236 
    237 
    238         /* eight comma-separated numbers */
    239         for ( i = 0; i < 7; i++ )
    240         {
    241           dp[i] = (FT_Int)ft_strtol( s, &ep, 10 );
    242           if ( *ep != ',' || s == ep )
    243             return FT_THROW( Invalid_Argument );
    244 
    245           s = ep + 1;
    246         }
    247 
    248         dp[7] = (FT_Int)ft_strtol( s, &ep, 10 );
    249         if ( !( *ep == '\0' || *ep == ' ' ) || s == ep )
    250           return FT_THROW( Invalid_Argument );
    251 
    252         darken_params = dp;
    253       }
    254       else
    255 #endif
    256         darken_params = (FT_Int*)value;
    257 
    258       x1 = darken_params[0];
    259       y1 = darken_params[1];
    260       x2 = darken_params[2];
    261       y2 = darken_params[3];
    262       x3 = darken_params[4];
    263       y3 = darken_params[5];
    264       x4 = darken_params[6];
    265       y4 = darken_params[7];
    266 
    267       if ( x1 < 0   || x2 < 0   || x3 < 0   || x4 < 0   ||
    268            y1 < 0   || y2 < 0   || y3 < 0   || y4 < 0   ||
    269            x1 > x2  || x2 > x3  || x3 > x4              ||
    270            y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 )
    271         return FT_THROW( Invalid_Argument );
    272 
    273       module->darken_params[0] = x1;
    274       module->darken_params[1] = y1;
    275       module->darken_params[2] = x2;
    276       module->darken_params[3] = y2;
    277       module->darken_params[4] = x3;
    278       module->darken_params[5] = y3;
    279       module->darken_params[6] = x4;
    280       module->darken_params[7] = y4;
    281 
    282       return error;
    283     }
    284     else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
    285     {
    286 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    287       if ( value_is_string )
    288       {
    289         const char*  s   = (const char*)value;
    290         long         nsd = ft_strtol( s, NULL, 10 );
    291 
    292 
    293         if ( !nsd )
    294           module->no_stem_darkening = FALSE;
    295         else
    296           module->no_stem_darkening = TRUE;
    297       }
    298       else
    299 #endif
    300       {
    301         FT_Bool*  no_stem_darkening = (FT_Bool*)value;
    302 
    303 
    304         module->no_stem_darkening = *no_stem_darkening;
    305       }
    306 
    307       return error;
    308     }
    309 
    310     FT_TRACE0(( "af_property_set: missing property `%s'\n",
    311                 property_name ));
    312     return FT_THROW( Missing_Property );
    313   }
    314 
    315 
    316   static FT_Error
    317   af_property_get( FT_Module    ft_module,
    318                    const char*  property_name,
    319                    void*        value )
    320   {
    321     FT_Error   error          = FT_Err_Ok;
    322     AF_Module  module         = (AF_Module)ft_module;
    323     FT_UInt    fallback_style = module->fallback_style;
    324     FT_UInt    default_script = module->default_script;
    325 #ifdef AF_CONFIG_OPTION_USE_WARPER
    326     FT_Bool    warping        = module->warping;
    327 #endif
    328 
    329 
    330     if ( !ft_strcmp( property_name, "glyph-to-script-map" ) )
    331     {
    332       FT_Prop_GlyphToScriptMap*  prop = (FT_Prop_GlyphToScriptMap*)value;
    333       AF_FaceGlobals             globals;
    334 
    335 
    336       error = af_property_get_face_globals( prop->face, &globals, module );
    337       if ( !error )
    338         prop->map = globals->glyph_styles;
    339 
    340       return error;
    341     }
    342     else if ( !ft_strcmp( property_name, "fallback-script" ) )
    343     {
    344       FT_UInt*  val = (FT_UInt*)value;
    345 
    346       AF_StyleClass  style_class = af_style_classes[fallback_style];
    347 
    348 
    349       *val = style_class->script;
    350 
    351       return error;
    352     }
    353     else if ( !ft_strcmp( property_name, "default-script" ) )
    354     {
    355       FT_UInt*  val = (FT_UInt*)value;
    356 
    357 
    358       *val = default_script;
    359 
    360       return error;
    361     }
    362     else if ( !ft_strcmp( property_name, "increase-x-height" ) )
    363     {
    364       FT_Prop_IncreaseXHeight*  prop = (FT_Prop_IncreaseXHeight*)value;
    365       AF_FaceGlobals            globals;
    366 
    367 
    368       error = af_property_get_face_globals( prop->face, &globals, module );
    369       if ( !error )
    370         prop->limit = globals->increase_x_height;
    371 
    372       return error;
    373     }
    374 #ifdef AF_CONFIG_OPTION_USE_WARPER
    375     else if ( !ft_strcmp( property_name, "warping" ) )
    376     {
    377       FT_Bool*  val = (FT_Bool*)value;
    378 
    379 
    380       *val = warping;
    381 
    382       return error;
    383     }
    384 #endif /* AF_CONFIG_OPTION_USE_WARPER */
    385     else if ( !ft_strcmp( property_name, "darkening-parameters" ) )
    386     {
    387       FT_Int*  darken_params = module->darken_params;
    388       FT_Int*  val           = (FT_Int*)value;
    389 
    390 
    391       val[0] = darken_params[0];
    392       val[1] = darken_params[1];
    393       val[2] = darken_params[2];
    394       val[3] = darken_params[3];
    395       val[4] = darken_params[4];
    396       val[5] = darken_params[5];
    397       val[6] = darken_params[6];
    398       val[7] = darken_params[7];
    399 
    400       return error;
    401     }
    402     else if ( !ft_strcmp( property_name, "no-stem-darkening" ) )
    403     {
    404       FT_Bool   no_stem_darkening = module->no_stem_darkening;
    405       FT_Bool*  val               = (FT_Bool*)value;
    406 
    407 
    408       *val = no_stem_darkening;
    409 
    410       return error;
    411     }
    412 
    413     FT_TRACE0(( "af_property_get: missing property `%s'\n",
    414                 property_name ));
    415     return FT_THROW( Missing_Property );
    416   }
    417 
    418 
    419   FT_DEFINE_SERVICE_PROPERTIESREC(
    420     af_service_properties,
    421 
    422     (FT_Properties_SetFunc)af_property_set,        /* set_property */
    423     (FT_Properties_GetFunc)af_property_get )       /* get_property */
    424 
    425 
    426   FT_DEFINE_SERVICEDESCREC1(
    427     af_services,
    428 
    429     FT_SERVICE_ID_PROPERTIES, &af_service_properties )
    430 
    431 
    432   FT_CALLBACK_DEF( FT_Module_Interface )
    433   af_get_interface( FT_Module    module,
    434                     const char*  module_interface )
    435   {
    436     FT_UNUSED( module );
    437 
    438     return ft_service_list_lookup( af_services, module_interface );
    439   }
    440 
    441 
    442   FT_CALLBACK_DEF( FT_Error )
    443   af_autofitter_init( FT_Module  ft_module )      /* AF_Module */
    444   {
    445     AF_Module  module = (AF_Module)ft_module;
    446 
    447 
    448     module->fallback_style    = AF_STYLE_FALLBACK;
    449     module->default_script    = AF_SCRIPT_DEFAULT;
    450 #ifdef AF_CONFIG_OPTION_USE_WARPER
    451     module->warping           = 0;
    452 #endif
    453     module->no_stem_darkening = TRUE;
    454 
    455     module->darken_params[0]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
    456     module->darken_params[1]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
    457     module->darken_params[2]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2;
    458     module->darken_params[3]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2;
    459     module->darken_params[4]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3;
    460     module->darken_params[5]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3;
    461     module->darken_params[6]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
    462     module->darken_params[7]  = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
    463 
    464     return FT_Err_Ok;
    465   }
    466 
    467 
    468   FT_CALLBACK_DEF( void )
    469   af_autofitter_done( FT_Module  ft_module )      /* AF_Module */
    470   {
    471     FT_UNUSED( ft_module );
    472 
    473 #ifdef FT_DEBUG_AUTOFIT
    474     if ( _af_debug_hints_rec->memory )
    475       af_glyph_hints_done( _af_debug_hints_rec );
    476 #endif
    477   }
    478 
    479 
    480   FT_CALLBACK_DEF( FT_Error )
    481   af_autofitter_load_glyph( AF_Module     module,
    482                             FT_GlyphSlot  slot,
    483                             FT_Size       size,
    484                             FT_UInt       glyph_index,
    485                             FT_Int32      load_flags )
    486   {
    487     FT_Error   error  = FT_Err_Ok;
    488     FT_Memory  memory = module->root.library->memory;
    489 
    490 #ifdef FT_DEBUG_AUTOFIT
    491 
    492     /* in debug mode, we use a global object that survives this routine */
    493 
    494     AF_GlyphHints  hints = _af_debug_hints_rec;
    495     AF_LoaderRec   loader[1];
    496 
    497     FT_UNUSED( size );
    498 
    499 
    500     if ( hints->memory )
    501       af_glyph_hints_done( hints );
    502 
    503     af_glyph_hints_init( hints, memory );
    504     af_loader_init( loader, hints );
    505 
    506     error = af_loader_load_glyph( loader, module, slot->face,
    507                                   glyph_index, load_flags );
    508 
    509 #ifdef FT_DEBUG_LEVEL_TRACE
    510     if ( ft_trace_levels[FT_COMPONENT] )
    511     {
    512 #endif
    513       af_glyph_hints_dump_points( hints, 0 );
    514       af_glyph_hints_dump_segments( hints, 0 );
    515       af_glyph_hints_dump_edges( hints, 0 );
    516 #ifdef FT_DEBUG_LEVEL_TRACE
    517     }
    518 #endif
    519 
    520     af_loader_done( loader );
    521 
    522     return error;
    523 
    524 #else /* !FT_DEBUG_AUTOFIT */
    525 
    526     AF_GlyphHintsRec  hints[1];
    527     AF_LoaderRec      loader[1];
    528 
    529     FT_UNUSED( size );
    530 
    531 
    532     af_glyph_hints_init( hints, memory );
    533     af_loader_init( loader, hints );
    534 
    535     error = af_loader_load_glyph( loader, module, slot->face,
    536                                   glyph_index, load_flags );
    537 
    538     af_loader_done( loader );
    539     af_glyph_hints_done( hints );
    540 
    541     return error;
    542 
    543 #endif /* !FT_DEBUG_AUTOFIT */
    544   }
    545 
    546 
    547   FT_DEFINE_AUTOHINTER_INTERFACE(
    548     af_autofitter_interface,
    549 
    550     NULL,                                                    /* reset_face */
    551     NULL,                                              /* get_global_hints */
    552     NULL,                                             /* done_global_hints */
    553     (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph )  /* load_glyph */
    554 
    555 
    556   FT_DEFINE_MODULE(
    557     autofit_module_class,
    558 
    559     FT_MODULE_HINTER,
    560     sizeof ( AF_ModuleRec ),
    561 
    562     "autofitter",
    563     0x10000L,   /* version 1.0 of the autofitter  */
    564     0x20000L,   /* requires FreeType 2.0 or above */
    565 
    566     (const void*)&af_autofitter_interface,
    567 
    568     (FT_Module_Constructor)af_autofitter_init,  /* module_init   */
    569     (FT_Module_Destructor) af_autofitter_done,  /* module_done   */
    570     (FT_Module_Requester)  af_get_interface     /* get_interface */
    571   )
    572 
    573 
    574 /* END */
    575