Home | History | Annotate | Download | only in autofit
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  afglobal.c                                                             */
      4 /*                                                                         */
      5 /*    Auto-fitter routines to compute global hinting values (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 "afranges.h"
     21 #include "afshaper.h"
     22 #include FT_INTERNAL_DEBUG_H
     23 
     24 
     25   /*************************************************************************/
     26   /*                                                                       */
     27   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     28   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     29   /* messages during execution.                                            */
     30   /*                                                                       */
     31 #undef  FT_COMPONENT
     32 #define FT_COMPONENT  trace_afglobal
     33 
     34 
     35   /* get writing system specific header files */
     36 #undef  WRITING_SYSTEM
     37 #define WRITING_SYSTEM( ws, WS )  /* empty */
     38 #include "afwrtsys.h"
     39 
     40 #include "aferrors.h"
     41 #include "afpic.h"
     42 
     43 
     44 #undef  SCRIPT
     45 #define SCRIPT( s, S, d, h, H, ss )         \
     46           AF_DEFINE_SCRIPT_CLASS(           \
     47             af_ ## s ## _script_class,      \
     48             AF_SCRIPT_ ## S,                \
     49             af_ ## s ## _uniranges,         \
     50             af_ ## s ## _nonbase_uniranges, \
     51             AF_ ## H,                       \
     52             ss )
     53 
     54 #include "afscript.h"
     55 
     56 
     57 #undef  STYLE
     58 #define STYLE( s, S, d, ws, sc, ss, c )  \
     59           AF_DEFINE_STYLE_CLASS(         \
     60             af_ ## s ## _style_class,    \
     61             AF_STYLE_ ## S,              \
     62             ws,                          \
     63             sc,                          \
     64             ss,                          \
     65             c )
     66 
     67 #include "afstyles.h"
     68 
     69 
     70 #ifndef FT_CONFIG_OPTION_PIC
     71 
     72 #undef  WRITING_SYSTEM
     73 #define WRITING_SYSTEM( ws, WS )               \
     74           &af_ ## ws ## _writing_system_class,
     75 
     76   FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass )
     77   af_writing_system_classes[] =
     78   {
     79 
     80 #include "afwrtsys.h"
     81 
     82     NULL  /* do not remove */
     83   };
     84 
     85 
     86 #undef  SCRIPT
     87 #define SCRIPT( s, S, d, h, H, ss )   \
     88           &af_ ## s ## _script_class,
     89 
     90   FT_LOCAL_ARRAY_DEF( AF_ScriptClass )
     91   af_script_classes[] =
     92   {
     93 
     94 #include "afscript.h"
     95 
     96     NULL  /* do not remove */
     97   };
     98 
     99 
    100 #undef  STYLE
    101 #define STYLE( s, S, d, ws, sc, ss, c ) \
    102           &af_ ## s ## _style_class,
    103 
    104   FT_LOCAL_ARRAY_DEF( AF_StyleClass )
    105   af_style_classes[] =
    106   {
    107 
    108 #include "afstyles.h"
    109 
    110     NULL  /* do not remove */
    111   };
    112 
    113 #endif /* !FT_CONFIG_OPTION_PIC */
    114 
    115 
    116 #ifdef FT_DEBUG_LEVEL_TRACE
    117 
    118 #undef  STYLE
    119 #define STYLE( s, S, d, ws, sc, ss, c )  #s,
    120 
    121   FT_LOCAL_ARRAY_DEF( char* )
    122   af_style_names[] =
    123   {
    124 
    125 #include "afstyles.h"
    126 
    127   };
    128 
    129 #endif /* FT_DEBUG_LEVEL_TRACE */
    130 
    131 
    132   /* Compute the style index of each glyph within a given face. */
    133 
    134   static FT_Error
    135   af_face_globals_compute_style_coverage( AF_FaceGlobals  globals )
    136   {
    137     FT_Error    error;
    138     FT_Face     face        = globals->face;
    139     FT_CharMap  old_charmap = face->charmap;
    140     FT_UShort*  gstyles     = globals->glyph_styles;
    141     FT_UInt     ss;
    142     FT_UInt     i;
    143     FT_UInt     dflt        = ~0U; /* a non-valid value */
    144 
    145 
    146     /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */
    147     for ( i = 0; i < (FT_UInt)globals->glyph_count; i++ )
    148       gstyles[i] = AF_STYLE_UNASSIGNED;
    149 
    150     error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
    151     if ( error )
    152     {
    153       /*
    154        * Ignore this error; we simply use the fallback style.
    155        * XXX: Shouldn't we rather disable hinting?
    156        */
    157       error = FT_Err_Ok;
    158       goto Exit;
    159     }
    160 
    161     /* scan each style in a Unicode charmap */
    162     for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ )
    163     {
    164       AF_StyleClass       style_class =
    165                             AF_STYLE_CLASSES_GET[ss];
    166       AF_ScriptClass      script_class =
    167                             AF_SCRIPT_CLASSES_GET[style_class->script];
    168       AF_Script_UniRange  range;
    169 
    170 
    171       if ( !script_class->script_uni_ranges )
    172         continue;
    173 
    174       /*
    175        *  Scan all Unicode points in the range and set the corresponding
    176        *  glyph style index.
    177        */
    178       if ( style_class->coverage == AF_COVERAGE_DEFAULT )
    179       {
    180         if ( (FT_UInt)style_class->script ==
    181              globals->module->default_script )
    182           dflt = ss;
    183 
    184         for ( range = script_class->script_uni_ranges;
    185               range->first != 0;
    186               range++ )
    187         {
    188           FT_ULong  charcode = range->first;
    189           FT_UInt   gindex;
    190 
    191 
    192           gindex = FT_Get_Char_Index( face, charcode );
    193 
    194           if ( gindex != 0                                                &&
    195                gindex < (FT_ULong)globals->glyph_count                    &&
    196                ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
    197             gstyles[gindex] = (FT_UShort)ss;
    198 
    199           for (;;)
    200           {
    201             charcode = FT_Get_Next_Char( face, charcode, &gindex );
    202 
    203             if ( gindex == 0 || charcode > range->last )
    204               break;
    205 
    206             if ( gindex < (FT_ULong)globals->glyph_count                    &&
    207                  ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
    208               gstyles[gindex] = (FT_UShort)ss;
    209           }
    210         }
    211 
    212         /* do the same for the script's non-base characters */
    213         for ( range = script_class->script_uni_nonbase_ranges;
    214               range->first != 0;
    215               range++ )
    216         {
    217           FT_ULong  charcode = range->first;
    218           FT_UInt   gindex;
    219 
    220 
    221           gindex = FT_Get_Char_Index( face, charcode );
    222 
    223           if ( gindex != 0                                          &&
    224                gindex < (FT_ULong)globals->glyph_count              &&
    225                ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss )
    226             gstyles[gindex] |= AF_NONBASE;
    227 
    228           for (;;)
    229           {
    230             charcode = FT_Get_Next_Char( face, charcode, &gindex );
    231 
    232             if ( gindex == 0 || charcode > range->last )
    233               break;
    234 
    235             if ( gindex < (FT_ULong)globals->glyph_count              &&
    236                  ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss )
    237               gstyles[gindex] |= AF_NONBASE;
    238           }
    239         }
    240       }
    241       else
    242       {
    243         /* get glyphs not directly addressable by cmap */
    244         af_shaper_get_coverage( globals, style_class, gstyles, 0 );
    245       }
    246     }
    247 
    248     /* handle the remaining default OpenType features ... */
    249     for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ )
    250     {
    251       AF_StyleClass  style_class = AF_STYLE_CLASSES_GET[ss];
    252 
    253 
    254       if ( style_class->coverage == AF_COVERAGE_DEFAULT )
    255         af_shaper_get_coverage( globals, style_class, gstyles, 0 );
    256     }
    257 
    258     /* ... and finally the default OpenType features of the default script */
    259     af_shaper_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles, 1 );
    260 
    261     /* mark ASCII digits */
    262     for ( i = 0x30; i <= 0x39; i++ )
    263     {
    264       FT_UInt  gindex = FT_Get_Char_Index( face, i );
    265 
    266 
    267       if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count )
    268         gstyles[gindex] |= AF_DIGIT;
    269     }
    270 
    271   Exit:
    272     /*
    273      *  By default, all uncovered glyphs are set to the fallback style.
    274      *  XXX: Shouldn't we disable hinting or do something similar?
    275      */
    276     if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED )
    277     {
    278       FT_Long  nn;
    279 
    280 
    281       for ( nn = 0; nn < globals->glyph_count; nn++ )
    282       {
    283         if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
    284         {
    285           gstyles[nn] &= ~AF_STYLE_MASK;
    286           gstyles[nn] |= globals->module->fallback_style;
    287         }
    288       }
    289     }
    290 
    291 #ifdef FT_DEBUG_LEVEL_TRACE
    292 
    293     FT_TRACE4(( "\n"
    294                 "style coverage\n"
    295                 "==============\n"
    296                 "\n" ));
    297 
    298     for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ )
    299     {
    300       AF_StyleClass  style_class = AF_STYLE_CLASSES_GET[ss];
    301       FT_UInt        count       = 0;
    302       FT_Long        idx;
    303 
    304 
    305       FT_TRACE4(( "%s:\n", af_style_names[style_class->style] ));
    306 
    307       for ( idx = 0; idx < globals->glyph_count; idx++ )
    308       {
    309         if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style )
    310         {
    311           if ( !( count % 10 ) )
    312             FT_TRACE4(( " " ));
    313 
    314           FT_TRACE4(( " %d", idx ));
    315           count++;
    316 
    317           if ( !( count % 10 ) )
    318             FT_TRACE4(( "\n" ));
    319         }
    320       }
    321 
    322       if ( !count )
    323         FT_TRACE4(( "  (none)\n" ));
    324       if ( count % 10 )
    325         FT_TRACE4(( "\n" ));
    326     }
    327 
    328 #endif /* FT_DEBUG_LEVEL_TRACE */
    329 
    330     FT_Set_Charmap( face, old_charmap );
    331     return error;
    332   }
    333 
    334 
    335   FT_LOCAL_DEF( FT_Error )
    336   af_face_globals_new( FT_Face          face,
    337                        AF_FaceGlobals  *aglobals,
    338                        AF_Module        module )
    339   {
    340     FT_Error        error;
    341     FT_Memory       memory;
    342     AF_FaceGlobals  globals = NULL;
    343 
    344 
    345     memory = face->memory;
    346 
    347     /* we allocate an AF_FaceGlobals structure together */
    348     /* with the glyph_styles array                      */
    349     if ( FT_ALLOC( globals,
    350                    sizeof ( *globals ) +
    351                      (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) )
    352       goto Exit;
    353 
    354     globals->face                      = face;
    355     globals->glyph_count               = face->num_glyphs;
    356     /* right after the globals structure come the glyph styles */
    357     globals->glyph_styles              = (FT_UShort*)( globals + 1 );
    358     globals->module                    = module;
    359     globals->stem_darkening_for_ppem   = 0;
    360     globals->darken_x                  = 0;
    361     globals->darken_y                  = 0;
    362     globals->standard_vertical_width   = 0;
    363     globals->standard_horizontal_width = 0;
    364     globals->scale_down_factor         = 0;
    365 
    366 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
    367     globals->hb_font = hb_ft_font_create( face, NULL );
    368     globals->hb_buf  = hb_buffer_create();
    369 #endif
    370 
    371     error = af_face_globals_compute_style_coverage( globals );
    372     if ( error )
    373     {
    374       af_face_globals_free( globals );
    375       globals = NULL;
    376     }
    377     else
    378       globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX;
    379 
    380   Exit:
    381     *aglobals = globals;
    382     return error;
    383   }
    384 
    385 
    386   FT_LOCAL_DEF( void )
    387   af_face_globals_free( AF_FaceGlobals  globals )
    388   {
    389     if ( globals )
    390     {
    391       FT_Memory  memory = globals->face->memory;
    392       FT_UInt    nn;
    393 
    394 
    395       for ( nn = 0; nn < AF_STYLE_MAX; nn++ )
    396       {
    397         if ( globals->metrics[nn] )
    398         {
    399           AF_StyleClass          style_class =
    400             AF_STYLE_CLASSES_GET[nn];
    401           AF_WritingSystemClass  writing_system_class =
    402             AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];
    403 
    404 
    405           if ( writing_system_class->style_metrics_done )
    406             writing_system_class->style_metrics_done( globals->metrics[nn] );
    407 
    408           FT_FREE( globals->metrics[nn] );
    409         }
    410       }
    411 
    412 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
    413       hb_font_destroy( globals->hb_font );
    414       hb_buffer_destroy( globals->hb_buf );
    415 #endif
    416 
    417       /* no need to free `globals->glyph_styles'; */
    418       /* it is part of the `globals' array        */
    419       FT_FREE( globals );
    420     }
    421   }
    422 
    423 
    424   FT_LOCAL_DEF( FT_Error )
    425   af_face_globals_get_metrics( AF_FaceGlobals    globals,
    426                                FT_UInt           gindex,
    427                                FT_UInt           options,
    428                                AF_StyleMetrics  *ametrics )
    429   {
    430     AF_StyleMetrics  metrics = NULL;
    431 
    432     AF_Style               style = (AF_Style)options;
    433     AF_WritingSystemClass  writing_system_class;
    434     AF_StyleClass          style_class;
    435 
    436     FT_Error  error = FT_Err_Ok;
    437 
    438 
    439     if ( gindex >= (FT_ULong)globals->glyph_count )
    440     {
    441       error = FT_THROW( Invalid_Argument );
    442       goto Exit;
    443     }
    444 
    445     /* if we have a forced style (via `options'), use it, */
    446     /* otherwise look into `glyph_styles' array           */
    447     if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX )
    448       style = (AF_Style)( globals->glyph_styles[gindex] &
    449                           AF_STYLE_UNASSIGNED           );
    450 
    451     style_class          = AF_STYLE_CLASSES_GET[style];
    452     writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET
    453                              [style_class->writing_system];
    454 
    455     metrics = globals->metrics[style];
    456     if ( !metrics )
    457     {
    458       /* create the global metrics object if necessary */
    459       FT_Memory  memory = globals->face->memory;
    460 
    461 
    462       if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) )
    463         goto Exit;
    464 
    465       metrics->style_class = style_class;
    466       metrics->globals     = globals;
    467 
    468       if ( writing_system_class->style_metrics_init )
    469       {
    470         error = writing_system_class->style_metrics_init( metrics,
    471                                                           globals->face );
    472         if ( error )
    473         {
    474           if ( writing_system_class->style_metrics_done )
    475             writing_system_class->style_metrics_done( metrics );
    476 
    477           FT_FREE( metrics );
    478           goto Exit;
    479         }
    480       }
    481 
    482       globals->metrics[style] = metrics;
    483     }
    484 
    485   Exit:
    486     *ametrics = metrics;
    487 
    488     return error;
    489   }
    490 
    491 
    492   FT_LOCAL_DEF( FT_Bool )
    493   af_face_globals_is_digit( AF_FaceGlobals  globals,
    494                             FT_UInt         gindex )
    495   {
    496     if ( gindex < (FT_ULong)globals->glyph_count )
    497       return (FT_Bool)( globals->glyph_styles[gindex] & AF_DIGIT );
    498 
    499     return (FT_Bool)0;
    500   }
    501 
    502 
    503 /* END */
    504