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