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-2011 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   /* index of default script in `af_script_classes' */
     53 #define AF_SCRIPT_LIST_DEFAULT  2
     54   /* a bit mask indicating an uncovered glyph       */
     55 #define AF_SCRIPT_LIST_NONE     0x7F
     56   /* if this flag is set, we have an ASCII digit    */
     57 #define AF_DIGIT                0x80
     58 
     59 
     60   /*
     61    *  Note that glyph_scripts[] is used to map each glyph into
     62    *  an index into the `af_script_classes' array.
     63    *
     64    */
     65   typedef struct  AF_FaceGlobalsRec_
     66   {
     67     FT_Face           face;
     68     FT_Long           glyph_count;    /* same as face->num_glyphs */
     69     FT_Byte*          glyph_scripts;
     70 
     71     AF_ScriptMetrics  metrics[AF_SCRIPT_MAX];
     72 
     73   } AF_FaceGlobalsRec;
     74 
     75 
     76   /* Compute the script index of each glyph within a given face. */
     77 
     78   static FT_Error
     79   af_face_globals_compute_script_coverage( AF_FaceGlobals  globals )
     80   {
     81     FT_Error    error       = AF_Err_Ok;
     82     FT_Face     face        = globals->face;
     83     FT_CharMap  old_charmap = face->charmap;
     84     FT_Byte*    gscripts    = globals->glyph_scripts;
     85     FT_UInt     ss, i;
     86 
     87 
     88     /* the value AF_SCRIPT_LIST_NONE means `uncovered glyph' */
     89     FT_MEM_SET( globals->glyph_scripts,
     90                 AF_SCRIPT_LIST_NONE,
     91                 globals->glyph_count );
     92 
     93     error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
     94     if ( error )
     95     {
     96      /*
     97       *  Ignore this error; we simply use the default script.
     98       *  XXX: Shouldn't we rather disable hinting?
     99       */
    100       error = AF_Err_Ok;
    101       goto Exit;
    102     }
    103 
    104     /* scan each script in a Unicode charmap */
    105     for ( ss = 0; AF_SCRIPT_CLASSES_GET[ss]; ss++ )
    106     {
    107       AF_ScriptClass      clazz = AF_SCRIPT_CLASSES_GET[ss];
    108       AF_Script_UniRange  range;
    109 
    110 
    111       if ( clazz->script_uni_ranges == NULL )
    112         continue;
    113 
    114       /*
    115        *  Scan all unicode points in the range and set the corresponding
    116        *  glyph script index.
    117        */
    118       for ( range = clazz->script_uni_ranges; range->first != 0; range++ )
    119       {
    120         FT_ULong  charcode = range->first;
    121         FT_UInt   gindex;
    122 
    123 
    124         gindex = FT_Get_Char_Index( face, charcode );
    125 
    126         if ( gindex != 0                             &&
    127              gindex < (FT_ULong)globals->glyph_count &&
    128              gscripts[gindex] == AF_SCRIPT_LIST_NONE )
    129           gscripts[gindex] = (FT_Byte)ss;
    130 
    131         for (;;)
    132         {
    133           charcode = FT_Get_Next_Char( face, charcode, &gindex );
    134 
    135           if ( gindex == 0 || charcode > range->last )
    136             break;
    137 
    138           if ( gindex < (FT_ULong)globals->glyph_count &&
    139                gscripts[gindex] == AF_SCRIPT_LIST_NONE )
    140             gscripts[gindex] = (FT_Byte)ss;
    141         }
    142       }
    143     }
    144 
    145     /* mark ASCII digits */
    146     for ( i = 0x30; i <= 0x39; i++ )
    147     {
    148       FT_UInt  gindex = FT_Get_Char_Index( face, i );
    149 
    150 
    151       if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count )
    152         gscripts[gindex] |= AF_DIGIT;
    153     }
    154 
    155   Exit:
    156     /*
    157      *  By default, all uncovered glyphs are set to the latin script.
    158      *  XXX: Shouldn't we disable hinting or do something similar?
    159      */
    160     {
    161       FT_Long  nn;
    162 
    163 
    164       for ( nn = 0; nn < globals->glyph_count; nn++ )
    165       {
    166         if ( ( gscripts[nn] & ~AF_DIGIT ) == AF_SCRIPT_LIST_NONE )
    167         {
    168           gscripts[nn] &= ~AF_SCRIPT_LIST_NONE;
    169           gscripts[nn] |= AF_SCRIPT_LIST_DEFAULT;
    170         }
    171       }
    172     }
    173 
    174     FT_Set_Charmap( face, old_charmap );
    175     return error;
    176   }
    177 
    178 
    179   FT_LOCAL_DEF( FT_Error )
    180   af_face_globals_new( FT_Face          face,
    181                        AF_FaceGlobals  *aglobals )
    182   {
    183     FT_Error        error;
    184     FT_Memory       memory;
    185     AF_FaceGlobals  globals = NULL;
    186 
    187 
    188     memory = face->memory;
    189 
    190     if ( !FT_ALLOC( globals, sizeof ( *globals ) +
    191                              face->num_glyphs * sizeof ( FT_Byte ) ) )
    192     {
    193       globals->face          = face;
    194       globals->glyph_count   = face->num_glyphs;
    195       globals->glyph_scripts = (FT_Byte*)( globals + 1 );
    196 
    197       error = af_face_globals_compute_script_coverage( globals );
    198       if ( error )
    199       {
    200         af_face_globals_free( globals );
    201         globals = NULL;
    202       }
    203     }
    204 
    205     *aglobals = globals;
    206     return error;
    207   }
    208 
    209 
    210   FT_LOCAL_DEF( void )
    211   af_face_globals_free( AF_FaceGlobals  globals )
    212   {
    213     if ( globals )
    214     {
    215       FT_Memory  memory = globals->face->memory;
    216       FT_UInt    nn;
    217 
    218 
    219       for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ )
    220       {
    221         if ( globals->metrics[nn] )
    222         {
    223           AF_ScriptClass  clazz = AF_SCRIPT_CLASSES_GET[nn];
    224 
    225 
    226           FT_ASSERT( globals->metrics[nn]->clazz == clazz );
    227 
    228           if ( clazz->script_metrics_done )
    229             clazz->script_metrics_done( globals->metrics[nn] );
    230 
    231           FT_FREE( globals->metrics[nn] );
    232         }
    233       }
    234 
    235       globals->glyph_count   = 0;
    236       globals->glyph_scripts = NULL;  /* no need to free this one! */
    237       globals->face          = NULL;
    238 
    239       FT_FREE( globals );
    240     }
    241   }
    242 
    243 
    244   FT_LOCAL_DEF( FT_Error )
    245   af_face_globals_get_metrics( AF_FaceGlobals     globals,
    246                                FT_UInt            gindex,
    247                                FT_UInt            options,
    248                                AF_ScriptMetrics  *ametrics )
    249   {
    250     AF_ScriptMetrics  metrics = NULL;
    251     FT_UInt           gidx;
    252     AF_ScriptClass    clazz;
    253     FT_UInt           script     = options & 15;
    254     const FT_Offset   script_max = sizeof ( AF_SCRIPT_CLASSES_GET ) /
    255                                      sizeof ( AF_SCRIPT_CLASSES_GET[0] );
    256     FT_Error          error      = AF_Err_Ok;
    257 
    258 
    259     if ( gindex >= (FT_ULong)globals->glyph_count )
    260     {
    261       error = AF_Err_Invalid_Argument;
    262       goto Exit;
    263     }
    264 
    265     gidx = script;
    266     if ( gidx == 0 || gidx + 1 >= script_max )
    267       gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_LIST_NONE;
    268 
    269     clazz = AF_SCRIPT_CLASSES_GET[gidx];
    270     if ( script == 0 )
    271       script = clazz->script;
    272 
    273     metrics = globals->metrics[clazz->script];
    274     if ( metrics == NULL )
    275     {
    276       /* create the global metrics object when needed */
    277       FT_Memory  memory = globals->face->memory;
    278 
    279 
    280       if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
    281         goto Exit;
    282 
    283       metrics->clazz = clazz;
    284 
    285       if ( clazz->script_metrics_init )
    286       {
    287         error = clazz->script_metrics_init( metrics, globals->face );
    288         if ( error )
    289         {
    290           if ( clazz->script_metrics_done )
    291             clazz->script_metrics_done( metrics );
    292 
    293           FT_FREE( metrics );
    294           goto Exit;
    295         }
    296       }
    297 
    298       globals->metrics[clazz->script] = metrics;
    299     }
    300 
    301   Exit:
    302     *ametrics = metrics;
    303 
    304     return error;
    305   }
    306 
    307 
    308   FT_LOCAL_DEF( FT_Bool )
    309   af_face_globals_is_digit( AF_FaceGlobals  globals,
    310                             FT_UInt         gindex )
    311   {
    312     if ( gindex < (FT_ULong)globals->glyph_count )
    313       return (FT_Bool)( globals->glyph_scripts[gindex] & AF_DIGIT );
    314 
    315     return (FT_Bool)0;
    316   }
    317 
    318 
    319 /* END */
    320