misc/libfreetype/src/autofit/afglobal.c
changeset 5172 88f2e05288ba
equal deleted inserted replaced
5171:f9283dc4860d 5172:88f2e05288ba
       
     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 */