1 /***************************************************************************/ 2 /* */ 3 /* sfobjs.c */ 4 /* */ 5 /* SFNT object management (base). */ 6 /* */ 7 /* Copyright 1996-2016 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 don't support Multiple Master CFFs yet */ 953 if ( !face->goto_table( face, TTAG_CFF, stream, 0 ) ) 954 num_instances = 0; 955 956 /* we support at most 2^15 - 1 instances */ 957 if ( num_instances >= ( 1U << 15 ) - 1 ) 958 { 959 if ( face_instance_index >= 0 ) 960 return FT_THROW( Invalid_Argument ); 961 else 962 num_instances = 0; 963 } 964 965 /* instance indices in `face_instance_index' start with index 1, */ 966 /* thus `>' and not `>=' */ 967 if ( instance_index > num_instances ) 968 { 969 if ( face_instance_index >= 0 ) 970 return FT_THROW( Invalid_Argument ); 971 else 972 num_instances = 0; 973 } 974 975 face->root.style_flags = (FT_Long)num_instances << 16; 976 } 977 #endif 978 979 face->root.num_faces = face->ttc_header.count; 980 face->root.face_index = face_instance_index; 981 982 return error; 983 } 984 985 986 #define LOAD_( x ) \ 987 do \ 988 { \ 989 FT_TRACE2(( "`" #x "' " )); \ 990 FT_TRACE3(( "-->\n" )); \ 991 \ 992 error = sfnt->load_ ## x( face, stream ); \ 993 \ 994 FT_TRACE2(( "%s\n", ( !error ) \ 995 ? "loaded" \ 996 : FT_ERR_EQ( error, Table_Missing ) \ 997 ? "missing" \ 998 : "failed to load" )); \ 999 FT_TRACE3(( "\n" )); \ 1000 } while ( 0 ) 1001 1002 #define LOADM_( x, vertical ) \ 1003 do \ 1004 { \ 1005 FT_TRACE2(( "`%s" #x "' ", \ 1006 vertical ? "vertical " : "" )); \ 1007 FT_TRACE3(( "-->\n" )); \ 1008 \ 1009 error = sfnt->load_ ## x( face, stream, vertical ); \ 1010 \ 1011 FT_TRACE2(( "%s\n", ( !error ) \ 1012 ? "loaded" \ 1013 : FT_ERR_EQ( error, Table_Missing ) \ 1014 ? "missing" \ 1015 : "failed to load" )); \ 1016 FT_TRACE3(( "\n" )); \ 1017 } while ( 0 ) 1018 1019 #define GET_NAME( id, field ) \ 1020 do \ 1021 { \ 1022 error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \ 1023 if ( error ) \ 1024 goto Exit; \ 1025 } while ( 0 ) 1026 1027 1028 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)1029 sfnt_load_face( FT_Stream stream, 1030 TT_Face face, 1031 FT_Int face_instance_index, 1032 FT_Int num_params, 1033 FT_Parameter* params ) 1034 { 1035 FT_Error error; 1036 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 1037 FT_Error psnames_error; 1038 #endif 1039 FT_Bool has_outline; 1040 FT_Bool is_apple_sbit; 1041 FT_Bool is_apple_sbix; 1042 FT_Bool ignore_preferred_family = FALSE; 1043 FT_Bool ignore_preferred_subfamily = FALSE; 1044 1045 SFNT_Service sfnt = (SFNT_Service)face->sfnt; 1046 1047 FT_UNUSED( face_instance_index ); 1048 1049 1050 /* Check parameters */ 1051 1052 { 1053 FT_Int i; 1054 1055 1056 for ( i = 0; i < num_params; i++ ) 1057 { 1058 if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY ) 1059 ignore_preferred_family = TRUE; 1060 else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY ) 1061 ignore_preferred_subfamily = TRUE; 1062 } 1063 } 1064 1065 /* Load tables */ 1066 1067 /* We now support two SFNT-based bitmapped font formats. They */ 1068 /* are recognized easily as they do not include a `glyf' */ 1069 /* table. */ 1070 /* */ 1071 /* The first format comes from Apple, and uses a table named */ 1072 /* `bhed' instead of `head' to store the font header (using */ 1073 /* the same format). It also doesn't include horizontal and */ 1074 /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ 1075 /* missing). */ 1076 /* */ 1077 /* The other format comes from Microsoft, and is used with */ 1078 /* WinCE/PocketPC. It looks like a standard TTF, except that */ 1079 /* it doesn't contain outlines. */ 1080 /* */ 1081 1082 FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); 1083 1084 /* do we have outlines in there? */ 1085 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1086 has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || 1087 tt_face_lookup_table( face, TTAG_glyf ) != 0 || 1088 tt_face_lookup_table( face, TTAG_CFF ) != 0 ); 1089 #else 1090 has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 || 1091 tt_face_lookup_table( face, TTAG_CFF ) != 0 ); 1092 #endif 1093 1094 is_apple_sbit = 0; 1095 is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); 1096 1097 /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf' 1098 * outline rendered on top. We don't support that yet, so just ignore 1099 * the 'glyf' outline and advertise it as a bitmap-only font. */ 1100 if ( is_apple_sbix ) 1101 has_outline = FALSE; 1102 1103 /* if this font doesn't contain outlines, we try to load */ 1104 /* a `bhed' table */ 1105 if ( !has_outline && sfnt->load_bhed ) 1106 { 1107 LOAD_( bhed ); 1108 is_apple_sbit = FT_BOOL( !error ); 1109 } 1110 1111 /* load the font header (`head' table) if this isn't an Apple */ 1112 /* sbit font file */ 1113 if ( !is_apple_sbit || is_apple_sbix ) 1114 { 1115 LOAD_( head ); 1116 if ( error ) 1117 goto Exit; 1118 } 1119 1120 if ( face->header.Units_Per_EM == 0 ) 1121 { 1122 error = FT_THROW( Invalid_Table ); 1123 1124 goto Exit; 1125 } 1126 1127 /* the following tables are often not present in embedded TrueType */ 1128 /* fonts within PDF documents, so don't check for them. */ 1129 LOAD_( maxp ); 1130 LOAD_( cmap ); 1131 1132 /* the following tables are optional in PCL fonts -- */ 1133 /* don't check for errors */ 1134 LOAD_( name ); 1135 LOAD_( post ); 1136 1137 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 1138 psnames_error = error; 1139 #endif 1140 1141 /* do not load the metrics headers and tables if this is an Apple */ 1142 /* sbit font file */ 1143 if ( !is_apple_sbit ) 1144 { 1145 /* load the `hhea' and `hmtx' tables */ 1146 LOADM_( hhea, 0 ); 1147 if ( !error ) 1148 { 1149 LOADM_( hmtx, 0 ); 1150 if ( FT_ERR_EQ( error, Table_Missing ) ) 1151 { 1152 error = FT_THROW( Hmtx_Table_Missing ); 1153 1154 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1155 /* If this is an incrementally loaded font and there are */ 1156 /* overriding metrics, tolerate a missing `hmtx' table. */ 1157 if ( face->root.internal->incremental_interface && 1158 face->root.internal->incremental_interface->funcs-> 1159 get_glyph_metrics ) 1160 { 1161 face->horizontal.number_Of_HMetrics = 0; 1162 error = FT_Err_Ok; 1163 } 1164 #endif 1165 } 1166 } 1167 else if ( FT_ERR_EQ( error, Table_Missing ) ) 1168 { 1169 /* No `hhea' table necessary for SFNT Mac fonts. */ 1170 if ( face->format_tag == TTAG_true ) 1171 { 1172 FT_TRACE2(( "This is an SFNT Mac font.\n" )); 1173 1174 has_outline = 0; 1175 error = FT_Err_Ok; 1176 } 1177 else 1178 { 1179 error = FT_THROW( Horiz_Header_Missing ); 1180 1181 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1182 /* If this is an incrementally loaded font and there are */ 1183 /* overriding metrics, tolerate a missing `hhea' table. */ 1184 if ( face->root.internal->incremental_interface && 1185 face->root.internal->incremental_interface->funcs-> 1186 get_glyph_metrics ) 1187 { 1188 face->horizontal.number_Of_HMetrics = 0; 1189 error = FT_Err_Ok; 1190 } 1191 #endif 1192 1193 } 1194 } 1195 1196 if ( error ) 1197 goto Exit; 1198 1199 /* try to load the `vhea' and `vmtx' tables */ 1200 LOADM_( hhea, 1 ); 1201 if ( !error ) 1202 { 1203 LOADM_( hmtx, 1 ); 1204 if ( !error ) 1205 face->vertical_info = 1; 1206 } 1207 1208 if ( error && FT_ERR_NEQ( error, Table_Missing ) ) 1209 goto Exit; 1210 1211 LOAD_( os2 ); 1212 if ( error ) 1213 { 1214 /* we treat the table as missing if there are any errors */ 1215 face->os2.version = 0xFFFFU; 1216 } 1217 } 1218 1219 /* the optional tables */ 1220 1221 /* embedded bitmap support */ 1222 if ( sfnt->load_eblc ) 1223 { 1224 LOAD_( eblc ); 1225 if ( error ) 1226 { 1227 /* a font which contains neither bitmaps nor outlines is */ 1228 /* still valid (although rather useless in most cases); */ 1229 /* however, you can find such stripped fonts in PDFs */ 1230 if ( FT_ERR_EQ( error, Table_Missing ) ) 1231 error = FT_Err_Ok; 1232 else 1233 goto Exit; 1234 } 1235 } 1236 1237 LOAD_( pclt ); 1238 if ( error ) 1239 { 1240 if ( FT_ERR_NEQ( error, Table_Missing ) ) 1241 goto Exit; 1242 1243 face->pclt.Version = 0; 1244 } 1245 1246 /* consider the kerning and gasp tables as optional */ 1247 LOAD_( gasp ); 1248 LOAD_( kern ); 1249 1250 face->root.num_glyphs = face->max_profile.numGlyphs; 1251 1252 /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ 1253 /* a WWS-only font face. `WWS' stands for `weight', width', and */ 1254 /* `slope', a term used by Microsoft's Windows Presentation */ 1255 /* Foundation (WPF). This flag has been introduced in version */ 1256 /* 1.5 of the OpenType specification (May 2008). */ 1257 1258 face->root.family_name = NULL; 1259 face->root.style_name = NULL; 1260 if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 ) 1261 { 1262 if ( !ignore_preferred_family ) 1263 GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); 1264 if ( !face->root.family_name ) 1265 GET_NAME( FONT_FAMILY, &face->root.family_name ); 1266 1267 if ( !ignore_preferred_subfamily ) 1268 GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); 1269 if ( !face->root.style_name ) 1270 GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); 1271 } 1272 else 1273 { 1274 GET_NAME( WWS_FAMILY, &face->root.family_name ); 1275 if ( !face->root.family_name && !ignore_preferred_family ) 1276 GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); 1277 if ( !face->root.family_name ) 1278 GET_NAME( FONT_FAMILY, &face->root.family_name ); 1279 1280 GET_NAME( WWS_SUBFAMILY, &face->root.style_name ); 1281 if ( !face->root.style_name && !ignore_preferred_subfamily ) 1282 GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); 1283 if ( !face->root.style_name ) 1284 GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); 1285 } 1286 1287 /* now set up root fields */ 1288 { 1289 FT_Face root = &face->root; 1290 FT_Long flags = root->face_flags; 1291 1292 1293 /*********************************************************************/ 1294 /* */ 1295 /* Compute face flags. */ 1296 /* */ 1297 if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || 1298 face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX ) 1299 flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ 1300 1301 if ( has_outline == TRUE ) 1302 flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ 1303 1304 /* The sfnt driver only supports bitmap fonts natively, thus we */ 1305 /* don't set FT_FACE_FLAG_HINTER. */ 1306 flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */ 1307 FT_FACE_FLAG_HORIZONTAL; /* horizontal data */ 1308 1309 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 1310 if ( !psnames_error && 1311 face->postscript.FormatType != 0x00030000L ) 1312 flags |= FT_FACE_FLAG_GLYPH_NAMES; 1313 #endif 1314 1315 /* fixed width font? */ 1316 if ( face->postscript.isFixedPitch ) 1317 flags |= FT_FACE_FLAG_FIXED_WIDTH; 1318 1319 /* vertical information? */ 1320 if ( face->vertical_info ) 1321 flags |= FT_FACE_FLAG_VERTICAL; 1322 1323 /* kerning available ? */ 1324 if ( TT_FACE_HAS_KERNING( face ) ) 1325 flags |= FT_FACE_FLAG_KERNING; 1326 1327 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 1328 /* Don't bother to load the tables unless somebody asks for them. */ 1329 /* No need to do work which will (probably) not be used. */ 1330 if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && 1331 tt_face_lookup_table( face, TTAG_fvar ) != 0 && 1332 tt_face_lookup_table( face, TTAG_gvar ) != 0 ) 1333 flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; 1334 #endif 1335 1336 root->face_flags = flags; 1337 1338 /*********************************************************************/ 1339 /* */ 1340 /* Compute style flags. */ 1341 /* */ 1342 1343 flags = 0; 1344 if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) 1345 { 1346 /* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ 1347 /* indicates an oblique font face. This flag has been */ 1348 /* introduced in version 1.5 of the OpenType specification. */ 1349 1350 if ( face->os2.fsSelection & 512 ) /* bit 9 */ 1351 flags |= FT_STYLE_FLAG_ITALIC; 1352 else if ( face->os2.fsSelection & 1 ) /* bit 0 */ 1353 flags |= FT_STYLE_FLAG_ITALIC; 1354 1355 if ( face->os2.fsSelection & 32 ) /* bit 5 */ 1356 flags |= FT_STYLE_FLAG_BOLD; 1357 } 1358 else 1359 { 1360 /* this is an old Mac font, use the header field */ 1361 1362 if ( face->header.Mac_Style & 1 ) 1363 flags |= FT_STYLE_FLAG_BOLD; 1364 1365 if ( face->header.Mac_Style & 2 ) 1366 flags |= FT_STYLE_FLAG_ITALIC; 1367 } 1368 1369 root->style_flags |= flags; 1370 1371 /*********************************************************************/ 1372 /* */ 1373 /* Polish the charmaps. */ 1374 /* */ 1375 /* Try to set the charmap encoding according to the platform & */ 1376 /* encoding ID of each charmap. */ 1377 /* */ 1378 1379 tt_face_build_cmaps( face ); /* ignore errors */ 1380 1381 1382 /* set the encoding fields */ 1383 { 1384 FT_Int m; 1385 1386 1387 for ( m = 0; m < root->num_charmaps; m++ ) 1388 { 1389 FT_CharMap charmap = root->charmaps[m]; 1390 1391 1392 charmap->encoding = sfnt_find_encoding( charmap->platform_id, 1393 charmap->encoding_id ); 1394 1395 #if 0 1396 if ( root->charmap == NULL && 1397 charmap->encoding == FT_ENCODING_UNICODE ) 1398 { 1399 /* set 'root->charmap' to the first Unicode encoding we find */ 1400 root->charmap = charmap; 1401 } 1402 #endif 1403 } 1404 } 1405 1406 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 1407 1408 /* 1409 * Now allocate the root array of FT_Bitmap_Size records and 1410 * populate them. Unfortunately, it isn't possible to indicate bit 1411 * depths in the FT_Bitmap_Size record. This is a design error. 1412 */ 1413 { 1414 FT_UInt i, count; 1415 1416 1417 count = face->sbit_num_strikes; 1418 1419 if ( count > 0 ) 1420 { 1421 FT_Memory memory = face->root.stream->memory; 1422 FT_UShort em_size = face->header.Units_Per_EM; 1423 FT_Short avgwidth = face->os2.xAvgCharWidth; 1424 FT_Size_Metrics metrics; 1425 1426 1427 if ( em_size == 0 || face->os2.version == 0xFFFFU ) 1428 { 1429 avgwidth = 1; 1430 em_size = 1; 1431 } 1432 1433 if ( FT_NEW_ARRAY( root->available_sizes, count ) ) 1434 goto Exit; 1435 1436 for ( i = 0; i < count; i++ ) 1437 { 1438 FT_Bitmap_Size* bsize = root->available_sizes + i; 1439 1440 1441 error = sfnt->load_strike_metrics( face, i, &metrics ); 1442 if ( error ) 1443 goto Exit; 1444 1445 bsize->height = (FT_Short)( metrics.height >> 6 ); 1446 bsize->width = (FT_Short)( 1447 ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); 1448 1449 bsize->x_ppem = metrics.x_ppem << 6; 1450 bsize->y_ppem = metrics.y_ppem << 6; 1451 1452 /* assume 72dpi */ 1453 bsize->size = metrics.y_ppem << 6; 1454 } 1455 1456 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; 1457 root->num_fixed_sizes = (FT_Int)count; 1458 } 1459 } 1460 1461 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ 1462 1463 /* a font with no bitmaps and no outlines is scalable; */ 1464 /* it has only empty glyphs then */ 1465 if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) 1466 root->face_flags |= FT_FACE_FLAG_SCALABLE; 1467 1468 1469 /*********************************************************************/ 1470 /* */ 1471 /* Set up metrics. */ 1472 /* */ 1473 if ( FT_IS_SCALABLE( root ) ) 1474 { 1475 /* XXX What about if outline header is missing */ 1476 /* (e.g. sfnt wrapped bitmap)? */ 1477 root->bbox.xMin = face->header.xMin; 1478 root->bbox.yMin = face->header.yMin; 1479 root->bbox.xMax = face->header.xMax; 1480 root->bbox.yMax = face->header.yMax; 1481 root->units_per_EM = face->header.Units_Per_EM; 1482 1483 1484 /* XXX: Computing the ascender/descender/height is very different */ 1485 /* from what the specification tells you. Apparently, we */ 1486 /* must be careful because */ 1487 /* */ 1488 /* - not all fonts have an OS/2 table; in this case, we take */ 1489 /* the values in the horizontal header. However, these */ 1490 /* values very often are not reliable. */ 1491 /* */ 1492 /* - otherwise, the correct typographic values are in the */ 1493 /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ 1494 /* */ 1495 /* However, certain fonts have these fields set to 0. */ 1496 /* Rather, they have usWinAscent & usWinDescent correctly */ 1497 /* set (but with different values). */ 1498 /* */ 1499 /* As an example, Arial Narrow is implemented through four */ 1500 /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ 1501 /* */ 1502 /* Strangely, all fonts have the same values in their */ 1503 /* sTypoXXX fields, except ARIALNB which sets them to 0. */ 1504 /* */ 1505 /* On the other hand, they all have different */ 1506 /* usWinAscent/Descent values -- as a conclusion, the OS/2 */ 1507 /* table cannot be used to compute the text height reliably! */ 1508 /* */ 1509 1510 /* The ascender and descender are taken from the `hhea' table. */ 1511 /* If zero, they are taken from the `OS/2' table. */ 1512 1513 root->ascender = face->horizontal.Ascender; 1514 root->descender = face->horizontal.Descender; 1515 1516 root->height = root->ascender - root->descender + 1517 face->horizontal.Line_Gap; 1518 1519 if ( !( root->ascender || root->descender ) ) 1520 { 1521 if ( face->os2.version != 0xFFFFU ) 1522 { 1523 if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) 1524 { 1525 root->ascender = face->os2.sTypoAscender; 1526 root->descender = face->os2.sTypoDescender; 1527 1528 root->height = root->ascender - root->descender + 1529 face->os2.sTypoLineGap; 1530 } 1531 else 1532 { 1533 root->ascender = (FT_Short)face->os2.usWinAscent; 1534 root->descender = -(FT_Short)face->os2.usWinDescent; 1535 1536 root->height = root->ascender - root->descender; 1537 } 1538 } 1539 } 1540 1541 root->max_advance_width = 1542 (FT_Short)face->horizontal.advance_Width_Max; 1543 root->max_advance_height = 1544 (FT_Short)( face->vertical_info ? face->vertical.advance_Height_Max 1545 : root->height ); 1546 1547 /* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */ 1548 /* Adjust underline position from top edge to centre of */ 1549 /* stroke to convert TrueType meaning to FreeType meaning. */ 1550 root->underline_position = face->postscript.underlinePosition - 1551 face->postscript.underlineThickness / 2; 1552 root->underline_thickness = face->postscript.underlineThickness; 1553 } 1554 1555 } 1556 1557 Exit: 1558 FT_TRACE2(( "sfnt_load_face: done\n" )); 1559 1560 return error; 1561 } 1562 1563 1564 #undef LOAD_ 1565 #undef LOADM_ 1566 #undef GET_NAME 1567 1568 1569 FT_LOCAL_DEF( void ) sfnt_done_face(TT_Face face)1570 sfnt_done_face( TT_Face face ) 1571 { 1572 FT_Memory memory; 1573 SFNT_Service sfnt; 1574 1575 1576 if ( !face ) 1577 return; 1578 1579 memory = face->root.memory; 1580 sfnt = (SFNT_Service)face->sfnt; 1581 1582 if ( sfnt ) 1583 { 1584 /* destroy the postscript names table if it is loaded */ 1585 if ( sfnt->free_psnames ) 1586 sfnt->free_psnames( face ); 1587 1588 /* destroy the embedded bitmaps table if it is loaded */ 1589 if ( sfnt->free_eblc ) 1590 sfnt->free_eblc( face ); 1591 } 1592 1593 #ifdef TT_CONFIG_OPTION_BDF 1594 /* freeing the embedded BDF properties */ 1595 tt_face_free_bdf_props( face ); 1596 #endif 1597 1598 /* freeing the kerning table */ 1599 tt_face_done_kern( face ); 1600 1601 /* freeing the collection table */ 1602 FT_FREE( face->ttc_header.offsets ); 1603 face->ttc_header.count = 0; 1604 1605 /* freeing table directory */ 1606 FT_FREE( face->dir_tables ); 1607 face->num_tables = 0; 1608 1609 { 1610 FT_Stream stream = FT_FACE_STREAM( face ); 1611 1612 1613 /* simply release the 'cmap' table frame */ 1614 FT_FRAME_RELEASE( face->cmap_table ); 1615 face->cmap_size = 0; 1616 } 1617 1618 /* freeing the horizontal metrics */ 1619 { 1620 FT_Stream stream = FT_FACE_STREAM( face ); 1621 1622 1623 FT_FRAME_RELEASE( face->horz_metrics ); 1624 FT_FRAME_RELEASE( face->vert_metrics ); 1625 face->horz_metrics_size = 0; 1626 face->vert_metrics_size = 0; 1627 } 1628 1629 /* freeing the vertical ones, if any */ 1630 if ( face->vertical_info ) 1631 { 1632 FT_FREE( face->vertical.long_metrics ); 1633 FT_FREE( face->vertical.short_metrics ); 1634 face->vertical_info = 0; 1635 } 1636 1637 /* freeing the gasp table */ 1638 FT_FREE( face->gasp.gaspRanges ); 1639 face->gasp.numRanges = 0; 1640 1641 /* freeing the name table */ 1642 if ( sfnt ) 1643 sfnt->free_name( face ); 1644 1645 /* freeing family and style name */ 1646 FT_FREE( face->root.family_name ); 1647 FT_FREE( face->root.style_name ); 1648 1649 /* freeing sbit size table */ 1650 FT_FREE( face->root.available_sizes ); 1651 face->root.num_fixed_sizes = 0; 1652 1653 FT_FREE( face->postscript_name ); 1654 1655 face->sfnt = NULL; 1656 } 1657 1658 1659 /* END */ 1660