1 /***************************************************************************/ 2 /* */ 3 /* afglobal.c */ 4 /* */ 5 /* Auto-fitter routines to compute global hinting values (body). */ 6 /* */ 7 /* Copyright 2003-2014 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 "afranges.h" 21 #include "hbshim.h" 22 #include FT_INTERNAL_DEBUG_H 23 24 25 /*************************************************************************/ 26 /* */ 27 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 28 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 29 /* messages during execution. */ 30 /* */ 31 #undef FT_COMPONENT 32 #define FT_COMPONENT trace_afglobal 33 34 35 /* get writing system specific header files */ 36 #undef WRITING_SYSTEM 37 #define WRITING_SYSTEM( ws, WS ) /* empty */ 38 #include "afwrtsys.h" 39 40 #include "aferrors.h" 41 #include "afpic.h" 42 43 44 #undef SCRIPT 45 #define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) \ 46 AF_DEFINE_SCRIPT_CLASS( \ 47 af_ ## s ## _script_class, \ 48 AF_SCRIPT_ ## S, \ 49 af_ ## s ## _uniranges, \ 50 sc1, sc2, sc3 ) 51 52 #include "afscript.h" 53 54 55 #undef STYLE 56 #define STYLE( s, S, d, ws, sc, ss, c ) \ 57 AF_DEFINE_STYLE_CLASS( \ 58 af_ ## s ## _style_class, \ 59 AF_STYLE_ ## S, \ 60 ws, \ 61 sc, \ 62 ss, \ 63 c ) 64 65 #include "afstyles.h" 66 67 68 #ifndef FT_CONFIG_OPTION_PIC 69 70 #undef WRITING_SYSTEM 71 #define WRITING_SYSTEM( ws, WS ) \ 72 &af_ ## ws ## _writing_system_class, 73 74 FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass ) 75 af_writing_system_classes[] = 76 { 77 78 #include "afwrtsys.h" 79 80 NULL /* do not remove */ 81 }; 82 83 84 #undef SCRIPT 85 #define SCRIPT( s, S, d, h, sc1, sc2, sc3 ) \ 86 &af_ ## s ## _script_class, 87 88 FT_LOCAL_ARRAY_DEF( AF_ScriptClass ) 89 af_script_classes[] = 90 { 91 92 #include "afscript.h" 93 94 NULL /* do not remove */ 95 }; 96 97 98 #undef STYLE 99 #define STYLE( s, S, d, ws, sc, ss, c ) \ 100 &af_ ## s ## _style_class, 101 102 FT_LOCAL_ARRAY_DEF( AF_StyleClass ) 103 af_style_classes[] = 104 { 105 106 #include "afstyles.h" 107 108 NULL /* do not remove */ 109 }; 110 111 #endif /* !FT_CONFIG_OPTION_PIC */ 112 113 114 #ifdef FT_DEBUG_LEVEL_TRACE 115 116 #undef STYLE 117 #define STYLE( s, S, d, ws, sc, ss, c ) #s, 118 119 FT_LOCAL_ARRAY_DEF( char* ) 120 af_style_names[] = 121 { 122 123 #include "afstyles.h" 124 125 }; 126 127 #endif /* FT_DEBUG_LEVEL_TRACE */ 128 129 130 /* Compute the style index of each glyph within a given face. */ 131 132 static FT_Error af_face_globals_compute_style_coverage(AF_FaceGlobals globals)133 af_face_globals_compute_style_coverage( AF_FaceGlobals globals ) 134 { 135 FT_Error error; 136 FT_Face face = globals->face; 137 FT_CharMap old_charmap = face->charmap; 138 FT_Byte* gstyles = globals->glyph_styles; 139 FT_UInt ss; 140 FT_UInt i; 141 FT_UInt dflt = ~0U; /* a non-valid value */ 142 143 144 /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */ 145 FT_MEM_SET( globals->glyph_styles, 146 AF_STYLE_UNASSIGNED, 147 globals->glyph_count ); 148 149 error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); 150 if ( error ) 151 { 152 /* 153 * Ignore this error; we simply use the fallback style. 154 * XXX: Shouldn't we rather disable hinting? 155 */ 156 error = FT_Err_Ok; 157 goto Exit; 158 } 159 160 /* scan each style in a Unicode charmap */ 161 for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) 162 { 163 AF_StyleClass style_class = 164 AF_STYLE_CLASSES_GET[ss]; 165 AF_ScriptClass script_class = 166 AF_SCRIPT_CLASSES_GET[style_class->script]; 167 AF_Script_UniRange range; 168 169 170 if ( script_class->script_uni_ranges == NULL ) 171 continue; 172 173 /* 174 * Scan all Unicode points in the range and set the corresponding 175 * glyph style index. 176 */ 177 if ( style_class->coverage == AF_COVERAGE_DEFAULT ) 178 { 179 if ( (FT_UInt)style_class->script == 180 globals->module->default_script ) 181 dflt = ss; 182 183 for ( range = script_class->script_uni_ranges; 184 range->first != 0; 185 range++ ) 186 { 187 FT_ULong charcode = range->first; 188 FT_UInt gindex; 189 190 191 gindex = FT_Get_Char_Index( face, charcode ); 192 193 if ( gindex != 0 && 194 gindex < (FT_ULong)globals->glyph_count && 195 gstyles[gindex] == AF_STYLE_UNASSIGNED ) 196 gstyles[gindex] = (FT_Byte)ss; 197 198 for (;;) 199 { 200 charcode = FT_Get_Next_Char( face, charcode, &gindex ); 201 202 if ( gindex == 0 || charcode > range->last ) 203 break; 204 205 if ( gindex < (FT_ULong)globals->glyph_count && 206 gstyles[gindex] == AF_STYLE_UNASSIGNED ) 207 gstyles[gindex] = (FT_Byte)ss; 208 } 209 } 210 } 211 else 212 { 213 /* get glyphs not directly addressable by cmap */ 214 af_get_coverage( globals, style_class, gstyles ); 215 } 216 } 217 218 /* handle the default OpenType features of the default script ... */ 219 af_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles ); 220 221 /* ... and the remaining default OpenType features */ 222 for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) 223 { 224 AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; 225 226 227 if ( ss != dflt && style_class->coverage == AF_COVERAGE_DEFAULT ) 228 af_get_coverage( globals, style_class, gstyles ); 229 } 230 231 /* mark ASCII digits */ 232 for ( i = 0x30; i <= 0x39; i++ ) 233 { 234 FT_UInt gindex = FT_Get_Char_Index( face, i ); 235 236 237 if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count ) 238 gstyles[gindex] |= AF_DIGIT; 239 } 240 241 Exit: 242 /* 243 * By default, all uncovered glyphs are set to the fallback style. 244 * XXX: Shouldn't we disable hinting or do something similar? 245 */ 246 if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) 247 { 248 FT_Long nn; 249 250 251 for ( nn = 0; nn < globals->glyph_count; nn++ ) 252 { 253 if ( ( gstyles[nn] & ~AF_DIGIT ) == AF_STYLE_UNASSIGNED ) 254 { 255 gstyles[nn] &= ~AF_STYLE_UNASSIGNED; 256 gstyles[nn] |= globals->module->fallback_style; 257 } 258 } 259 } 260 261 #ifdef FT_DEBUG_LEVEL_TRACE 262 263 FT_TRACE4(( "\n" 264 "style coverage\n" 265 "==============\n" 266 "\n" )); 267 268 for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) 269 { 270 AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; 271 FT_UInt count = 0; 272 FT_Long idx; 273 274 275 FT_TRACE4(( "%s:\n", af_style_names[style_class->style] )); 276 277 for ( idx = 0; idx < globals->glyph_count; idx++ ) 278 { 279 if ( ( gstyles[idx] & ~AF_DIGIT ) == style_class->style ) 280 { 281 if ( !( count % 10 ) ) 282 FT_TRACE4(( " " )); 283 284 FT_TRACE4(( " %d", idx )); 285 count++; 286 287 if ( !( count % 10 ) ) 288 FT_TRACE4(( "\n" )); 289 } 290 } 291 292 if ( !count ) 293 FT_TRACE4(( " (none)\n" )); 294 if ( count % 10 ) 295 FT_TRACE4(( "\n" )); 296 } 297 298 #endif /* FT_DEBUG_LEVEL_TRACE */ 299 300 FT_Set_Charmap( face, old_charmap ); 301 return error; 302 } 303 304 305 FT_LOCAL_DEF( FT_Error ) af_face_globals_new(FT_Face face,AF_FaceGlobals * aglobals,AF_Module module)306 af_face_globals_new( FT_Face face, 307 AF_FaceGlobals *aglobals, 308 AF_Module module ) 309 { 310 FT_Error error; 311 FT_Memory memory; 312 AF_FaceGlobals globals = NULL; 313 314 315 memory = face->memory; 316 317 if ( FT_ALLOC( globals, sizeof ( *globals ) + 318 face->num_glyphs * sizeof ( FT_Byte ) ) ) 319 goto Exit; 320 321 globals->face = face; 322 globals->glyph_count = face->num_glyphs; 323 globals->glyph_styles = (FT_Byte*)( globals + 1 ); 324 globals->module = module; 325 326 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ 327 globals->hb_font = hb_ft_font_create( face, NULL ); 328 #endif 329 330 error = af_face_globals_compute_style_coverage( globals ); 331 if ( error ) 332 { 333 af_face_globals_free( globals ); 334 globals = NULL; 335 } 336 else 337 globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; 338 339 Exit: 340 *aglobals = globals; 341 return error; 342 } 343 344 345 FT_LOCAL_DEF( void ) af_face_globals_free(AF_FaceGlobals globals)346 af_face_globals_free( AF_FaceGlobals globals ) 347 { 348 if ( globals ) 349 { 350 FT_Memory memory = globals->face->memory; 351 FT_UInt nn; 352 353 354 for ( nn = 0; nn < AF_STYLE_MAX; nn++ ) 355 { 356 if ( globals->metrics[nn] ) 357 { 358 AF_StyleClass style_class = 359 AF_STYLE_CLASSES_GET[nn]; 360 AF_WritingSystemClass writing_system_class = 361 AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; 362 363 364 if ( writing_system_class->style_metrics_done ) 365 writing_system_class->style_metrics_done( globals->metrics[nn] ); 366 367 FT_FREE( globals->metrics[nn] ); 368 } 369 } 370 371 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ 372 hb_font_destroy( globals->hb_font ); 373 globals->hb_font = NULL; 374 #endif 375 376 globals->glyph_count = 0; 377 globals->glyph_styles = NULL; /* no need to free this one! */ 378 globals->face = NULL; 379 380 FT_FREE( globals ); 381 } 382 } 383 384 385 FT_LOCAL_DEF( FT_Error ) af_face_globals_get_metrics(AF_FaceGlobals globals,FT_UInt gindex,FT_UInt options,AF_StyleMetrics * ametrics)386 af_face_globals_get_metrics( AF_FaceGlobals globals, 387 FT_UInt gindex, 388 FT_UInt options, 389 AF_StyleMetrics *ametrics ) 390 { 391 AF_StyleMetrics metrics = NULL; 392 393 AF_Style style = (AF_Style)options; 394 AF_WritingSystemClass writing_system_class; 395 AF_StyleClass style_class; 396 397 FT_Error error = FT_Err_Ok; 398 399 400 if ( gindex >= (FT_ULong)globals->glyph_count ) 401 { 402 error = FT_THROW( Invalid_Argument ); 403 goto Exit; 404 } 405 406 /* if we have a forced style (via `options'), use it, */ 407 /* otherwise look into `glyph_styles' array */ 408 if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX ) 409 style = (AF_Style)( globals->glyph_styles[gindex] & 410 AF_STYLE_UNASSIGNED ); 411 412 style_class = AF_STYLE_CLASSES_GET[style]; 413 writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET 414 [style_class->writing_system]; 415 416 metrics = globals->metrics[style]; 417 if ( metrics == NULL ) 418 { 419 /* create the global metrics object if necessary */ 420 FT_Memory memory = globals->face->memory; 421 422 423 if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) ) 424 goto Exit; 425 426 metrics->style_class = style_class; 427 metrics->globals = globals; 428 429 if ( writing_system_class->style_metrics_init ) 430 { 431 error = writing_system_class->style_metrics_init( metrics, 432 globals->face ); 433 if ( error ) 434 { 435 if ( writing_system_class->style_metrics_done ) 436 writing_system_class->style_metrics_done( metrics ); 437 438 FT_FREE( metrics ); 439 goto Exit; 440 } 441 } 442 443 globals->metrics[style] = metrics; 444 } 445 446 Exit: 447 *ametrics = metrics; 448 449 return error; 450 } 451 452 453 FT_LOCAL_DEF( FT_Bool ) af_face_globals_is_digit(AF_FaceGlobals globals,FT_UInt gindex)454 af_face_globals_is_digit( AF_FaceGlobals globals, 455 FT_UInt gindex ) 456 { 457 if ( gindex < (FT_ULong)globals->glyph_count ) 458 return (FT_Bool)( globals->glyph_styles[gindex] & AF_DIGIT ); 459 460 return (FT_Bool)0; 461 } 462 463 464 /* END */ 465