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