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 #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 53 /* Compute the script index of each glyph within a given face. */ 54 55 static FT_Error af_face_globals_compute_script_coverage(AF_FaceGlobals globals)56 af_face_globals_compute_script_coverage( AF_FaceGlobals globals ) 57 { 58 FT_Error error; 59 FT_Face face = globals->face; 60 FT_CharMap old_charmap = face->charmap; 61 FT_Byte* gscripts = globals->glyph_scripts; 62 FT_UInt ss; 63 FT_UInt i; 64 65 66 /* the value AF_SCRIPT_NONE means `uncovered glyph' */ 67 FT_MEM_SET( globals->glyph_scripts, 68 AF_SCRIPT_NONE, 69 globals->glyph_count ); 70 71 error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); 72 if ( error ) 73 { 74 /* 75 * Ignore this error; we simply use the fallback script. 76 * XXX: Shouldn't we rather disable hinting? 77 */ 78 error = FT_Err_Ok; 79 goto Exit; 80 } 81 82 /* scan each script in a Unicode charmap */ 83 for ( ss = 0; AF_SCRIPT_CLASSES_GET[ss]; ss++ ) 84 { 85 AF_ScriptClass clazz = AF_SCRIPT_CLASSES_GET[ss]; 86 AF_Script_UniRange range; 87 88 89 if ( clazz->script_uni_ranges == NULL ) 90 continue; 91 92 /* 93 * Scan all Unicode points in the range and set the corresponding 94 * glyph script index. 95 */ 96 for ( range = clazz->script_uni_ranges; range->first != 0; range++ ) 97 { 98 FT_ULong charcode = range->first; 99 FT_UInt gindex; 100 101 102 gindex = FT_Get_Char_Index( face, charcode ); 103 104 if ( gindex != 0 && 105 gindex < (FT_ULong)globals->glyph_count && 106 gscripts[gindex] == AF_SCRIPT_NONE ) 107 gscripts[gindex] = (FT_Byte)ss; 108 109 for (;;) 110 { 111 charcode = FT_Get_Next_Char( face, charcode, &gindex ); 112 113 if ( gindex == 0 || charcode > range->last ) 114 break; 115 116 if ( gindex < (FT_ULong)globals->glyph_count && 117 gscripts[gindex] == AF_SCRIPT_NONE ) 118 gscripts[gindex] = (FT_Byte)ss; 119 } 120 } 121 } 122 123 /* mark ASCII digits */ 124 for ( i = 0x30; i <= 0x39; i++ ) 125 { 126 FT_UInt gindex = FT_Get_Char_Index( face, i ); 127 128 129 if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count ) 130 gscripts[gindex] |= AF_DIGIT; 131 } 132 133 Exit: 134 /* 135 * By default, all uncovered glyphs are set to the fallback script. 136 * XXX: Shouldn't we disable hinting or do something similar? 137 */ 138 if ( globals->module->fallback_script != AF_SCRIPT_NONE ) 139 { 140 FT_Long nn; 141 142 143 for ( nn = 0; nn < globals->glyph_count; nn++ ) 144 { 145 if ( ( gscripts[nn] & ~AF_DIGIT ) == AF_SCRIPT_NONE ) 146 { 147 gscripts[nn] &= ~AF_SCRIPT_NONE; 148 gscripts[nn] |= globals->module->fallback_script; 149 } 150 } 151 } 152 153 FT_Set_Charmap( face, old_charmap ); 154 return error; 155 } 156 157 158 FT_LOCAL_DEF( FT_Error ) af_face_globals_new(FT_Face face,AF_FaceGlobals * aglobals,AF_Module module)159 af_face_globals_new( FT_Face face, 160 AF_FaceGlobals *aglobals, 161 AF_Module module ) 162 { 163 FT_Error error; 164 FT_Memory memory; 165 AF_FaceGlobals globals = NULL; 166 167 168 memory = face->memory; 169 170 if ( FT_ALLOC( globals, sizeof ( *globals ) + 171 face->num_glyphs * sizeof ( FT_Byte ) ) ) 172 goto Exit; 173 174 globals->face = face; 175 globals->glyph_count = face->num_glyphs; 176 globals->glyph_scripts = (FT_Byte*)( globals + 1 ); 177 globals->module = module; 178 179 error = af_face_globals_compute_script_coverage( globals ); 180 if ( error ) 181 { 182 af_face_globals_free( globals ); 183 globals = NULL; 184 } 185 186 globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; 187 188 Exit: 189 *aglobals = globals; 190 return error; 191 } 192 193 194 FT_LOCAL_DEF( void ) af_face_globals_free(AF_FaceGlobals globals)195 af_face_globals_free( AF_FaceGlobals globals ) 196 { 197 if ( globals ) 198 { 199 FT_Memory memory = globals->face->memory; 200 FT_UInt nn; 201 202 203 for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ ) 204 { 205 if ( globals->metrics[nn] ) 206 { 207 AF_ScriptClass clazz = AF_SCRIPT_CLASSES_GET[nn]; 208 209 210 FT_ASSERT( globals->metrics[nn]->clazz == clazz ); 211 212 if ( clazz->script_metrics_done ) 213 clazz->script_metrics_done( globals->metrics[nn] ); 214 215 FT_FREE( globals->metrics[nn] ); 216 } 217 } 218 219 globals->glyph_count = 0; 220 globals->glyph_scripts = NULL; /* no need to free this one! */ 221 globals->face = NULL; 222 223 FT_FREE( globals ); 224 } 225 } 226 227 228 FT_LOCAL_DEF( FT_Error ) af_face_globals_get_metrics(AF_FaceGlobals globals,FT_UInt gindex,FT_UInt options,AF_ScriptMetrics * ametrics)229 af_face_globals_get_metrics( AF_FaceGlobals globals, 230 FT_UInt gindex, 231 FT_UInt options, 232 AF_ScriptMetrics *ametrics ) 233 { 234 AF_ScriptMetrics metrics = NULL; 235 FT_UInt gidx; 236 AF_ScriptClass clazz; 237 FT_UInt script = options & 15; 238 const FT_Offset script_max = sizeof ( AF_SCRIPT_CLASSES_GET ) / 239 sizeof ( AF_SCRIPT_CLASSES_GET[0] ); 240 FT_Error error = FT_Err_Ok; 241 242 243 if ( gindex >= (FT_ULong)globals->glyph_count ) 244 { 245 error = FT_THROW( Invalid_Argument ); 246 goto Exit; 247 } 248 249 gidx = script; 250 if ( gidx == 0 || gidx + 1 >= script_max ) 251 gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_NONE; 252 253 clazz = AF_SCRIPT_CLASSES_GET[gidx]; 254 if ( script == 0 ) 255 script = clazz->script; 256 257 metrics = globals->metrics[clazz->script]; 258 if ( metrics == NULL ) 259 { 260 /* create the global metrics object if necessary */ 261 FT_Memory memory = globals->face->memory; 262 263 264 if ( FT_ALLOC( metrics, clazz->script_metrics_size ) ) 265 goto Exit; 266 267 metrics->clazz = clazz; 268 metrics->globals = globals; 269 270 if ( clazz->script_metrics_init ) 271 { 272 error = clazz->script_metrics_init( metrics, globals->face ); 273 if ( error ) 274 { 275 if ( clazz->script_metrics_done ) 276 clazz->script_metrics_done( metrics ); 277 278 FT_FREE( metrics ); 279 goto Exit; 280 } 281 } 282 283 globals->metrics[clazz->script] = metrics; 284 } 285 286 Exit: 287 *ametrics = metrics; 288 289 return error; 290 } 291 292 293 FT_LOCAL_DEF( FT_Bool ) af_face_globals_is_digit(AF_FaceGlobals globals,FT_UInt gindex)294 af_face_globals_is_digit( AF_FaceGlobals globals, 295 FT_UInt gindex ) 296 { 297 if ( gindex < (FT_ULong)globals->glyph_count ) 298 return (FT_Bool)( globals->glyph_scripts[gindex] & AF_DIGIT ); 299 300 return (FT_Bool)0; 301 } 302 303 304 /* END */ 305