Tizen 2.0 Release
[framework/graphics/freetype.git] / src / autofit / afglobal.c
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 */