1 /***************************************************************************/ 2 /* */ 3 /* afglobal.c */ 4 /* */ 5 /* Auto-fitter routines to compute global hinting values (body). */ 6 /* */ 7 /* Copyright 2003-2015 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 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 ) 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, 318 sizeof ( *globals ) + 319 (FT_ULong)face->num_glyphs * sizeof ( FT_Byte ) ) ) 320 goto Exit; 321 322 globals->face = face; 323 globals->glyph_count = face->num_glyphs; 324 globals->glyph_styles = (FT_Byte*)( globals + 1 ); 325 globals->module = module; 326 327 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ 328 globals->hb_font = hb_ft_font_create( face, NULL ); 329 #endif 330 331 error = af_face_globals_compute_style_coverage( globals ); 332 if ( error ) 333 { 334 af_face_globals_free( globals ); 335 globals = NULL; 336 } 337 else 338 globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; 339 340 Exit: 341 *aglobals = globals; 342 return error; 343 } 344 345 346 FT_LOCAL_DEF( void ) 347 af_face_globals_free( AF_FaceGlobals globals ) 348 { 349 if ( globals ) 350 { 351 FT_Memory memory = globals->face->memory; 352 FT_UInt nn; 353 354 355 for ( nn = 0; nn < AF_STYLE_MAX; nn++ ) 356 { 357 if ( globals->metrics[nn] ) 358 { 359 AF_StyleClass style_class = 360 AF_STYLE_CLASSES_GET[nn]; 361 AF_WritingSystemClass writing_system_class = 362 AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; 363 364 365 if ( writing_system_class->style_metrics_done ) 366 writing_system_class->style_metrics_done( globals->metrics[nn] ); 367 368 FT_FREE( globals->metrics[nn] ); 369 } 370 } 371 372 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ 373 hb_font_destroy( globals->hb_font ); 374 globals->hb_font = NULL; 375 #endif 376 377 globals->glyph_count = 0; 378 globals->glyph_styles = NULL; /* no need to free this one! */ 379 globals->face = NULL; 380 381 FT_FREE( globals ); 382 } 383 } 384 385 386 FT_LOCAL_DEF( FT_Error ) 387 af_face_globals_get_metrics( AF_FaceGlobals globals, 388 FT_UInt gindex, 389 FT_UInt options, 390 AF_StyleMetrics *ametrics ) 391 { 392 AF_StyleMetrics metrics = NULL; 393 394 AF_Style style = (AF_Style)options; 395 AF_WritingSystemClass writing_system_class; 396 AF_StyleClass style_class; 397 398 FT_Error error = FT_Err_Ok; 399 400 401 if ( gindex >= (FT_ULong)globals->glyph_count ) 402 { 403 error = FT_THROW( Invalid_Argument ); 404 goto Exit; 405 } 406 407 /* if we have a forced style (via `options'), use it, */ 408 /* otherwise look into `glyph_styles' array */ 409 if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX ) 410 style = (AF_Style)( globals->glyph_styles[gindex] & 411 AF_STYLE_UNASSIGNED ); 412 413 style_class = AF_STYLE_CLASSES_GET[style]; 414 writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET 415 [style_class->writing_system]; 416 417 metrics = globals->metrics[style]; 418 if ( metrics == NULL ) 419 { 420 /* create the global metrics object if necessary */ 421 FT_Memory memory = globals->face->memory; 422 423 424 if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) ) 425 goto Exit; 426 427 metrics->style_class = style_class; 428 metrics->globals = globals; 429 430 if ( writing_system_class->style_metrics_init ) 431 { 432 error = writing_system_class->style_metrics_init( metrics, 433 globals->face ); 434 if ( error ) 435 { 436 if ( writing_system_class->style_metrics_done ) 437 writing_system_class->style_metrics_done( metrics ); 438 439 FT_FREE( metrics ); 440 goto Exit; 441 } 442 } 443 444 globals->metrics[style] = metrics; 445 } 446 447 Exit: 448 *ametrics = metrics; 449 450 return error; 451 } 452 453 454 FT_LOCAL_DEF( FT_Bool ) 455 af_face_globals_is_digit( AF_FaceGlobals globals, 456 FT_UInt gindex ) 457 { 458 if ( gindex < (FT_ULong)globals->glyph_count ) 459 return (FT_Bool)( globals->glyph_styles[gindex] & AF_DIGIT ); 460 461 return (FT_Bool)0; 462 } 463 464 465 /* END */ 466