• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 
25 #include "aferrors.h"
26 
27 #ifdef FT_OPTION_AUTOFIT2
28 #include "aflatin2.h"
29 #endif
30 
31   /* populate this list when you add new scripts */
32   static AF_ScriptClass const  af_script_classes[] =
33   {
34     &af_dummy_script_class,
35 #ifdef FT_OPTION_AUTOFIT2
36     &af_latin2_script_class,
37 #endif
38     &af_latin_script_class,
39     &af_cjk_script_class,
40     &af_indic_script_class,
41     NULL  /* do not remove */
42   };
43 
44   /* index of default script in `af_script_classes' */
45 #define AF_SCRIPT_LIST_DEFAULT  2
46   /* indicates an uncovered glyph                   */
47 #define AF_SCRIPT_LIST_NONE   255
48 
49 
50   /*
51    *  Note that glyph_scripts[] is used to map each glyph into
52    *  an index into the `af_script_classes' array.
53    *
54    */
55   typedef struct  AF_FaceGlobalsRec_
56   {
57     FT_Face           face;
58     FT_UInt           glyph_count;    /* same as face->num_glyphs */
59     FT_Byte*          glyph_scripts;
60 
61     AF_ScriptMetrics  metrics[AF_SCRIPT_MAX];
62 
63   } AF_FaceGlobalsRec;
64 
65 
66   /* Compute the script index of each glyph within a given face. */
67 
68   static FT_Error
af_face_globals_compute_script_coverage(AF_FaceGlobals globals)69   af_face_globals_compute_script_coverage( AF_FaceGlobals  globals )
70   {
71     FT_Error    error       = AF_Err_Ok;
72     FT_Face     face        = globals->face;
73     FT_CharMap  old_charmap = face->charmap;
74     FT_Byte*    gscripts    = globals->glyph_scripts;
75     FT_UInt     ss;
76 
77 
78     /* the value 255 means `uncovered glyph' */
79     FT_MEM_SET( globals->glyph_scripts,
80                 AF_SCRIPT_LIST_NONE,
81                 globals->glyph_count );
82 
83     error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
84     if ( error )
85     {
86      /*
87       *  Ignore this error; we simply use the default script.
88       *  XXX: Shouldn't we rather disable hinting?
89       */
90       error = AF_Err_Ok;
91       goto Exit;
92     }
93 
94     /* scan each script in a Unicode charmap */
95     for ( ss = 0; af_script_classes[ss]; ss++ )
96     {
97       AF_ScriptClass      clazz = af_script_classes[ss];
98       AF_Script_UniRange  range;
99 
100 
101       if ( clazz->script_uni_ranges == NULL )
102         continue;
103 
104       /*
105        *  Scan all unicode points in the range and set the corresponding
106        *  glyph script index.
107        */
108       for ( range = clazz->script_uni_ranges; range->first != 0; range++ )
109       {
110         FT_ULong  charcode = range->first;
111         FT_UInt   gindex;
112 
113 
114         gindex = FT_Get_Char_Index( face, charcode );
115 
116         if ( gindex != 0                             &&
117              gindex < globals->glyph_count           &&
118              gscripts[gindex] == AF_SCRIPT_LIST_NONE )
119         {
120           gscripts[gindex] = (FT_Byte)ss;
121         }
122 
123         for (;;)
124         {
125           charcode = FT_Get_Next_Char( face, charcode, &gindex );
126 
127           if ( gindex == 0 || charcode > range->last )
128             break;
129 
130           if ( gindex < globals->glyph_count           &&
131                gscripts[gindex] == AF_SCRIPT_LIST_NONE )
132           {
133             gscripts[gindex] = (FT_Byte)ss;
134           }
135         }
136       }
137     }
138 
139   Exit:
140     /*
141      *  By default, all uncovered glyphs are set to the latin script.
142      *  XXX: Shouldn't we disable hinting or do something similar?
143      */
144     {
145       FT_UInt  nn;
146 
147 
148       for ( nn = 0; nn < globals->glyph_count; nn++ )
149       {
150         if ( gscripts[nn] == AF_SCRIPT_LIST_NONE )
151           gscripts[nn] = AF_SCRIPT_LIST_DEFAULT;
152       }
153     }
154 
155     FT_Set_Charmap( face, old_charmap );
156     return error;
157   }
158 
159 
160   FT_LOCAL_DEF( FT_Error )
af_face_globals_new(FT_Face face,AF_FaceGlobals * aglobals)161   af_face_globals_new( FT_Face          face,
162                        AF_FaceGlobals  *aglobals )
163   {
164     FT_Error        error;
165     FT_Memory       memory;
166     AF_FaceGlobals  globals;
167 
168 
169     memory = face->memory;
170 
171     if ( !FT_ALLOC( globals, sizeof ( *globals ) +
172                              face->num_glyphs * sizeof ( FT_Byte ) ) )
173     {
174       globals->face          = face;
175       globals->glyph_count   = face->num_glyphs;
176       globals->glyph_scripts = (FT_Byte*)( globals + 1 );
177 
178       error = af_face_globals_compute_script_coverage( globals );
179       if ( error )
180       {
181         af_face_globals_free( globals );
182         globals = NULL;
183       }
184     }
185 
186     *aglobals = globals;
187     return error;
188   }
189 
190 
191   FT_LOCAL_DEF( void )
af_face_globals_free(AF_FaceGlobals globals)192   af_face_globals_free( AF_FaceGlobals  globals )
193   {
194     if ( globals )
195     {
196       FT_Memory  memory = globals->face->memory;
197       FT_UInt    nn;
198 
199 
200       for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ )
201       {
202         if ( globals->metrics[nn] )
203         {
204           AF_ScriptClass  clazz = af_script_classes[nn];
205 
206 
207           FT_ASSERT( globals->metrics[nn]->clazz == clazz );
208 
209           if ( clazz->script_metrics_done )
210             clazz->script_metrics_done( globals->metrics[nn] );
211 
212           FT_FREE( globals->metrics[nn] );
213         }
214       }
215 
216       globals->glyph_count   = 0;
217       globals->glyph_scripts = NULL;  /* no need to free this one! */
218       globals->face          = NULL;
219 
220       FT_FREE( globals );
221     }
222   }
223 
224 
225   FT_LOCAL_DEF( FT_Error )
af_face_globals_get_metrics(AF_FaceGlobals globals,FT_UInt gindex,FT_UInt options,AF_ScriptMetrics * ametrics)226   af_face_globals_get_metrics( AF_FaceGlobals     globals,
227                                FT_UInt            gindex,
228                                FT_UInt            options,
229                                AF_ScriptMetrics  *ametrics )
230   {
231     AF_ScriptMetrics  metrics = NULL;
232     FT_UInt           gidx;
233     AF_ScriptClass    clazz;
234     FT_UInt           script     = options & 15;
235     const FT_UInt     script_max = sizeof ( af_script_classes ) /
236                                      sizeof ( af_script_classes[0] );
237     FT_Error          error      = AF_Err_Ok;
238 
239 
240     if ( gindex >= globals->glyph_count )
241     {
242       error = AF_Err_Invalid_Argument;
243       goto Exit;
244     }
245 
246     gidx = script;
247     if ( gidx == 0 || gidx + 1 >= script_max )
248       gidx = globals->glyph_scripts[gindex];
249 
250     clazz = af_script_classes[gidx];
251     if ( script == 0 )
252       script = clazz->script;
253 
254     metrics = globals->metrics[clazz->script];
255     if ( metrics == NULL )
256     {
257       /* create the global metrics object when needed */
258       FT_Memory  memory = globals->face->memory;
259 
260 
261       if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
262         goto Exit;
263 
264       metrics->clazz = clazz;
265 
266       if ( clazz->script_metrics_init )
267       {
268         error = clazz->script_metrics_init( metrics, globals->face );
269         if ( error )
270         {
271           if ( clazz->script_metrics_done )
272             clazz->script_metrics_done( metrics );
273 
274           FT_FREE( metrics );
275           goto Exit;
276         }
277       }
278 
279       globals->metrics[clazz->script] = metrics;
280     }
281 
282   Exit:
283     *ametrics = metrics;
284 
285     return error;
286   }
287 
288 
289 /* END */
290