1 /***************************************************************************/ 2 /* */ 3 /* sfobjs.c */ 4 /* */ 5 /* SFNT object management (base). */ 6 /* */ 7 /* Copyright 1996-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 <ft2build.h> 20 #include "sfobjs.h" 21 #include "ttload.h" 22 #include "ttcmap.h" 23 #include "ttkern.h" 24 #include FT_INTERNAL_SFNT_H 25 #include FT_INTERNAL_DEBUG_H 26 #include FT_TRUETYPE_IDS_H 27 #include FT_TRUETYPE_TAGS_H 28 #include FT_SERVICE_POSTSCRIPT_CMAPS_H 29 #include FT_SFNT_NAMES_H 30 #include FT_GZIP_H 31 #include "sferrors.h" 32 33 #ifdef TT_CONFIG_OPTION_BDF 34 #include "ttbdf.h" 35 #endif 36 37 38 /*************************************************************************/ 39 /* */ 40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 42 /* messages during execution. */ 43 /* */ 44 #undef FT_COMPONENT 45 #define FT_COMPONENT trace_sfobjs 46 47 48 49 /* convert a UTF-16 name entry to ASCII */ 50 static FT_String* 51 tt_name_entry_ascii_from_utf16( TT_NameEntry entry, 52 FT_Memory memory ) 53 { 54 FT_String* string = NULL; 55 FT_UInt len, code, n; 56 FT_Byte* read = (FT_Byte*)entry->string; 57 FT_Error error; 58 59 60 len = (FT_UInt)entry->stringLength / 2; 61 62 if ( FT_NEW_ARRAY( string, len + 1 ) ) 63 return NULL; 64 65 for ( n = 0; n < len; n++ ) 66 { 67 code = FT_NEXT_USHORT( read ); 68 69 if ( code == 0 ) 70 break; 71 72 if ( code < 32 || code > 127 ) 73 code = '?'; 74 75 string[n] = (char)code; 76 } 77 78 string[n] = 0; 79 80 return string; 81 } 82 83 84 /* convert an Apple Roman or symbol name entry to ASCII */ 85 static FT_String* 86 tt_name_entry_ascii_from_other( TT_NameEntry entry, 87 FT_Memory memory ) 88 { 89 FT_String* string = NULL; 90 FT_UInt len, code, n; 91 FT_Byte* read = (FT_Byte*)entry->string; 92 FT_Error error; 93 94 95 len = (FT_UInt)entry->stringLength; 96 97 if ( FT_NEW_ARRAY( string, len + 1 ) ) 98 return NULL; 99 100 for ( n = 0; n < len; n++ ) 101 { 102 code = *read++; 103 104 if ( code == 0 ) 105 break; 106 107 if ( code < 32 || code > 127 ) 108 code = '?'; 109 110 string[n] = (char)code; 111 } 112 113 string[n] = 0; 114 115 return string; 116 } 117 118 119 typedef FT_String* (*TT_NameEntry_ConvertFunc)( TT_NameEntry entry, 120 FT_Memory memory ); 121 122 123 /* documentation is in sfnt.h */ 124 125 FT_LOCAL_DEF( FT_Error ) 126 tt_face_get_name( TT_Face face, 127 FT_UShort nameid, 128 FT_String** name ) 129 { 130 FT_Memory memory = face->root.memory; 131 FT_Error error = FT_Err_Ok; 132 FT_String* result = NULL; 133 FT_UShort n; 134 TT_NameEntryRec* rec; 135 FT_Int found_apple = -1; 136 FT_Int found_apple_roman = -1; 137 FT_Int found_apple_english = -1; 138 FT_Int found_win = -1; 139 FT_Int found_unicode = -1; 140 141 FT_Bool is_english = 0; 142 143 TT_NameEntry_ConvertFunc convert; 144 145 146 FT_ASSERT( name ); 147 148 rec = face->name_table.names; 149 for ( n = 0; n < face->num_names; n++, rec++ ) 150 { 151 /* According to the OpenType 1.3 specification, only Microsoft or */ 152 /* Apple platform IDs might be used in the `name' table. The */ 153 /* `Unicode' platform is reserved for the `cmap' table, and the */ 154 /* `ISO' one is deprecated. */ 155 /* */ 156 /* However, the Apple TrueType specification doesn't say the same */ 157 /* thing and goes to suggest that all Unicode `name' table entries */ 158 /* should be coded in UTF-16 (in big-endian format I suppose). */ 159 /* */ 160 if ( rec->nameID == nameid && rec->stringLength > 0 ) 161 { 162 switch ( rec->platformID ) 163 { 164 case TT_PLATFORM_APPLE_UNICODE: 165 case TT_PLATFORM_ISO: 166 /* there is `languageID' to check there. We should use this */ 167 /* field only as a last solution when nothing else is */ 168 /* available. */ 169 /* */ 170 found_unicode = n; 171 break; 172 173 case TT_PLATFORM_MACINTOSH: 174 /* This is a bit special because some fonts will use either */ 175 /* an English language id, or a Roman encoding id, to indicate */ 176 /* the English version of its font name. */ 177 /* */ 178 if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) 179 found_apple_english = n; 180 else if ( rec->encodingID == TT_MAC_ID_ROMAN ) 181 found_apple_roman = n; 182 break; 183 184 case TT_PLATFORM_MICROSOFT: 185 /* we only take a non-English name when there is nothing */ 186 /* else available in the font */ 187 /* */ 188 if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) 189 { 190 switch ( rec->encodingID ) 191 { 192 case TT_MS_ID_SYMBOL_CS: 193 case TT_MS_ID_UNICODE_CS: 194 case TT_MS_ID_UCS_4: 195 is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); 196 found_win = n; 197 break; 198 199 default: 200 ; 201 } 202 } 203 break; 204 205 default: 206 ; 207 } 208 } 209 } 210 211 found_apple = found_apple_roman; 212 if ( found_apple_english >= 0 ) 213 found_apple = found_apple_english; 214 215 /* some fonts contain invalid Unicode or Macintosh formatted entries; */ 216 /* we will thus favor names encoded in Windows formats if available */ 217 /* (provided it is an English name) */ 218 /* */ 219 convert = NULL; 220 if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) 221 { 222 rec = face->name_table.names + found_win; 223 switch ( rec->encodingID ) 224 { 225 /* all Unicode strings are encoded using UTF-16BE */ 226 case TT_MS_ID_UNICODE_CS: 227 case TT_MS_ID_SYMBOL_CS: 228 convert = tt_name_entry_ascii_from_utf16; 229 break; 230 231 case TT_MS_ID_UCS_4: 232 /* Apparently, if this value is found in a name table entry, it is */ 233 /* documented as `full Unicode repertoire'. Experience with the */ 234 /* MsGothic font shipped with Windows Vista shows that this really */ 235 /* means UTF-16 encoded names (UCS-4 values are only used within */ 236 /* charmaps). */ 237 convert = tt_name_entry_ascii_from_utf16; 238 break; 239 240 default: 241 ; 242 } 243 } 244 else if ( found_apple >= 0 ) 245 { 246 rec = face->name_table.names + found_apple; 247 convert = tt_name_entry_ascii_from_other; 248 } 249 else if ( found_unicode >= 0 ) 250 { 251 rec = face->name_table.names + found_unicode; 252 convert = tt_name_entry_ascii_from_utf16; 253 } 254 255 if ( rec && convert ) 256 { 257 if ( rec->string == NULL ) 258 { 259 FT_Stream stream = face->name_table.stream; 260 261 262 if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || 263 FT_STREAM_SEEK( rec->stringOffset ) || 264 FT_STREAM_READ( rec->string, rec->stringLength ) ) 265 { 266 FT_FREE( rec->string ); 267 rec->stringLength = 0; 268 result = NULL; 269 goto Exit; 270 } 271 } 272 273 result = convert( rec, memory ); 274 } 275 276 Exit: 277 *name = result; 278 return error; 279 } 280 281 282 static FT_Encoding 283 sfnt_find_encoding( int platform_id, 284 int encoding_id ) 285 { 286 typedef struct TEncoding_ 287 { 288 int platform_id; 289 int encoding_id; 290 FT_Encoding encoding; 291 292 } TEncoding; 293 294 static 295 const TEncoding tt_encodings[] = 296 { 297 { TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE }, 298 299 { TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE }, 300 301 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN }, 302 303 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL }, 304 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE }, 305 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE }, 306 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_SJIS }, 307 { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, FT_ENCODING_GB2312 }, 308 { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_BIG5 }, 309 { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_WANSUNG }, 310 { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_JOHAB } 311 }; 312 313 const TEncoding *cur, *limit; 314 315 316 cur = tt_encodings; 317 limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); 318 319 for ( ; cur < limit; cur++ ) 320 { 321 if ( cur->platform_id == platform_id ) 322 { 323 if ( cur->encoding_id == encoding_id || 324 cur->encoding_id == -1 ) 325 return cur->encoding; 326 } 327 } 328 329 return FT_ENCODING_NONE; 330 } 331 332 333 #define WRITE_USHORT( p, v ) \ 334 do \ 335 { \ 336 *(p)++ = (FT_Byte)( (v) >> 8 ); \ 337 *(p)++ = (FT_Byte)( (v) >> 0 ); \ 338 \ 339 } while ( 0 ) 340 341 #define WRITE_ULONG( p, v ) \ 342 do \ 343 { \ 344 *(p)++ = (FT_Byte)( (v) >> 24 ); \ 345 *(p)++ = (FT_Byte)( (v) >> 16 ); \ 346 *(p)++ = (FT_Byte)( (v) >> 8 ); \ 347 *(p)++ = (FT_Byte)( (v) >> 0 ); \ 348 \ 349 } while ( 0 ) 350 351 352 static void 353 sfnt_stream_close( FT_Stream stream ) 354 { 355 FT_Memory memory = stream->memory; 356 357 358 FT_FREE( stream->base ); 359 360 stream->size = 0; 361 stream->base = NULL; 362 stream->close = NULL; 363 } 364 365 366 FT_CALLBACK_DEF( int ) 367 compare_offsets( const void* a, 368 const void* b ) 369 { 370 WOFF_Table table1 = *(WOFF_Table*)a; 371 WOFF_Table table2 = *(WOFF_Table*)b; 372 373 FT_ULong offset1 = table1->Offset; 374 FT_ULong offset2 = table2->Offset; 375 376 377 if ( offset1 > offset2 ) 378 return 1; 379 else if ( offset1 < offset2 ) 380 return -1; 381 else 382 return 0; 383 } 384 385 386 /* Replace `face->root.stream' with a stream containing the extracted */ 387 /* SFNT of a WOFF font. */ 388 389 static FT_Error 390 woff_open_font( FT_Stream stream, 391 TT_Face face ) 392 { 393 FT_Memory memory = stream->memory; 394 FT_Error error = FT_Err_Ok; 395 396 WOFF_HeaderRec woff; 397 WOFF_Table tables = NULL; 398 WOFF_Table* indices = NULL; 399 400 FT_ULong woff_offset; 401 402 FT_Byte* sfnt = NULL; 403 FT_Stream sfnt_stream = NULL; 404 405 FT_Byte* sfnt_header; 406 FT_ULong sfnt_offset; 407 408 FT_Int nn; 409 FT_ULong old_tag = 0; 410 411 static const FT_Frame_Field woff_header_fields[] = 412 { 413 #undef FT_STRUCTURE 414 #define FT_STRUCTURE WOFF_HeaderRec 415 416 FT_FRAME_START( 44 ), 417 FT_FRAME_ULONG ( signature ), 418 FT_FRAME_ULONG ( flavor ), 419 FT_FRAME_ULONG ( length ), 420 FT_FRAME_USHORT( num_tables ), 421 FT_FRAME_USHORT( reserved ), 422 FT_FRAME_ULONG ( totalSfntSize ), 423 FT_FRAME_USHORT( majorVersion ), 424 FT_FRAME_USHORT( minorVersion ), 425 FT_FRAME_ULONG ( metaOffset ), 426 FT_FRAME_ULONG ( metaLength ), 427 FT_FRAME_ULONG ( metaOrigLength ), 428 FT_FRAME_ULONG ( privOffset ), 429 FT_FRAME_ULONG ( privLength ), 430 FT_FRAME_END 431 }; 432 433 434 FT_ASSERT( stream == face->root.stream ); 435 FT_ASSERT( FT_STREAM_POS() == 0 ); 436 437 if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) ) 438 return error; 439 440 /* Make sure we don't recurse back here or hit TTC code. */ 441 if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf ) 442 return FT_THROW( Invalid_Table ); 443 444 /* Miscellaneous checks. */ 445 if ( woff.length != stream->size || 446 woff.num_tables == 0 || 447 44 + woff.num_tables * 20UL >= woff.length || 448 12 + woff.num_tables * 16UL >= woff.totalSfntSize || 449 ( woff.totalSfntSize & 3 ) != 0 || 450 ( woff.metaOffset == 0 && ( woff.metaLength != 0 || 451 woff.metaOrigLength != 0 ) ) || 452 ( woff.metaLength != 0 && woff.metaOrigLength == 0 ) || 453 ( woff.privOffset == 0 && woff.privLength != 0 ) ) 454 return FT_THROW( Invalid_Table ); 455 456 if ( FT_ALLOC( sfnt, woff.totalSfntSize ) || 457 FT_NEW( sfnt_stream ) ) 458 goto Exit; 459 460 sfnt_header = sfnt; 461 462 /* Write sfnt header. */ 463 { 464 FT_UInt searchRange, entrySelector, rangeShift, x; 465 466 467 x = woff.num_tables; 468 entrySelector = 0; 469 while ( x ) 470 { 471 x >>= 1; 472 entrySelector += 1; 473 } 474 entrySelector--; 475 476 searchRange = ( 1 << entrySelector ) * 16; 477 rangeShift = woff.num_tables * 16 - searchRange; 478 479 WRITE_ULONG ( sfnt_header, woff.flavor ); 480 WRITE_USHORT( sfnt_header, woff.num_tables ); 481 WRITE_USHORT( sfnt_header, searchRange ); 482 WRITE_USHORT( sfnt_header, entrySelector ); 483 WRITE_USHORT( sfnt_header, rangeShift ); 484 } 485 486 /* While the entries in the sfnt header must be sorted by the */ 487 /* tag value, the tables themselves are not. We thus have to */ 488 /* sort them by offset and check that they don't overlap. */ 489 490 if ( FT_NEW_ARRAY( tables, woff.num_tables ) || 491 FT_NEW_ARRAY( indices, woff.num_tables ) ) 492 goto Exit; 493 494 FT_TRACE2(( "\n" 495 " tag offset compLen origLen checksum\n" 496 " -------------------------------------------\n" )); 497 498 if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) 499 goto Exit; 500 501 for ( nn = 0; nn < woff.num_tables; nn++ ) 502 { 503 WOFF_Table table = tables + nn; 504 505 table->Tag = FT_GET_TAG4(); 506 table->Offset = FT_GET_ULONG(); 507 table->CompLength = FT_GET_ULONG(); 508 table->OrigLength = FT_GET_ULONG(); 509 table->CheckSum = FT_GET_ULONG(); 510 511 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n", 512 (FT_Char)( table->Tag >> 24 ), 513 (FT_Char)( table->Tag >> 16 ), 514 (FT_Char)( table->Tag >> 8 ), 515 (FT_Char)( table->Tag ), 516 table->Offset, 517 table->CompLength, 518 table->OrigLength, 519 table->CheckSum )); 520 521 if ( table->Tag <= old_tag ) 522 { 523 FT_FRAME_EXIT(); 524 error = FT_THROW( Invalid_Table ); 525 goto Exit; 526 } 527 528 old_tag = table->Tag; 529 indices[nn] = table; 530 } 531 532 FT_FRAME_EXIT(); 533 534 /* Sort by offset. */ 535 536 ft_qsort( indices, 537 woff.num_tables, 538 sizeof ( WOFF_Table ), 539 compare_offsets ); 540 541 /* Check offsets and lengths. */ 542 543 woff_offset = 44 + woff.num_tables * 20L; 544 sfnt_offset = 12 + woff.num_tables * 16L; 545 546 for ( nn = 0; nn < woff.num_tables; nn++ ) 547 { 548 WOFF_Table table = indices[nn]; 549 550 551 if ( table->Offset != woff_offset || 552 table->CompLength > woff.length || 553 table->Offset > woff.length - table->CompLength || 554 table->OrigLength > woff.totalSfntSize || 555 sfnt_offset > woff.totalSfntSize - table->OrigLength || 556 table->CompLength > table->OrigLength ) 557 { 558 error = FT_THROW( Invalid_Table ); 559 goto Exit; 560 } 561 562 table->OrigOffset = sfnt_offset; 563 564 /* The offsets must be multiples of 4. */ 565 woff_offset += ( table->CompLength + 3 ) & ~3U; 566 sfnt_offset += ( table->OrigLength + 3 ) & ~3U; 567 } 568 569 /* 570 * Final checks! 571 * 572 * We don't decode and check the metadata block. 573 * We don't check table checksums either. 574 * But other than those, I think we implement all 575 * `MUST' checks from the spec. 576 */ 577 578 if ( woff.metaOffset ) 579 { 580 if ( woff.metaOffset != woff_offset || 581 woff.metaOffset + woff.metaLength > woff.length ) 582 { 583 error = FT_THROW( Invalid_Table ); 584 goto Exit; 585 } 586 587 /* We have padding only ... */ 588 woff_offset += woff.metaLength; 589 } 590 591 if ( woff.privOffset ) 592 { 593 /* ... if it isn't the last block. */ 594 woff_offset = ( woff_offset + 3 ) & ~3U; 595 596 if ( woff.privOffset != woff_offset || 597 woff.privOffset + woff.privLength > woff.length ) 598 { 599 error = FT_THROW( Invalid_Table ); 600 goto Exit; 601 } 602 603 /* No padding for the last block. */ 604 woff_offset += woff.privLength; 605 } 606 607 if ( sfnt_offset != woff.totalSfntSize || 608 woff_offset != woff.length ) 609 { 610 error = FT_THROW( Invalid_Table ); 611 goto Exit; 612 } 613 614 /* Write the tables. */ 615 616 for ( nn = 0; nn < woff.num_tables; nn++ ) 617 { 618 WOFF_Table table = tables + nn; 619 620 621 /* Write SFNT table entry. */ 622 WRITE_ULONG( sfnt_header, table->Tag ); 623 WRITE_ULONG( sfnt_header, table->CheckSum ); 624 WRITE_ULONG( sfnt_header, table->OrigOffset ); 625 WRITE_ULONG( sfnt_header, table->OrigLength ); 626 627 /* Write table data. */ 628 if ( FT_STREAM_SEEK( table->Offset ) || 629 FT_FRAME_ENTER( table->CompLength ) ) 630 goto Exit; 631 632 if ( table->CompLength == table->OrigLength ) 633 { 634 /* Uncompressed data; just copy. */ 635 ft_memcpy( sfnt + table->OrigOffset, 636 stream->cursor, 637 table->OrigLength ); 638 } 639 else 640 { 641 #ifdef FT_CONFIG_OPTION_USE_ZLIB 642 643 /* Uncompress with zlib. */ 644 FT_ULong output_len = table->OrigLength; 645 646 647 error = FT_Gzip_Uncompress( memory, 648 sfnt + table->OrigOffset, &output_len, 649 stream->cursor, table->CompLength ); 650 if ( error ) 651 goto Exit; 652 if ( output_len != table->OrigLength ) 653 { 654 error = FT_THROW( Invalid_Table ); 655 goto Exit; 656 } 657 658 #else /* !FT_CONFIG_OPTION_USE_ZLIB */ 659 660 error = FT_THROW( Unimplemented_Feature ); 661 goto Exit; 662 663 #endif /* !FT_CONFIG_OPTION_USE_ZLIB */ 664 } 665 666 FT_FRAME_EXIT(); 667 668 /* We don't check whether the padding bytes in the WOFF file are */ 669 /* actually '\0'. For the output, however, we do set them properly. */ 670 sfnt_offset = table->OrigOffset + table->OrigLength; 671 while ( sfnt_offset & 3 ) 672 { 673 sfnt[sfnt_offset] = '\0'; 674 sfnt_offset++; 675 } 676 } 677 678 /* Ok! Finally ready. Swap out stream and return. */ 679 FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize ); 680 sfnt_stream->memory = stream->memory; 681 sfnt_stream->close = sfnt_stream_close; 682 683 FT_Stream_Free( 684 face->root.stream, 685 ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); 686 687 face->root.stream = sfnt_stream; 688 689 face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; 690 691 Exit: 692 FT_FREE( tables ); 693 FT_FREE( indices ); 694 695 if ( error ) 696 { 697 FT_FREE( sfnt ); 698 FT_Stream_Close( sfnt_stream ); 699 FT_FREE( sfnt_stream ); 700 } 701 702 return error; 703 } 704 705 706 #undef WRITE_USHORT 707 #undef WRITE_ULONG 708 709 710 /* Fill in face->ttc_header. If the font is not a TTC, it is */ 711 /* synthesized into a TTC with one offset table. */ 712 static FT_Error 713 sfnt_open_font( FT_Stream stream, 714 TT_Face face ) 715 { 716 FT_Memory memory = stream->memory; 717 FT_Error error; 718 FT_ULong tag, offset; 719 720 static const FT_Frame_Field ttc_header_fields[] = 721 { 722 #undef FT_STRUCTURE 723 #define FT_STRUCTURE TTC_HeaderRec 724 725 FT_FRAME_START( 8 ), 726 FT_FRAME_LONG( version ), 727 FT_FRAME_LONG( count ), /* this is ULong in the specs */ 728 FT_FRAME_END 729 }; 730 731 732 face->ttc_header.tag = 0; 733 face->ttc_header.version = 0; 734 face->ttc_header.count = 0; 735 736 retry: 737 offset = FT_STREAM_POS(); 738 739 if ( FT_READ_ULONG( tag ) ) 740 return error; 741 742 if ( tag == TTAG_wOFF ) 743 { 744 FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" )); 745 746 if ( FT_STREAM_SEEK( offset ) ) 747 return error; 748 749 error = woff_open_font( stream, face ); 750 if ( error ) 751 return error; 752 753 /* Swap out stream and retry! */ 754 stream = face->root.stream; 755 goto retry; 756 } 757 758 if ( tag != 0x00010000UL && 759 tag != TTAG_ttcf && 760 tag != TTAG_OTTO && 761 tag != TTAG_true && 762 tag != TTAG_typ1 && 763 tag != 0x00020000UL ) 764 { 765 FT_TRACE2(( " not a font using the SFNT container format\n" )); 766 return FT_THROW( Unknown_File_Format ); 767 } 768 769 face->ttc_header.tag = TTAG_ttcf; 770 771 if ( tag == TTAG_ttcf ) 772 { 773 FT_Int n; 774 775 776 FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); 777 778 if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) 779 return error; 780 781 if ( face->ttc_header.count == 0 ) 782 return FT_THROW( Invalid_Table ); 783 784 /* a rough size estimate: let's conservatively assume that there */ 785 /* is just a single table info in each subfont header (12 + 16*1 = */ 786 /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ 787 /* size of the TTC header plus `28*count' bytes for all subfont */ 788 /* headers */ 789 if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) 790 return FT_THROW( Array_Too_Large ); 791 792 /* now read the offsets of each font in the file */ 793 if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) 794 return error; 795 796 if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) 797 return error; 798 799 for ( n = 0; n < face->ttc_header.count; n++ ) 800 face->ttc_header.offsets[n] = FT_GET_ULONG(); 801 802 FT_FRAME_EXIT(); 803 } 804 else 805 { 806 FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); 807 808 face->ttc_header.version = 1 << 16; 809 face->ttc_header.count = 1; 810 811 if ( FT_NEW( face->ttc_header.offsets ) ) 812 return error; 813 814 face->ttc_header.offsets[0] = offset; 815 } 816 817 return error; 818 } 819 820 821 FT_LOCAL_DEF( FT_Error ) 822 sfnt_init_face( FT_Stream stream, 823 TT_Face face, 824 FT_Int face_instance_index, 825 FT_Int num_params, 826 FT_Parameter* params ) 827 { 828 FT_Error error; 829 FT_Library library = face->root.driver->root.library; 830 SFNT_Service sfnt; 831 FT_Int face_index; 832 833 834 /* for now, parameters are unused */ 835 FT_UNUSED( num_params ); 836 FT_UNUSED( params ); 837 838 839 sfnt = (SFNT_Service)face->sfnt; 840 if ( !sfnt ) 841 { 842 sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); 843 if ( !sfnt ) 844 { 845 FT_ERROR(( "sfnt_init_face: cannot access `sfnt' module\n" )); 846 return FT_THROW( Missing_Module ); 847 } 848 849 face->sfnt = sfnt; 850 face->goto_table = sfnt->goto_table; 851 } 852 853 FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS ); 854 855 FT_TRACE2(( "SFNT driver\n" )); 856 857 error = sfnt_open_font( stream, face ); 858 if ( error ) 859 return error; 860 861 /* Stream may have changed in sfnt_open_font. */ 862 stream = face->root.stream; 863 864 FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_instance_index )); 865 866 face_index = FT_ABS( face_instance_index ) & 0xFFFF; 867 868 if ( face_index >= face->ttc_header.count ) 869 { 870 if ( face_instance_index >= 0 ) 871 return FT_THROW( Invalid_Argument ); 872 else 873 face_index = 0; 874 } 875 876 if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ) 877 return error; 878 879 /* check whether we have a valid TrueType file */ 880 error = sfnt->load_font_dir( face, stream ); 881 if ( error ) 882 return error; 883 884 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 885 { 886 FT_ULong fvar_len; 887 FT_UShort num_instances; 888 FT_Int instance_index; 889 890 891 instance_index = FT_ABS( face_instance_index ) >> 16; 892 893 /* test whether current face is a GX font with named instances */ 894 if ( face->goto_table( face, TTAG_fvar, stream, &fvar_len ) || 895 fvar_len < 20 || 896 FT_STREAM_SKIP( 12 ) || 897 FT_READ_USHORT( num_instances ) ) 898 num_instances = 0; 899 900 /* we support at most 2^15 - 1 instances */ 901 if ( num_instances >= ( 1U << 15 ) - 1 ) 902 { 903 if ( face_instance_index >= 0 ) 904 return FT_THROW( Invalid_Argument ); 905 else 906 num_instances = 0; 907 } 908 909 /* instance indices in `face_instance_index' start with index 1, */ 910 /* thus `>' and not `>=' */ 911 if ( instance_index > num_instances ) 912 { 913 if ( face_instance_index >= 0 ) 914 return FT_THROW( Invalid_Argument ); 915 else 916 num_instances = 0; 917 } 918 919 face->root.style_flags = (FT_Long)num_instances << 16; 920 } 921 #endif 922 923 face->root.num_faces = face->ttc_header.count; 924 face->root.face_index = face_index; 925 926 return error; 927 } 928 929 930 #define LOAD_( x ) \ 931 do \ 932 { \ 933 FT_TRACE2(( "`" #x "' " )); \ 934 FT_TRACE3(( "-->\n" )); \ 935 \ 936 error = sfnt->load_ ## x( face, stream ); \ 937 \ 938 FT_TRACE2(( "%s\n", ( !error ) \ 939 ? "loaded" \ 940 : FT_ERR_EQ( error, Table_Missing ) \ 941 ? "missing" \ 942 : "failed to load" )); \ 943 FT_TRACE3(( "\n" )); \ 944 } while ( 0 ) 945 946 #define LOADM_( x, vertical ) \ 947 do \ 948 { \ 949 FT_TRACE2(( "`%s" #x "' ", \ 950 vertical ? "vertical " : "" )); \ 951 FT_TRACE3(( "-->\n" )); \ 952 \ 953 error = sfnt->load_ ## x( face, stream, vertical ); \ 954 \ 955 FT_TRACE2(( "%s\n", ( !error ) \ 956 ? "loaded" \ 957 : FT_ERR_EQ( error, Table_Missing ) \ 958 ? "missing" \ 959 : "failed to load" )); \ 960 FT_TRACE3(( "\n" )); \ 961 } while ( 0 ) 962 963 #define GET_NAME( id, field ) \ 964 do \ 965 { \ 966 error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \ 967 if ( error ) \ 968 goto Exit; \ 969 } while ( 0 ) 970 971 972 FT_LOCAL_DEF( FT_Error ) 973 sfnt_load_face( FT_Stream stream, 974 TT_Face face, 975 FT_Int face_instance_index, 976 FT_Int num_params, 977 FT_Parameter* params ) 978 { 979 FT_Error error; 980 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 981 FT_Error psnames_error; 982 #endif 983 FT_Bool has_outline; 984 FT_Bool is_apple_sbit; 985 FT_Bool is_apple_sbix; 986 FT_Bool ignore_preferred_family = FALSE; 987 FT_Bool ignore_preferred_subfamily = FALSE; 988 989 SFNT_Service sfnt = (SFNT_Service)face->sfnt; 990 991 FT_UNUSED( face_instance_index ); 992 993 994 /* Check parameters */ 995 996 { 997 FT_Int i; 998 999 1000 for ( i = 0; i < num_params; i++ ) 1001 { 1002 if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY ) 1003 ignore_preferred_family = TRUE; 1004 else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY ) 1005 ignore_preferred_subfamily = TRUE; 1006 } 1007 } 1008 1009 /* Load tables */ 1010 1011 /* We now support two SFNT-based bitmapped font formats. They */ 1012 /* are recognized easily as they do not include a `glyf' */ 1013 /* table. */ 1014 /* */ 1015 /* The first format comes from Apple, and uses a table named */ 1016 /* `bhed' instead of `head' to store the font header (using */ 1017 /* the same format). It also doesn't include horizontal and */ 1018 /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ 1019 /* missing). */ 1020 /* */ 1021 /* The other format comes from Microsoft, and is used with */ 1022 /* WinCE/PocketPC. It looks like a standard TTF, except that */ 1023 /* it doesn't contain outlines. */ 1024 /* */ 1025 1026 FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); 1027 1028 /* do we have outlines in there? */ 1029 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1030 has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || 1031 tt_face_lookup_table( face, TTAG_glyf ) != 0 || 1032 tt_face_lookup_table( face, TTAG_CFF ) != 0 ); 1033 #else 1034 has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 || 1035 tt_face_lookup_table( face, TTAG_CFF ) != 0 ); 1036 #endif 1037 1038 is_apple_sbit = 0; 1039 is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); 1040 1041 /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf' 1042 * outline rendered on top. We don't support that yet, so just ignore 1043 * the 'glyf' outline and advertise it as a bitmap-only font. */ 1044 if ( is_apple_sbix ) 1045 has_outline = FALSE; 1046 1047 /* if this font doesn't contain outlines, we try to load */ 1048 /* a `bhed' table */ 1049 if ( !has_outline && sfnt->load_bhed ) 1050 { 1051 LOAD_( bhed ); 1052 is_apple_sbit = FT_BOOL( !error ); 1053 } 1054 1055 /* load the font header (`head' table) if this isn't an Apple */ 1056 /* sbit font file */ 1057 if ( !is_apple_sbit || is_apple_sbix ) 1058 { 1059 LOAD_( head ); 1060 if ( error ) 1061 goto Exit; 1062 } 1063 1064 if ( face->header.Units_Per_EM == 0 ) 1065 { 1066 error = FT_THROW( Invalid_Table ); 1067 1068 goto Exit; 1069 } 1070 1071 /* the following tables are often not present in embedded TrueType */ 1072 /* fonts within PDF documents, so don't check for them. */ 1073 LOAD_( maxp ); 1074 LOAD_( cmap ); 1075 1076 /* the following tables are optional in PCL fonts -- */ 1077 /* don't check for errors */ 1078 LOAD_( name ); 1079 LOAD_( post ); 1080 1081 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 1082 psnames_error = error; 1083 #endif 1084 1085 /* do not load the metrics headers and tables if this is an Apple */ 1086 /* sbit font file */ 1087 if ( !is_apple_sbit ) 1088 { 1089 /* load the `hhea' and `hmtx' tables */ 1090 LOADM_( hhea, 0 ); 1091 if ( !error ) 1092 { 1093 LOADM_( hmtx, 0 ); 1094 if ( FT_ERR_EQ( error, Table_Missing ) ) 1095 { 1096 error = FT_THROW( Hmtx_Table_Missing ); 1097 1098 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1099 /* If this is an incrementally loaded font and there are */ 1100 /* overriding metrics, tolerate a missing `hmtx' table. */ 1101 if ( face->root.internal->incremental_interface && 1102 face->root.internal->incremental_interface->funcs-> 1103 get_glyph_metrics ) 1104 { 1105 face->horizontal.number_Of_HMetrics = 0; 1106 error = FT_Err_Ok; 1107 } 1108 #endif 1109 } 1110 } 1111 else if ( FT_ERR_EQ( error, Table_Missing ) ) 1112 { 1113 /* No `hhea' table necessary for SFNT Mac fonts. */ 1114 if ( face->format_tag == TTAG_true ) 1115 { 1116 FT_TRACE2(( "This is an SFNT Mac font.\n" )); 1117 1118 has_outline = 0; 1119 error = FT_Err_Ok; 1120 } 1121 else 1122 { 1123 error = FT_THROW( Horiz_Header_Missing ); 1124 1125 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1126 /* If this is an incrementally loaded font and there are */ 1127 /* overriding metrics, tolerate a missing `hhea' table. */ 1128 if ( face->root.internal->incremental_interface && 1129 face->root.internal->incremental_interface->funcs-> 1130 get_glyph_metrics ) 1131 { 1132 face->horizontal.number_Of_HMetrics = 0; 1133 error = FT_Err_Ok; 1134 } 1135 #endif 1136 1137 } 1138 } 1139 1140 if ( error ) 1141 goto Exit; 1142 1143 /* try to load the `vhea' and `vmtx' tables */ 1144 LOADM_( hhea, 1 ); 1145 if ( !error ) 1146 { 1147 LOADM_( hmtx, 1 ); 1148 if ( !error ) 1149 face->vertical_info = 1; 1150 } 1151 1152 if ( error && FT_ERR_NEQ( error, Table_Missing ) ) 1153 goto Exit; 1154 1155 LOAD_( os2 ); 1156 if ( error ) 1157 { 1158 /* we treat the table as missing if there are any errors */ 1159 face->os2.version = 0xFFFFU; 1160 } 1161 } 1162 1163 /* the optional tables */ 1164 1165 /* embedded bitmap support */ 1166 if ( sfnt->load_eblc ) 1167 { 1168 LOAD_( eblc ); 1169 if ( error ) 1170 { 1171 /* a font which contains neither bitmaps nor outlines is */ 1172 /* still valid (although rather useless in most cases); */ 1173 /* however, you can find such stripped fonts in PDFs */ 1174 if ( FT_ERR_EQ( error, Table_Missing ) ) 1175 error = FT_Err_Ok; 1176 else 1177 goto Exit; 1178 } 1179 } 1180 1181 LOAD_( pclt ); 1182 if ( error ) 1183 { 1184 if ( FT_ERR_NEQ( error, Table_Missing ) ) 1185 goto Exit; 1186 1187 face->pclt.Version = 0; 1188 } 1189 1190 /* consider the kerning and gasp tables as optional */ 1191 LOAD_( gasp ); 1192 LOAD_( kern ); 1193 1194 face->root.num_glyphs = face->max_profile.numGlyphs; 1195 1196 /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ 1197 /* a WWS-only font face. `WWS' stands for `weight', width', and */ 1198 /* `slope', a term used by Microsoft's Windows Presentation */ 1199 /* Foundation (WPF). This flag has been introduced in version */ 1200 /* 1.5 of the OpenType specification (May 2008). */ 1201 1202 face->root.family_name = NULL; 1203 face->root.style_name = NULL; 1204 if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 ) 1205 { 1206 if ( !ignore_preferred_family ) 1207 GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); 1208 if ( !face->root.family_name ) 1209 GET_NAME( FONT_FAMILY, &face->root.family_name ); 1210 1211 if ( !ignore_preferred_subfamily ) 1212 GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); 1213 if ( !face->root.style_name ) 1214 GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); 1215 } 1216 else 1217 { 1218 GET_NAME( WWS_FAMILY, &face->root.family_name ); 1219 if ( !face->root.family_name && !ignore_preferred_family ) 1220 GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); 1221 if ( !face->root.family_name ) 1222 GET_NAME( FONT_FAMILY, &face->root.family_name ); 1223 1224 GET_NAME( WWS_SUBFAMILY, &face->root.style_name ); 1225 if ( !face->root.style_name && !ignore_preferred_subfamily ) 1226 GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); 1227 if ( !face->root.style_name ) 1228 GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); 1229 } 1230 1231 /* now set up root fields */ 1232 { 1233 FT_Face root = &face->root; 1234 FT_Long flags = root->face_flags; 1235 1236 1237 /*********************************************************************/ 1238 /* */ 1239 /* Compute face flags. */ 1240 /* */ 1241 if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || 1242 face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX ) 1243 flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ 1244 1245 if ( has_outline == TRUE ) 1246 flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ 1247 1248 /* The sfnt driver only supports bitmap fonts natively, thus we */ 1249 /* don't set FT_FACE_FLAG_HINTER. */ 1250 flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ 1251 FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ 1252 1253 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 1254 if ( !psnames_error && 1255 face->postscript.FormatType != 0x00030000L ) 1256 flags |= FT_FACE_FLAG_GLYPH_NAMES; 1257 #endif 1258 1259 /* fixed width font? */ 1260 if ( face->postscript.isFixedPitch ) 1261 flags |= FT_FACE_FLAG_FIXED_WIDTH; 1262 1263 /* vertical information? */ 1264 if ( face->vertical_info ) 1265 flags |= FT_FACE_FLAG_VERTICAL; 1266 1267 /* kerning available ? */ 1268 if ( TT_FACE_HAS_KERNING( face ) ) 1269 flags |= FT_FACE_FLAG_KERNING; 1270 1271 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 1272 /* Don't bother to load the tables unless somebody asks for them. */ 1273 /* No need to do work which will (probably) not be used. */ 1274 if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && 1275 tt_face_lookup_table( face, TTAG_fvar ) != 0 && 1276 tt_face_lookup_table( face, TTAG_gvar ) != 0 ) 1277 flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; 1278 #endif 1279 1280 root->face_flags = flags; 1281 1282 /*********************************************************************/ 1283 /* */ 1284 /* Compute style flags. */ 1285 /* */ 1286 1287 flags = 0; 1288 if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) 1289 { 1290 /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ 1291 /* indicates an oblique font face. This flag has been */ 1292 /* introduced in version 1.5 of the OpenType specification. */ 1293 1294 if ( face->os2.fsSelection & 512 ) /* bit 9 */ 1295 flags |= FT_STYLE_FLAG_ITALIC; 1296 else if ( face->os2.fsSelection & 1 ) /* bit 0 */ 1297 flags |= FT_STYLE_FLAG_ITALIC; 1298 1299 if ( face->os2.fsSelection & 32 ) /* bit 5 */ 1300 flags |= FT_STYLE_FLAG_BOLD; 1301 } 1302 else 1303 { 1304 /* this is an old Mac font, use the header field */ 1305 1306 if ( face->header.Mac_Style & 1 ) 1307 flags |= FT_STYLE_FLAG_BOLD; 1308 1309 if ( face->header.Mac_Style & 2 ) 1310 flags |= FT_STYLE_FLAG_ITALIC; 1311 } 1312 1313 root->style_flags |= flags; 1314 1315 /*********************************************************************/ 1316 /* */ 1317 /* Polish the charmaps. */ 1318 /* */ 1319 /* Try to set the charmap encoding according to the platform & */ 1320 /* encoding ID of each charmap. */ 1321 /* */ 1322 1323 tt_face_build_cmaps( face ); /* ignore errors */ 1324 1325 1326 /* set the encoding fields */ 1327 { 1328 FT_Int m; 1329 1330 1331 for ( m = 0; m < root->num_charmaps; m++ ) 1332 { 1333 FT_CharMap charmap = root->charmaps[m]; 1334 1335 1336 charmap->encoding = sfnt_find_encoding( charmap->platform_id, 1337 charmap->encoding_id ); 1338 1339 #if 0 1340 if ( root->charmap == NULL && 1341 charmap->encoding == FT_ENCODING_UNICODE ) 1342 { 1343 /* set 'root->charmap' to the first Unicode encoding we find */ 1344 root->charmap = charmap; 1345 } 1346 #endif 1347 } 1348 } 1349 1350 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 1351 1352 /* 1353 * Now allocate the root array of FT_Bitmap_Size records and 1354 * populate them. Unfortunately, it isn't possible to indicate bit 1355 * depths in the FT_Bitmap_Size record. This is a design error. 1356 */ 1357 { 1358 FT_UInt i, count; 1359 1360 1361 count = face->sbit_num_strikes; 1362 1363 if ( count > 0 ) 1364 { 1365 FT_Memory memory = face->root.stream->memory; 1366 FT_UShort em_size = face->header.Units_Per_EM; 1367 FT_Short avgwidth = face->os2.xAvgCharWidth; 1368 FT_Size_Metrics metrics; 1369 1370 1371 if ( em_size == 0 || face->os2.version == 0xFFFFU ) 1372 { 1373 avgwidth = 1; 1374 em_size = 1; 1375 } 1376 1377 if ( FT_NEW_ARRAY( root->available_sizes, count ) ) 1378 goto Exit; 1379 1380 for ( i = 0; i < count; i++ ) 1381 { 1382 FT_Bitmap_Size* bsize = root->available_sizes + i; 1383 1384 1385 error = sfnt->load_strike_metrics( face, i, &metrics ); 1386 if ( error ) 1387 goto Exit; 1388 1389 bsize->height = (FT_Short)( metrics.height >> 6 ); 1390 bsize->width = (FT_Short)( 1391 ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); 1392 1393 bsize->x_ppem = metrics.x_ppem << 6; 1394 bsize->y_ppem = metrics.y_ppem << 6; 1395 1396 /* assume 72dpi */ 1397 bsize->size = metrics.y_ppem << 6; 1398 } 1399 1400 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; 1401 root->num_fixed_sizes = (FT_Int)count; 1402 } 1403 } 1404 1405 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ 1406 1407 /* a font with no bitmaps and no outlines is scalable; */ 1408 /* it has only empty glyphs then */ 1409 if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) 1410 root->face_flags |= FT_FACE_FLAG_SCALABLE; 1411 1412 1413 /*********************************************************************/ 1414 /* */ 1415 /* Set up metrics. */ 1416 /* */ 1417 if ( FT_IS_SCALABLE( root ) ) 1418 { 1419 /* XXX What about if outline header is missing */ 1420 /* (e.g. sfnt wrapped bitmap)? */ 1421 root->bbox.xMin = face->header.xMin; 1422 root->bbox.yMin = face->header.yMin; 1423 root->bbox.xMax = face->header.xMax; 1424 root->bbox.yMax = face->header.yMax; 1425 root->units_per_EM = face->header.Units_Per_EM; 1426 1427 1428 /* XXX: Computing the ascender/descender/height is very different */ 1429 /* from what the specification tells you. Apparently, we */ 1430 /* must be careful because */ 1431 /* */ 1432 /* - not all fonts have an OS/2 table; in this case, we take */ 1433 /* the values in the horizontal header. However, these */ 1434 /* values very often are not reliable. */ 1435 /* */ 1436 /* - otherwise, the correct typographic values are in the */ 1437 /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ 1438 /* */ 1439 /* However, certain fonts have these fields set to 0. */ 1440 /* Rather, they have usWinAscent & usWinDescent correctly */ 1441 /* set (but with different values). */ 1442 /* */ 1443 /* As an example, Arial Narrow is implemented through four */ 1444 /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ 1445 /* */ 1446 /* Strangely, all fonts have the same values in their */ 1447 /* sTypoXXX fields, except ARIALNB which sets them to 0. */ 1448 /* */ 1449 /* On the other hand, they all have different */ 1450 /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ 1451 /* table cannot be used to compute the text height reliably! */ 1452 /* */ 1453 1454 /* The ascender and descender are taken from the `hhea' table. */ 1455 /* If zero, they are taken from the `OS/2' table. */ 1456 1457 root->ascender = face->horizontal.Ascender; 1458 root->descender = face->horizontal.Descender; 1459 1460 root->height = root->ascender - root->descender + 1461 face->horizontal.Line_Gap; 1462 1463 if ( !( root->ascender || root->descender ) ) 1464 { 1465 if ( face->os2.version != 0xFFFFU ) 1466 { 1467 if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) 1468 { 1469 root->ascender = face->os2.sTypoAscender; 1470 root->descender = face->os2.sTypoDescender; 1471 1472 root->height = root->ascender - root->descender + 1473 face->os2.sTypoLineGap; 1474 } 1475 else 1476 { 1477 root->ascender = (FT_Short)face->os2.usWinAscent; 1478 root->descender = -(FT_Short)face->os2.usWinDescent; 1479 1480 root->height = root->ascender - root->descender; 1481 } 1482 } 1483 } 1484 1485 root->max_advance_width = 1486 (FT_Short)face->horizontal.advance_Width_Max; 1487 root->max_advance_height = 1488 (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max 1489 : root->height ); 1490 1491 /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */ 1492 /* Adjust underline position from top edge to centre of */ 1493 /* stroke to convert TrueType meaning to FreeType meaning. */ 1494 root->underline_position = face->postscript.underlinePosition - 1495 face->postscript.underlineThickness / 2; 1496 root->underline_thickness = face->postscript.underlineThickness; 1497 } 1498 1499 } 1500 1501 Exit: 1502 FT_TRACE2(( "sfnt_load_face: done\n" )); 1503 1504 return error; 1505 } 1506 1507 1508 #undef LOAD_ 1509 #undef LOADM_ 1510 #undef GET_NAME 1511 1512 1513 FT_LOCAL_DEF( void ) 1514 sfnt_done_face( TT_Face face ) 1515 { 1516 FT_Memory memory; 1517 SFNT_Service sfnt; 1518 1519 1520 if ( !face ) 1521 return; 1522 1523 memory = face->root.memory; 1524 sfnt = (SFNT_Service)face->sfnt; 1525 1526 if ( sfnt ) 1527 { 1528 /* destroy the postscript names table if it is loaded */ 1529 if ( sfnt->free_psnames ) 1530 sfnt->free_psnames( face ); 1531 1532 /* destroy the embedded bitmaps table if it is loaded */ 1533 if ( sfnt->free_eblc ) 1534 sfnt->free_eblc( face ); 1535 } 1536 1537 #ifdef TT_CONFIG_OPTION_BDF 1538 /* freeing the embedded BDF properties */ 1539 tt_face_free_bdf_props( face ); 1540 #endif 1541 1542 /* freeing the kerning table */ 1543 tt_face_done_kern( face ); 1544 1545 /* freeing the collection table */ 1546 FT_FREE( face->ttc_header.offsets ); 1547 face->ttc_header.count = 0; 1548 1549 /* freeing table directory */ 1550 FT_FREE( face->dir_tables ); 1551 face->num_tables = 0; 1552 1553 { 1554 FT_Stream stream = FT_FACE_STREAM( face ); 1555 1556 1557 /* simply release the 'cmap' table frame */ 1558 FT_FRAME_RELEASE( face->cmap_table ); 1559 face->cmap_size = 0; 1560 } 1561 1562 /* freeing the horizontal metrics */ 1563 { 1564 FT_Stream stream = FT_FACE_STREAM( face ); 1565 1566 1567 FT_FRAME_RELEASE( face->horz_metrics ); 1568 FT_FRAME_RELEASE( face->vert_metrics ); 1569 face->horz_metrics_size = 0; 1570 face->vert_metrics_size = 0; 1571 } 1572 1573 /* freeing the vertical ones, if any */ 1574 if ( face->vertical_info ) 1575 { 1576 FT_FREE( face->vertical.long_metrics ); 1577 FT_FREE( face->vertical.short_metrics ); 1578 face->vertical_info = 0; 1579 } 1580 1581 /* freeing the gasp table */ 1582 FT_FREE( face->gasp.gaspRanges ); 1583 face->gasp.numRanges = 0; 1584 1585 /* freeing the name table */ 1586 if ( sfnt ) 1587 sfnt->free_name( face ); 1588 1589 /* freeing family and style name */ 1590 FT_FREE( face->root.family_name ); 1591 FT_FREE( face->root.style_name ); 1592 1593 /* freeing sbit size table */ 1594 FT_FREE( face->root.available_sizes ); 1595 face->root.num_fixed_sizes = 0; 1596 1597 FT_FREE( face->postscript_name ); 1598 1599 face->sfnt = NULL; 1600 } 1601 1602 1603 /* END */ 1604