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