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-2013 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 "afdummy.h"
     21 #include "aflatin.h"
     22 #include "afcjk.h"
     23 #include "afindic.h"
     24 #include "afpic.h"
     25 
     26 #include "aferrors.h"
     27 
     28 #ifdef FT_OPTION_AUTOFIT2
     29 #include "aflatin2.h"
     30 #endif
     31 
     32 #ifndef FT_CONFIG_OPTION_PIC
     33 
     34   /* when updating this table, don't forget to update          */
     35   /* AF_SCRIPT_CLASSES_COUNT and autofit_module_class_pic_init */
     36 
     37   /* populate this list when you add new scripts */
     38   static AF_ScriptClass const  af_script_classes[] =
     39   {
     40     &af_dummy_script_class,
     41 #ifdef FT_OPTION_AUTOFIT2
     42     &af_latin2_script_class,
     43 #endif
     44     &af_latin_script_class,
     45     &af_cjk_script_class,
     46     &af_indic_script_class,
     47     NULL  /* do not remove */
     48   };
     49 
     50 #endif /* !FT_CONFIG_OPTION_PIC */
     51 
     52 
     53   /* Compute the script index of each glyph within a given face. */
     54 
     55   static FT_Error
     56   af_face_globals_compute_script_coverage( AF_FaceGlobals  globals )
     57   {
     58     FT_Error    error;
     59     FT_Face     face        = globals->face;
     60     FT_CharMap  old_charmap = face->charmap;
     61     FT_Byte*    gscripts    = globals->glyph_scripts;
     62     FT_UInt     ss;
     63     FT_UInt     i;
     64 
     65 
     66     /* the value AF_SCRIPT_NONE means `uncovered glyph' */
     67     FT_MEM_SET( globals->glyph_scripts,
     68                 AF_SCRIPT_NONE,
     69                 globals->glyph_count );
     70 
     71     error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
     72     if ( error )
     73     {
     74      /*
     75       *  Ignore this error; we simply use the fallback script.
     76       *  XXX: Shouldn't we rather disable hinting?
     77       */
     78       error = FT_Err_Ok;
     79       goto Exit;
     80     }
     81 
     82     /* scan each script in a Unicode charmap */
     83     for ( ss = 0; AF_SCRIPT_CLASSES_GET[ss]; ss++ )
     84     {
     85       AF_ScriptClass      clazz = AF_SCRIPT_CLASSES_GET[ss];
     86       AF_Script_UniRange  range;
     87 
     88 
     89       if ( clazz->script_uni_ranges == NULL )
     90         continue;
     91 
     92       /*
     93        *  Scan all Unicode points in the range and set the corresponding
     94        *  glyph script index.
     95        */
     96       for ( range = clazz->script_uni_ranges; range->first != 0; range++ )
     97       {
     98         FT_ULong  charcode = range->first;
     99         FT_UInt   gindex;
    100 
    101 
    102         gindex = FT_Get_Char_Index( face, charcode );
    103 
    104         if ( gindex != 0                             &&
    105              gindex < (FT_ULong)globals->glyph_count &&
    106              gscripts[gindex] == AF_SCRIPT_NONE )
    107           gscripts[gindex] = (FT_Byte)ss;
    108 
    109         for (;;)
    110         {
    111           charcode = FT_Get_Next_Char( face, charcode, &gindex );
    112 
    113           if ( gindex == 0 || charcode > range->last )
    114             break;
    115 
    116           if ( gindex < (FT_ULong)globals->glyph_count &&
    117                gscripts[gindex] == AF_SCRIPT_NONE )
    118             gscripts[gindex] = (FT_Byte)ss;
    119         }
    120       }
    121     }
    122 
    123     /* mark ASCII digits */
    124     for ( i = 0x30; i <= 0x39; i++ )
    125     {
    126       FT_UInt  gindex = FT_Get_Char_Index( face, i );
    127 
    128 
    129       if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count )
    130         gscripts[gindex] |= AF_DIGIT;
    131     }
    132 
    133   Exit:
    134     /*
    135      *  By default, all uncovered glyphs are set to the fallback script.
    136      *  XXX: Shouldn't we disable hinting or do something similar?
    137      */
    138     if ( globals->module->fallback_script != AF_SCRIPT_NONE )
    139     {
    140       FT_Long  nn;
    141 
    142 
    143       for ( nn = 0; nn < globals->glyph_count; nn++ )
    144       {
    145         if ( ( gscripts[nn] & ~AF_DIGIT ) == AF_SCRIPT_NONE )
    146         {
    147           gscripts[nn] &= ~AF_SCRIPT_NONE;
    148           gscripts[nn] |= globals->module->fallback_script;
    149         }
    150       }
    151     }
    152 
    153     FT_Set_Charmap( face, old_charmap );
    154     return error;
    155   }
    156 
    157 
    158   FT_LOCAL_DEF( FT_Error )
    159   af_face_globals_new( FT_Face          face,
    160                        AF_FaceGlobals  *aglobals,
    161                        AF_Module        module )
    162   {
    163     FT_Error        error;
    164     FT_Memory       memory;
    165     AF_FaceGlobals  globals = NULL;
    166 
    167 
    168     memory = face->memory;
    169 
    170     if ( FT_ALLOC( globals, sizeof ( *globals ) +
    171                             face->num_glyphs * sizeof ( FT_Byte ) ) )
    172       goto Exit;
    173 
    174     globals->face          = face;
    175     globals->glyph_count   = face->num_glyphs;
    176     globals->glyph_scripts = (FT_Byte*)( globals + 1 );
    177     globals->module        = module;
    178 
    179     error = af_face_globals_compute_script_coverage( globals );
    180     if ( error )
    181     {
    182       af_face_globals_free( globals );
    183       globals = NULL;
    184     }
    185 
    186     globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX;
    187 
    188   Exit:
    189     *aglobals = globals;
    190     return error;
    191   }
    192 
    193 
    194   FT_LOCAL_DEF( void )
    195   af_face_globals_free( AF_FaceGlobals  globals )
    196   {
    197     if ( globals )
    198     {
    199       FT_Memory  memory = globals->face->memory;
    200       FT_UInt    nn;
    201 
    202 
    203       for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ )
    204       {
    205         if ( globals->metrics[nn] )
    206         {
    207           AF_ScriptClass  clazz = AF_SCRIPT_CLASSES_GET[nn];
    208 
    209 
    210           FT_ASSERT( globals->metrics[nn]->clazz == clazz );
    211 
    212           if ( clazz->script_metrics_done )
    213             clazz->script_metrics_done( globals->metrics[nn] );
    214 
    215           FT_FREE( globals->metrics[nn] );
    216         }
    217       }
    218 
    219       globals->glyph_count   = 0;
    220       globals->glyph_scripts = NULL;  /* no need to free this one! */
    221       globals->face          = NULL;
    222 
    223       FT_FREE( globals );
    224     }
    225   }
    226 
    227 
    228   FT_LOCAL_DEF( FT_Error )
    229   af_face_globals_get_metrics( AF_FaceGlobals     globals,
    230                                FT_UInt            gindex,
    231                                FT_UInt            options,
    232                                AF_ScriptMetrics  *ametrics )
    233   {
    234     AF_ScriptMetrics  metrics = NULL;
    235     FT_UInt           gidx;
    236     AF_ScriptClass    clazz;
    237     FT_UInt           script     = options & 15;
    238     const FT_Offset   script_max = sizeof ( AF_SCRIPT_CLASSES_GET ) /
    239                                      sizeof ( AF_SCRIPT_CLASSES_GET[0] );
    240     FT_Error          error      = FT_Err_Ok;
    241 
    242 
    243     if ( gindex >= (FT_ULong)globals->glyph_count )
    244     {
    245       error = FT_THROW( Invalid_Argument );
    246       goto Exit;
    247     }
    248 
    249     gidx = script;
    250     if ( gidx == 0 || gidx + 1 >= script_max )
    251       gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_NONE;
    252 
    253     clazz = AF_SCRIPT_CLASSES_GET[gidx];
    254     if ( script == 0 )
    255       script = clazz->script;
    256 
    257     metrics = globals->metrics[clazz->script];
    258     if ( metrics == NULL )
    259     {
    260       /* create the global metrics object if necessary */
    261       FT_Memory  memory = globals->face->memory;
    262 
    263 
    264       if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
    265         goto Exit;
    266 
    267       metrics->clazz   = clazz;
    268       metrics->globals = globals;
    269 
    270       if ( clazz->script_metrics_init )
    271       {
    272         error = clazz->script_metrics_init( metrics, globals->face );
    273         if ( error )
    274         {
    275           if ( clazz->script_metrics_done )
    276             clazz->script_metrics_done( metrics );
    277 
    278           FT_FREE( metrics );
    279           goto Exit;
    280         }
    281       }
    282 
    283       globals->metrics[clazz->script] = metrics;
    284     }
    285 
    286   Exit:
    287     *ametrics = metrics;
    288 
    289     return error;
    290   }
    291 
    292 
    293   FT_LOCAL_DEF( FT_Bool )
    294   af_face_globals_is_digit( AF_FaceGlobals  globals,
    295                             FT_UInt         gindex )
    296   {
    297     if ( gindex < (FT_ULong)globals->glyph_count )
    298       return (FT_Bool)( globals->glyph_scripts[gindex] & AF_DIGIT );
    299 
    300     return (FT_Bool)0;
    301   }
    302 
    303 
    304 /* END */
    305