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 = -1; 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 ( style_class->script == globals->module->default_script ) 180 dflt = ss; 181 182 for ( range = script_class->script_uni_ranges; 183 range->first != 0; 184 range++ ) 185 { 186 FT_ULong charcode = range->first; 187 FT_UInt gindex; 188 189 190 gindex = FT_Get_Char_Index( face, charcode ); 191 192 if ( gindex != 0 && 193 gindex < (FT_ULong)globals->glyph_count && 194 gstyles[gindex] == AF_STYLE_UNASSIGNED ) 195 gstyles[gindex] = (FT_Byte)ss; 196 197 for (;;) 198 { 199 charcode = FT_Get_Next_Char( face, charcode, &gindex ); 200 201 if ( gindex == 0 || charcode > range->last ) 202 break; 203 204 if ( gindex < (FT_ULong)globals->glyph_count && 205 gstyles[gindex] == AF_STYLE_UNASSIGNED ) 206 gstyles[gindex] = (FT_Byte)ss; 207 } 208 } 209 } 210 else 211 { 212 /* get glyphs not directly addressable by cmap */ 213 af_get_coverage( globals, style_class, gstyles ); 214 } 215 } 216 217 /* handle the default OpenType features of the default script ... */ 218 af_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles ); 219 220 /* ... and the remaining default OpenType features */ 221 for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) 222 { 223 AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; 224 225 226 if ( ss != dflt && style_class->coverage == AF_COVERAGE_DEFAULT ) 227 af_get_coverage( globals, style_class, gstyles ); 228 } 229 230 /* mark ASCII digits */ 231 for ( i = 0x30; i <= 0x39; i++ ) 232 { 233 FT_UInt gindex = FT_Get_Char_Index( face, i ); 234 235 236 if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count ) 237 gstyles[gindex] |= AF_DIGIT; 238 } 239 240 Exit: 241 /* 242 * By default, all uncovered glyphs are set to the fallback style. 243 * XXX: Shouldn't we disable hinting or do something similar? 244 */ 245 if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) 246 { 247 FT_Long nn; 248 249 250 for ( nn = 0; nn < globals->glyph_count; nn++ ) 251 { 252 if ( ( gstyles[nn] & ~AF_DIGIT ) == AF_STYLE_UNASSIGNED ) 253 { 254 gstyles[nn] &= ~AF_STYLE_UNASSIGNED; 255 gstyles[nn] |= globals->module->fallback_style; 256 } 257 } 258 } 259 260 #ifdef FT_DEBUG_LEVEL_TRACE 261 262 FT_TRACE4(( "\n" 263 "style coverage\n" 264 "==============\n" 265 "\n" )); 266 267 for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) 268 { 269 AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; 270 FT_UInt count = 0; 271 FT_Long idx; 272 273 274 FT_TRACE4(( "%s:\n", af_style_names[style_class->style] )); 275 276 for ( idx = 0; idx < globals->glyph_count; idx++ ) 277 { 278 if ( ( gstyles[idx] & ~AF_DIGIT ) == style_class->style ) 279 { 280 if ( !( count % 10 ) ) 281 FT_TRACE4(( " " )); 282 283 FT_TRACE4(( " %d", idx )); 284 count++; 285 286 if ( !( count % 10 ) ) 287 FT_TRACE4(( "\n" )); 288 } 289 } 290 291 if ( !count ) 292 FT_TRACE4(( " (none)\n" )); 293 if ( count % 10 ) 294 FT_TRACE4(( "\n" )); 295 } 296 297 #endif /* FT_DEBUG_LEVEL_TRACE */ 298 299 FT_Set_Charmap( face, old_charmap ); 300 return error; 301 } 302 303 304 FT_LOCAL_DEF( FT_Error ) af_face_globals_new(FT_Face face,AF_FaceGlobals * aglobals,AF_Module module)305 af_face_globals_new( FT_Face face, 306 AF_FaceGlobals *aglobals, 307 AF_Module module ) 308 { 309 FT_Error error; 310 FT_Memory memory; 311 AF_FaceGlobals globals = NULL; 312 313 314 memory = face->memory; 315 316 if ( FT_ALLOC( globals, sizeof ( *globals ) + 317 face->num_glyphs * sizeof ( FT_Byte ) ) ) 318 goto Exit; 319 320 globals->face = face; 321 globals->glyph_count = face->num_glyphs; 322 globals->glyph_styles = (FT_Byte*)( globals + 1 ); 323 globals->module = module; 324 325 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ 326 globals->hb_font = hb_ft_font_create( face, NULL ); 327 #endif 328 329 error = af_face_globals_compute_style_coverage( globals ); 330 if ( error ) 331 { 332 af_face_globals_free( globals ); 333 globals = NULL; 334 } 335 336 if (globals != NULL) 337 { 338 globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; 339 } 340 341 Exit: 342 *aglobals = globals; 343 return error; 344 } 345 346 347 FT_LOCAL_DEF( void ) af_face_globals_free(AF_FaceGlobals globals)348 af_face_globals_free( AF_FaceGlobals globals ) 349 { 350 if ( globals ) 351 { 352 FT_Memory memory = globals->face->memory; 353 FT_UInt nn; 354 355 356 for ( nn = 0; nn < AF_STYLE_MAX; nn++ ) 357 { 358 if ( globals->metrics[nn] ) 359 { 360 AF_StyleClass style_class = 361 AF_STYLE_CLASSES_GET[nn]; 362 AF_WritingSystemClass writing_system_class = 363 AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; 364 365 366 if ( writing_system_class->style_metrics_done ) 367 writing_system_class->style_metrics_done( globals->metrics[nn] ); 368 369 FT_FREE( globals->metrics[nn] ); 370 } 371 } 372 373 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ 374 hb_font_destroy( globals->hb_font ); 375 globals->hb_font = NULL; 376 #endif 377 378 globals->glyph_count = 0; 379 globals->glyph_styles = NULL; /* no need to free this one! */ 380 globals->face = NULL; 381 382 FT_FREE( globals ); 383 } 384 } 385 386 387 FT_LOCAL_DEF( FT_Error ) af_face_globals_get_metrics(AF_FaceGlobals globals,FT_UInt gindex,FT_UInt options,AF_StyleMetrics * ametrics)388 af_face_globals_get_metrics( AF_FaceGlobals globals, 389 FT_UInt gindex, 390 FT_UInt options, 391 AF_StyleMetrics *ametrics ) 392 { 393 AF_StyleMetrics metrics = NULL; 394 395 AF_Style style = (AF_Style)options; 396 AF_WritingSystemClass writing_system_class; 397 AF_StyleClass style_class; 398 399 FT_Error error = FT_Err_Ok; 400 401 402 if ( gindex >= (FT_ULong)globals->glyph_count ) 403 { 404 error = FT_THROW( Invalid_Argument ); 405 goto Exit; 406 } 407 408 /* if we have a forced style (via `options'), use it, */ 409 /* otherwise look into `glyph_styles' array */ 410 if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX ) 411 style = (AF_Style)( globals->glyph_styles[gindex] & 412 AF_STYLE_UNASSIGNED ); 413 414 style_class = AF_STYLE_CLASSES_GET[style]; 415 writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET 416 [style_class->writing_system]; 417 418 metrics = globals->metrics[style]; 419 if ( metrics == NULL ) 420 { 421 /* create the global metrics object if necessary */ 422 FT_Memory memory = globals->face->memory; 423 424 425 if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) ) 426 goto Exit; 427 428 metrics->style_class = style_class; 429 metrics->globals = globals; 430 431 if ( writing_system_class->style_metrics_init ) 432 { 433 error = writing_system_class->style_metrics_init( metrics, 434 globals->face ); 435 if ( error ) 436 { 437 if ( writing_system_class->style_metrics_done ) 438 writing_system_class->style_metrics_done( metrics ); 439 440 FT_FREE( metrics ); 441 goto Exit; 442 } 443 } 444 445 globals->metrics[style] = metrics; 446 } 447 448 Exit: 449 *ametrics = metrics; 450 451 return error; 452 } 453 454 455 FT_LOCAL_DEF( FT_Bool ) af_face_globals_is_digit(AF_FaceGlobals globals,FT_UInt gindex)456 af_face_globals_is_digit( AF_FaceGlobals globals, 457 FT_UInt gindex ) 458 { 459 if ( gindex < (FT_ULong)globals->glyph_count ) 460 return (FT_Bool)( globals->glyph_styles[gindex] & AF_DIGIT ); 461 462 return (FT_Bool)0; 463 } 464 465 466 /* END */ 467