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 af_face_globals_compute_script_coverage(AF_FaceGlobals globals)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 ) af_face_globals_new(FT_Face face,AF_FaceGlobals * aglobals)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 ) af_face_globals_free(AF_FaceGlobals globals)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 ) af_face_globals_get_metrics(AF_FaceGlobals globals,FT_UInt gindex,FT_UInt options,AF_ScriptMetrics * ametrics)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 ) af_face_globals_is_digit(AF_FaceGlobals globals,FT_UInt gindex)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 */ 320