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