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