afglobal.c revision aacb8e1368a883fcbc9fe64fd0e460cef9c9b20c
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