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, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 255 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         {
    130           gscripts[gindex] = (FT_Byte)ss;
    131         }
    132 
    133         for (;;)
    134         {
    135           charcode = FT_Get_Next_Char( face, charcode, &gindex );
    136 
    137           if ( gindex == 0 || charcode > range->last )
    138             break;
    139 
    140           if ( gindex < (FT_ULong)globals->glyph_count &&
    141                gscripts[gindex] == AF_SCRIPT_LIST_NONE )
    142           {
    143             gscripts[gindex] = (FT_Byte)ss;
    144           }
    145         }
    146       }
    147     }
    148 
    149     /* mark ASCII digits */
    150     for ( i = 0x30; i <= 0x39; i++ )
    151     {
    152       FT_UInt  gindex = FT_Get_Char_Index( face, i );
    153 
    154 
    155       if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count )
    156         gscripts[gindex] |= AF_DIGIT;
    157     }
    158 
    159   Exit:
    160     /*
    161      *  By default, all uncovered glyphs are set to the latin script.
    162      *  XXX: Shouldn't we disable hinting or do something similar?
    163      */
    164     {
    165       FT_Long  nn;
    166 
    167 
    168       for ( nn = 0; nn < globals->glyph_count; nn++ )
    169       {
    170         if ( ( gscripts[nn] & ~AF_DIGIT ) == AF_SCRIPT_LIST_NONE )
    171         {
    172           gscripts[nn] &= ~AF_SCRIPT_LIST_NONE;
    173           gscripts[nn] |= AF_SCRIPT_LIST_DEFAULT;
    174         }
    175       }
    176     }
    177 
    178     FT_Set_Charmap( face, old_charmap );
    179     return error;
    180   }
    181 
    182 
    183   FT_LOCAL_DEF( FT_Error )
    184   af_face_globals_new( FT_Face          face,
    185                        AF_FaceGlobals  *aglobals )
    186   {
    187     FT_Error        error;
    188     FT_Memory       memory;
    189     AF_FaceGlobals  globals = NULL;
    190 
    191 
    192     memory = face->memory;
    193 
    194     if ( !FT_ALLOC( globals, sizeof ( *globals ) +
    195                              face->num_glyphs * sizeof ( FT_Byte ) ) )
    196     {
    197       globals->face          = face;
    198       globals->glyph_count   = face->num_glyphs;
    199       globals->glyph_scripts = (FT_Byte*)( globals + 1 );
    200 
    201       error = af_face_globals_compute_script_coverage( globals );
    202       if ( error )
    203       {
    204         af_face_globals_free( globals );
    205         globals = NULL;
    206       }
    207     }
    208 
    209     *aglobals = globals;
    210     return error;
    211   }
    212 
    213 
    214   FT_LOCAL_DEF( void )
    215   af_face_globals_free( AF_FaceGlobals  globals )
    216   {
    217     if ( globals )
    218     {
    219       FT_Memory  memory = globals->face->memory;
    220       FT_UInt    nn;
    221 
    222 
    223       for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ )
    224       {
    225         if ( globals->metrics[nn] )
    226         {
    227           AF_ScriptClass  clazz = AF_SCRIPT_CLASSES_GET[nn];
    228 
    229 
    230           FT_ASSERT( globals->metrics[nn]->clazz == clazz );
    231 
    232           if ( clazz->script_metrics_done )
    233             clazz->script_metrics_done( globals->metrics[nn] );
    234 
    235           FT_FREE( globals->metrics[nn] );
    236         }
    237       }
    238 
    239       globals->glyph_count   = 0;
    240       globals->glyph_scripts = NULL;  /* no need to free this one! */
    241       globals->face          = NULL;
    242 
    243       FT_FREE( globals );
    244     }
    245   }
    246 
    247 
    248   FT_LOCAL_DEF( FT_Error )
    249   af_face_globals_get_metrics( AF_FaceGlobals     globals,
    250                                FT_UInt            gindex,
    251                                FT_UInt            options,
    252                                AF_ScriptMetrics  *ametrics )
    253   {
    254     AF_ScriptMetrics  metrics = NULL;
    255     FT_UInt           gidx;
    256     AF_ScriptClass    clazz;
    257     FT_UInt           script     = options & 15;
    258     const FT_Offset   script_max = sizeof ( AF_SCRIPT_CLASSES_GET ) /
    259                                      sizeof ( AF_SCRIPT_CLASSES_GET[0] );
    260     FT_Error          error      = AF_Err_Ok;
    261 
    262 
    263     if ( gindex >= (FT_ULong)globals->glyph_count )
    264     {
    265       error = AF_Err_Invalid_Argument;
    266       goto Exit;
    267     }
    268 
    269     gidx = script;
    270     if ( gidx == 0 || gidx + 1 >= script_max )
    271       gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_LIST_NONE;
    272 
    273     clazz = AF_SCRIPT_CLASSES_GET[gidx];
    274     if ( script == 0 )
    275       script = clazz->script;
    276 
    277     metrics = globals->metrics[clazz->script];
    278     if ( metrics == NULL )
    279     {
    280       /* create the global metrics object when needed */
    281       FT_Memory  memory = globals->face->memory;
    282 
    283 
    284       if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
    285         goto Exit;
    286 
    287       metrics->clazz = clazz;
    288 
    289       if ( clazz->script_metrics_init )
    290       {
    291         error = clazz->script_metrics_init( metrics, globals->face );
    292         if ( error )
    293         {
    294           if ( clazz->script_metrics_done )
    295             clazz->script_metrics_done( metrics );
    296 
    297           FT_FREE( metrics );
    298           goto Exit;
    299         }
    300       }
    301 
    302       globals->metrics[clazz->script] = metrics;
    303     }
    304 
    305   Exit:
    306     *ametrics = metrics;
    307 
    308     return error;
    309   }
    310 
    311 
    312   FT_LOCAL_DEF( FT_Bool )
    313   af_face_globals_is_digit( AF_FaceGlobals  globals,
    314                             FT_UInt         gindex )
    315   {
    316     if ( gindex < (FT_ULong)globals->glyph_count )
    317       return (FT_Bool)( globals->glyph_scripts[gindex] & AF_DIGIT );
    318 
    319     return (FT_Bool)0;
    320   }
    321 
    322 
    323 /* END */
    324