| 1 | /***************************************************************************/ |
| 2 | /* */ |
| 3 | /* ttpost.c */ |
| 4 | /* */ |
| 5 | /* PostScript name table processing for TrueType and OpenType fonts */ |
| 6 | /* (body). */ |
| 7 | /* */ |
| 8 | /* Copyright 1996-2018 by */ |
| 9 | /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
| 10 | /* */ |
| 11 | /* This file is part of the FreeType project, and may only be used, */ |
| 12 | /* modified, and distributed under the terms of the FreeType project */ |
| 13 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
| 14 | /* this file you indicate that you have read the license and */ |
| 15 | /* understand and accept it fully. */ |
| 16 | /* */ |
| 17 | /***************************************************************************/ |
| 18 | |
| 19 | /*************************************************************************/ |
| 20 | /* */ |
| 21 | /* The post table is not completely loaded by the core engine. This */ |
| 22 | /* file loads the missing PS glyph names and implements an API to access */ |
| 23 | /* them. */ |
| 24 | /* */ |
| 25 | /*************************************************************************/ |
| 26 | |
| 27 | |
| 28 | #include <ft2build.h> |
| 29 | #include FT_INTERNAL_DEBUG_H |
| 30 | #include FT_INTERNAL_STREAM_H |
| 31 | #include FT_TRUETYPE_TAGS_H |
| 32 | |
| 33 | |
| 34 | #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES |
| 35 | |
| 36 | #include "ttpost.h" |
| 37 | |
| 38 | #include "sferrors.h" |
| 39 | |
| 40 | |
| 41 | /*************************************************************************/ |
| 42 | /* */ |
| 43 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
| 44 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
| 45 | /* messages during execution. */ |
| 46 | /* */ |
| 47 | #undef FT_COMPONENT |
| 48 | #define FT_COMPONENT trace_ttpost |
| 49 | |
| 50 | |
| 51 | /* If this configuration macro is defined, we rely on the `PSNames' */ |
| 52 | /* module to grab the glyph names. */ |
| 53 | |
| 54 | #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES |
| 55 | |
| 56 | |
| 57 | #include FT_SERVICE_POSTSCRIPT_CMAPS_H |
| 58 | |
| 59 | #define MAC_NAME( x ) (FT_String*)psnames->macintosh_name( (FT_UInt)(x) ) |
| 60 | |
| 61 | |
| 62 | #else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ |
| 63 | |
| 64 | |
| 65 | /* Otherwise, we ignore the `PSNames' module, and provide our own */ |
| 66 | /* table of Mac names. Thus, it is possible to build a version of */ |
| 67 | /* FreeType without the Type 1 driver & PSNames module. */ |
| 68 | |
| 69 | #define MAC_NAME( x ) (FT_String*)tt_post_default_names[x] |
| 70 | |
| 71 | /* the 258 default Mac PS glyph names; see file `tools/glnames.py' */ |
| 72 | |
| 73 | static const FT_String* const tt_post_default_names[258] = |
| 74 | { |
| 75 | /* 0 */ |
| 76 | ".notdef" , ".null" , "nonmarkingreturn" , "space" , "exclam" , |
| 77 | "quotedbl" , "numbersign" , "dollar" , "percent" , "ampersand" , |
| 78 | /* 10 */ |
| 79 | "quotesingle" , "parenleft" , "parenright" , "asterisk" , "plus" , |
| 80 | "comma" , "hyphen" , "period" , "slash" , "zero" , |
| 81 | /* 20 */ |
| 82 | "one" , "two" , "three" , "four" , "five" , |
| 83 | "six" , "seven" , "eight" , "nine" , "colon" , |
| 84 | /* 30 */ |
| 85 | "semicolon" , "less" , "equal" , "greater" , "question" , |
| 86 | "at" , "A" , "B" , "C" , "D" , |
| 87 | /* 40 */ |
| 88 | "E" , "F" , "G" , "H" , "I" , |
| 89 | "J" , "K" , "L" , "M" , "N" , |
| 90 | /* 50 */ |
| 91 | "O" , "P" , "Q" , "R" , "S" , |
| 92 | "T" , "U" , "V" , "W" , "X" , |
| 93 | /* 60 */ |
| 94 | "Y" , "Z" , "bracketleft" , "backslash" , "bracketright" , |
| 95 | "asciicircum" , "underscore" , "grave" , "a" , "b" , |
| 96 | /* 70 */ |
| 97 | "c" , "d" , "e" , "f" , "g" , |
| 98 | "h" , "i" , "j" , "k" , "l" , |
| 99 | /* 80 */ |
| 100 | "m" , "n" , "o" , "p" , "q" , |
| 101 | "r" , "s" , "t" , "u" , "v" , |
| 102 | /* 90 */ |
| 103 | "w" , "x" , "y" , "z" , "braceleft" , |
| 104 | "bar" , "braceright" , "asciitilde" , "Adieresis" , "Aring" , |
| 105 | /* 100 */ |
| 106 | "Ccedilla" , "Eacute" , "Ntilde" , "Odieresis" , "Udieresis" , |
| 107 | "aacute" , "agrave" , "acircumflex" , "adieresis" , "atilde" , |
| 108 | /* 110 */ |
| 109 | "aring" , "ccedilla" , "eacute" , "egrave" , "ecircumflex" , |
| 110 | "edieresis" , "iacute" , "igrave" , "icircumflex" , "idieresis" , |
| 111 | /* 120 */ |
| 112 | "ntilde" , "oacute" , "ograve" , "ocircumflex" , "odieresis" , |
| 113 | "otilde" , "uacute" , "ugrave" , "ucircumflex" , "udieresis" , |
| 114 | /* 130 */ |
| 115 | "dagger" , "degree" , "cent" , "sterling" , "section" , |
| 116 | "bullet" , "paragraph" , "germandbls" , "registered" , "copyright" , |
| 117 | /* 140 */ |
| 118 | "trademark" , "acute" , "dieresis" , "notequal" , "AE" , |
| 119 | "Oslash" , "infinity" , "plusminus" , "lessequal" , "greaterequal" , |
| 120 | /* 150 */ |
| 121 | "yen" , "mu" , "partialdiff" , "summation" , "product" , |
| 122 | "pi" , "integral" , "ordfeminine" , "ordmasculine" , "Omega" , |
| 123 | /* 160 */ |
| 124 | "ae" , "oslash" , "questiondown" , "exclamdown" , "logicalnot" , |
| 125 | "radical" , "florin" , "approxequal" , "Delta" , "guillemotleft" , |
| 126 | /* 170 */ |
| 127 | "guillemotright" , "ellipsis" , "nonbreakingspace" , "Agrave" , "Atilde" , |
| 128 | "Otilde" , "OE" , "oe" , "endash" , "emdash" , |
| 129 | /* 180 */ |
| 130 | "quotedblleft" , "quotedblright" , "quoteleft" , "quoteright" , "divide" , |
| 131 | "lozenge" , "ydieresis" , "Ydieresis" , "fraction" , "currency" , |
| 132 | /* 190 */ |
| 133 | "guilsinglleft" , "guilsinglright" , "fi" , "fl" , "daggerdbl" , |
| 134 | "periodcentered" , "quotesinglbase" , "quotedblbase" , "perthousand" , "Acircumflex" , |
| 135 | /* 200 */ |
| 136 | "Ecircumflex" , "Aacute" , "Edieresis" , "Egrave" , "Iacute" , |
| 137 | "Icircumflex" , "Idieresis" , "Igrave" , "Oacute" , "Ocircumflex" , |
| 138 | /* 210 */ |
| 139 | "apple" , "Ograve" , "Uacute" , "Ucircumflex" , "Ugrave" , |
| 140 | "dotlessi" , "circumflex" , "tilde" , "macron" , "breve" , |
| 141 | /* 220 */ |
| 142 | "dotaccent" , "ring" , "cedilla" , "hungarumlaut" , "ogonek" , |
| 143 | "caron" , "Lslash" , "lslash" , "Scaron" , "scaron" , |
| 144 | /* 230 */ |
| 145 | "Zcaron" , "zcaron" , "brokenbar" , "Eth" , "eth" , |
| 146 | "Yacute" , "yacute" , "Thorn" , "thorn" , "minus" , |
| 147 | /* 240 */ |
| 148 | "multiply" , "onesuperior" , "twosuperior" , "threesuperior" , "onehalf" , |
| 149 | "onequarter" , "threequarters" , "franc" , "Gbreve" , "gbreve" , |
| 150 | /* 250 */ |
| 151 | "Idotaccent" , "Scedilla" , "scedilla" , "Cacute" , "cacute" , |
| 152 | "Ccaron" , "ccaron" , "dcroat" , |
| 153 | }; |
| 154 | |
| 155 | |
| 156 | #endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ |
| 157 | |
| 158 | |
| 159 | static FT_Error |
| 160 | load_format_20( TT_Face face, |
| 161 | FT_Stream stream, |
| 162 | FT_ULong post_limit ) |
| 163 | { |
| 164 | FT_Memory memory = stream->memory; |
| 165 | FT_Error error; |
| 166 | |
| 167 | FT_Int num_glyphs; |
| 168 | FT_UShort num_names; |
| 169 | |
| 170 | FT_UShort* glyph_indices = NULL; |
| 171 | FT_Char** name_strings = NULL; |
| 172 | |
| 173 | |
| 174 | if ( FT_READ_USHORT( num_glyphs ) ) |
| 175 | goto Exit; |
| 176 | |
| 177 | /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ |
| 178 | /* than the value in the maxp table (cf. cyberbit.ttf). */ |
| 179 | |
| 180 | /* There already exist fonts which have more than 32768 glyph names */ |
| 181 | /* in this table, so the test for this threshold has been dropped. */ |
| 182 | |
| 183 | if ( num_glyphs > face->max_profile.numGlyphs ) |
| 184 | { |
| 185 | error = FT_THROW( Invalid_File_Format ); |
| 186 | goto Exit; |
| 187 | } |
| 188 | |
| 189 | /* load the indices */ |
| 190 | { |
| 191 | FT_Int n; |
| 192 | |
| 193 | |
| 194 | if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || |
| 195 | FT_FRAME_ENTER( num_glyphs * 2L ) ) |
| 196 | goto Fail; |
| 197 | |
| 198 | for ( n = 0; n < num_glyphs; n++ ) |
| 199 | glyph_indices[n] = FT_GET_USHORT(); |
| 200 | |
| 201 | FT_FRAME_EXIT(); |
| 202 | } |
| 203 | |
| 204 | /* compute number of names stored in table */ |
| 205 | { |
| 206 | FT_Int n; |
| 207 | |
| 208 | |
| 209 | num_names = 0; |
| 210 | |
| 211 | for ( n = 0; n < num_glyphs; n++ ) |
| 212 | { |
| 213 | FT_Int idx; |
| 214 | |
| 215 | |
| 216 | idx = glyph_indices[n]; |
| 217 | if ( idx >= 258 ) |
| 218 | { |
| 219 | idx -= 257; |
| 220 | if ( idx > num_names ) |
| 221 | num_names = (FT_UShort)idx; |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | /* now load the name strings */ |
| 227 | { |
| 228 | FT_UShort n; |
| 229 | |
| 230 | |
| 231 | if ( FT_NEW_ARRAY( name_strings, num_names ) ) |
| 232 | goto Fail; |
| 233 | |
| 234 | for ( n = 0; n < num_names; n++ ) |
| 235 | { |
| 236 | FT_UInt len; |
| 237 | |
| 238 | |
| 239 | if ( FT_STREAM_POS() >= post_limit ) |
| 240 | break; |
| 241 | else |
| 242 | { |
| 243 | FT_TRACE6(( "load_format_20: %d byte left in post table\n" , |
| 244 | post_limit - FT_STREAM_POS() )); |
| 245 | |
| 246 | if ( FT_READ_BYTE( len ) ) |
| 247 | goto Fail1; |
| 248 | } |
| 249 | |
| 250 | if ( len > post_limit || |
| 251 | FT_STREAM_POS() > post_limit - len ) |
| 252 | { |
| 253 | FT_Int d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS(); |
| 254 | |
| 255 | |
| 256 | FT_ERROR(( "load_format_20:" |
| 257 | " exceeding string length (%d)," |
| 258 | " truncating at end of post table (%d byte left)\n" , |
| 259 | len, d )); |
| 260 | len = (FT_UInt)FT_MAX( 0, d ); |
| 261 | } |
| 262 | |
| 263 | if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || |
| 264 | FT_STREAM_READ( name_strings[n], len ) ) |
| 265 | goto Fail1; |
| 266 | |
| 267 | name_strings[n][len] = '\0'; |
| 268 | } |
| 269 | |
| 270 | if ( n < num_names ) |
| 271 | { |
| 272 | FT_ERROR(( "load_format_20:" |
| 273 | " all entries in post table are already parsed," |
| 274 | " using NULL names for gid %d - %d\n" , |
| 275 | n, num_names - 1 )); |
| 276 | for ( ; n < num_names; n++ ) |
| 277 | if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) |
| 278 | goto Fail1; |
| 279 | else |
| 280 | name_strings[n][0] = '\0'; |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | /* all right, set table fields and exit successfully */ |
| 285 | { |
| 286 | TT_Post_20 table = &face->postscript_names.names.format_20; |
| 287 | |
| 288 | |
| 289 | table->num_glyphs = (FT_UShort)num_glyphs; |
| 290 | table->num_names = (FT_UShort)num_names; |
| 291 | table->glyph_indices = glyph_indices; |
| 292 | table->glyph_names = name_strings; |
| 293 | } |
| 294 | return FT_Err_Ok; |
| 295 | |
| 296 | Fail1: |
| 297 | { |
| 298 | FT_UShort n; |
| 299 | |
| 300 | |
| 301 | for ( n = 0; n < num_names; n++ ) |
| 302 | FT_FREE( name_strings[n] ); |
| 303 | } |
| 304 | |
| 305 | Fail: |
| 306 | FT_FREE( name_strings ); |
| 307 | FT_FREE( glyph_indices ); |
| 308 | |
| 309 | Exit: |
| 310 | return error; |
| 311 | } |
| 312 | |
| 313 | |
| 314 | static FT_Error |
| 315 | load_format_25( TT_Face face, |
| 316 | FT_Stream stream, |
| 317 | FT_ULong post_limit ) |
| 318 | { |
| 319 | FT_Memory memory = stream->memory; |
| 320 | FT_Error error; |
| 321 | |
| 322 | FT_Int num_glyphs; |
| 323 | FT_Char* offset_table = NULL; |
| 324 | |
| 325 | FT_UNUSED( post_limit ); |
| 326 | |
| 327 | |
| 328 | if ( FT_READ_USHORT( num_glyphs ) ) |
| 329 | goto Exit; |
| 330 | |
| 331 | /* check the number of glyphs */ |
| 332 | if ( num_glyphs > face->max_profile.numGlyphs || |
| 333 | num_glyphs > 258 || |
| 334 | num_glyphs < 1 ) |
| 335 | { |
| 336 | error = FT_THROW( Invalid_File_Format ); |
| 337 | goto Exit; |
| 338 | } |
| 339 | |
| 340 | if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || |
| 341 | FT_STREAM_READ( offset_table, num_glyphs ) ) |
| 342 | goto Fail; |
| 343 | |
| 344 | /* now check the offset table */ |
| 345 | { |
| 346 | FT_Int n; |
| 347 | |
| 348 | |
| 349 | for ( n = 0; n < num_glyphs; n++ ) |
| 350 | { |
| 351 | FT_Long idx = (FT_Long)n + offset_table[n]; |
| 352 | |
| 353 | |
| 354 | if ( idx < 0 || idx > num_glyphs ) |
| 355 | { |
| 356 | error = FT_THROW( Invalid_File_Format ); |
| 357 | goto Fail; |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | /* OK, set table fields and exit successfully */ |
| 363 | { |
| 364 | TT_Post_25 table = &face->postscript_names.names.format_25; |
| 365 | |
| 366 | |
| 367 | table->num_glyphs = (FT_UShort)num_glyphs; |
| 368 | table->offsets = offset_table; |
| 369 | } |
| 370 | |
| 371 | return FT_Err_Ok; |
| 372 | |
| 373 | Fail: |
| 374 | FT_FREE( offset_table ); |
| 375 | |
| 376 | Exit: |
| 377 | return error; |
| 378 | } |
| 379 | |
| 380 | |
| 381 | static FT_Error |
| 382 | load_post_names( TT_Face face ) |
| 383 | { |
| 384 | FT_Stream stream; |
| 385 | FT_Error error; |
| 386 | FT_Fixed format; |
| 387 | FT_ULong post_len; |
| 388 | FT_ULong post_limit; |
| 389 | |
| 390 | |
| 391 | /* get a stream for the face's resource */ |
| 392 | stream = face->root.stream; |
| 393 | |
| 394 | /* seek to the beginning of the PS names table */ |
| 395 | error = face->goto_table( face, TTAG_post, stream, &post_len ); |
| 396 | if ( error ) |
| 397 | goto Exit; |
| 398 | |
| 399 | post_limit = FT_STREAM_POS() + post_len; |
| 400 | |
| 401 | format = face->postscript.FormatType; |
| 402 | |
| 403 | /* go to beginning of subtable */ |
| 404 | if ( FT_STREAM_SKIP( 32 ) ) |
| 405 | goto Exit; |
| 406 | |
| 407 | /* now read postscript table */ |
| 408 | if ( format == 0x00020000L ) |
| 409 | error = load_format_20( face, stream, post_limit ); |
| 410 | else if ( format == 0x00025000L ) |
| 411 | error = load_format_25( face, stream, post_limit ); |
| 412 | else |
| 413 | error = FT_THROW( Invalid_File_Format ); |
| 414 | |
| 415 | face->postscript_names.loaded = 1; |
| 416 | |
| 417 | Exit: |
| 418 | return error; |
| 419 | } |
| 420 | |
| 421 | |
| 422 | FT_LOCAL_DEF( void ) |
| 423 | tt_face_free_ps_names( TT_Face face ) |
| 424 | { |
| 425 | FT_Memory memory = face->root.memory; |
| 426 | TT_Post_Names names = &face->postscript_names; |
| 427 | FT_Fixed format; |
| 428 | |
| 429 | |
| 430 | if ( names->loaded ) |
| 431 | { |
| 432 | format = face->postscript.FormatType; |
| 433 | |
| 434 | if ( format == 0x00020000L ) |
| 435 | { |
| 436 | TT_Post_20 table = &names->names.format_20; |
| 437 | FT_UShort n; |
| 438 | |
| 439 | |
| 440 | FT_FREE( table->glyph_indices ); |
| 441 | table->num_glyphs = 0; |
| 442 | |
| 443 | for ( n = 0; n < table->num_names; n++ ) |
| 444 | FT_FREE( table->glyph_names[n] ); |
| 445 | |
| 446 | FT_FREE( table->glyph_names ); |
| 447 | table->num_names = 0; |
| 448 | } |
| 449 | else if ( format == 0x00025000L ) |
| 450 | { |
| 451 | TT_Post_25 table = &names->names.format_25; |
| 452 | |
| 453 | |
| 454 | FT_FREE( table->offsets ); |
| 455 | table->num_glyphs = 0; |
| 456 | } |
| 457 | } |
| 458 | names->loaded = 0; |
| 459 | } |
| 460 | |
| 461 | |
| 462 | /*************************************************************************/ |
| 463 | /* */ |
| 464 | /* <Function> */ |
| 465 | /* tt_face_get_ps_name */ |
| 466 | /* */ |
| 467 | /* <Description> */ |
| 468 | /* Get the PostScript glyph name of a glyph. */ |
| 469 | /* */ |
| 470 | /* <Input> */ |
| 471 | /* face :: A handle to the parent face. */ |
| 472 | /* */ |
| 473 | /* idx :: The glyph index. */ |
| 474 | /* */ |
| 475 | /* <InOut> */ |
| 476 | /* PSname :: The address of a string pointer. Undefined in case of */ |
| 477 | /* error, otherwise it is a pointer to the glyph name. */ |
| 478 | /* */ |
| 479 | /* You must not modify the returned string! */ |
| 480 | /* */ |
| 481 | /* <Output> */ |
| 482 | /* FreeType error code. 0 means success. */ |
| 483 | /* */ |
| 484 | FT_LOCAL_DEF( FT_Error ) |
| 485 | tt_face_get_ps_name( TT_Face face, |
| 486 | FT_UInt idx, |
| 487 | FT_String** PSname ) |
| 488 | { |
| 489 | FT_Error error; |
| 490 | TT_Post_Names names; |
| 491 | FT_Fixed format; |
| 492 | |
| 493 | #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES |
| 494 | FT_Service_PsCMaps psnames; |
| 495 | #endif |
| 496 | |
| 497 | |
| 498 | if ( !face ) |
| 499 | return FT_THROW( Invalid_Face_Handle ); |
| 500 | |
| 501 | if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) |
| 502 | return FT_THROW( Invalid_Glyph_Index ); |
| 503 | |
| 504 | #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES |
| 505 | psnames = (FT_Service_PsCMaps)face->psnames; |
| 506 | if ( !psnames ) |
| 507 | return FT_THROW( Unimplemented_Feature ); |
| 508 | #endif |
| 509 | |
| 510 | names = &face->postscript_names; |
| 511 | |
| 512 | /* `.notdef' by default */ |
| 513 | *PSname = MAC_NAME( 0 ); |
| 514 | |
| 515 | format = face->postscript.FormatType; |
| 516 | |
| 517 | if ( format == 0x00010000L ) |
| 518 | { |
| 519 | if ( idx < 258 ) /* paranoid checking */ |
| 520 | *PSname = MAC_NAME( idx ); |
| 521 | } |
| 522 | else if ( format == 0x00020000L ) |
| 523 | { |
| 524 | TT_Post_20 table = &names->names.format_20; |
| 525 | |
| 526 | |
| 527 | if ( !names->loaded ) |
| 528 | { |
| 529 | error = load_post_names( face ); |
| 530 | if ( error ) |
| 531 | goto End; |
| 532 | } |
| 533 | |
| 534 | if ( idx < (FT_UInt)table->num_glyphs ) |
| 535 | { |
| 536 | FT_UShort name_index = table->glyph_indices[idx]; |
| 537 | |
| 538 | |
| 539 | if ( name_index < 258 ) |
| 540 | *PSname = MAC_NAME( name_index ); |
| 541 | else |
| 542 | *PSname = (FT_String*)table->glyph_names[name_index - 258]; |
| 543 | } |
| 544 | } |
| 545 | else if ( format == 0x00025000L ) |
| 546 | { |
| 547 | TT_Post_25 table = &names->names.format_25; |
| 548 | |
| 549 | |
| 550 | if ( !names->loaded ) |
| 551 | { |
| 552 | error = load_post_names( face ); |
| 553 | if ( error ) |
| 554 | goto End; |
| 555 | } |
| 556 | |
| 557 | if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */ |
| 558 | *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] ); |
| 559 | } |
| 560 | |
| 561 | /* nothing to do for format == 0x00030000L */ |
| 562 | |
| 563 | End: |
| 564 | return FT_Err_Ok; |
| 565 | } |
| 566 | |
| 567 | #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ |
| 568 | |
| 569 | /* ANSI C doesn't like empty source files */ |
| 570 | typedef int _tt_post_dummy; |
| 571 | |
| 572 | #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ |
| 573 | |
| 574 | |
| 575 | /* END */ |
| 576 | |