1 /***************************************************************************/ 2 /* */ 3 /* ttload.c */ 4 /* */ 5 /* Load the basic TrueType tables, i.e., tables that can be either in */ 6 /* TTF or OTF fonts (body). */ 7 /* */ 8 /* Copyright 1996-2001, 2002 by */ 9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 10 /* */ 11 /* This file is part of the FreeType project, and may only be used, */ 12 /* modified, and distributed under the terms of the FreeType project */ 13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 14 /* this file you indicate that you have read the license and */ 15 /* understand and accept it fully. */ 16 /* */ 17 /***************************************************************************/ 18 19 20 #include <ft2build.h> 21 #include FT_INTERNAL_DEBUG_H 22 #include FT_INTERNAL_STREAM_H 23 #include FT_TRUETYPE_TAGS_H 24 #include "ttload.h" 25 #include "ttcmap.h" 26 27 #include "sferrors.h" 28 29 30 /*************************************************************************/ 31 /* */ 32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 34 /* messages during execution. */ 35 /* */ 36 #undef FT_COMPONENT 37 #define FT_COMPONENT trace_ttload 38 39 40 /*************************************************************************/ 41 /* */ 42 /* <Function> */ 43 /* tt_face_lookup_table */ 44 /* */ 45 /* <Description> */ 46 /* Looks for a TrueType table by name. */ 47 /* */ 48 /* <Input> */ 49 /* face :: A face object handle. */ 50 /* */ 51 /* tag :: The searched tag. */ 52 /* */ 53 /* <Return> */ 54 /* A pointer to the table directory entry. 0 if not found. */ 55 /* */ 56 FT_LOCAL_DEF( TT_Table ) tt_face_lookup_table(TT_Face face,FT_ULong tag)57 tt_face_lookup_table( TT_Face face, 58 FT_ULong tag ) 59 { 60 TT_Table entry; 61 TT_Table limit; 62 63 64 FT_TRACE3(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ", 65 face, 66 (FT_Char)( tag >> 24 ), 67 (FT_Char)( tag >> 16 ), 68 (FT_Char)( tag >> 8 ), 69 (FT_Char)( tag ) )); 70 71 entry = face->dir_tables; 72 limit = entry + face->num_tables; 73 74 for ( ; entry < limit; entry++ ) 75 { 76 /* For compatibility with Windows, we consider 0-length */ 77 /* tables the same as missing tables. */ 78 if ( entry->Tag == tag && entry->Length != 0 ) 79 { 80 FT_TRACE3(( "found table.\n" )); 81 return entry; 82 } 83 } 84 85 FT_TRACE3(( "could not find table!\n" )); 86 return 0; 87 } 88 89 90 /*************************************************************************/ 91 /* */ 92 /* <Function> */ 93 /* tt_face_goto_table */ 94 /* */ 95 /* <Description> */ 96 /* Looks for a TrueType table by name, then seek a stream to it. */ 97 /* */ 98 /* <Input> */ 99 /* face :: A face object handle. */ 100 /* */ 101 /* tag :: The searched tag. */ 102 /* */ 103 /* stream :: The stream to seek when the table is found. */ 104 /* */ 105 /* <Output> */ 106 /* length :: The length of the table if found, undefined otherwise. */ 107 /* */ 108 /* <Return> */ 109 /* FreeType error code. 0 means success. */ 110 /* */ 111 FT_LOCAL_DEF( FT_Error ) tt_face_goto_table(TT_Face face,FT_ULong tag,FT_Stream stream,FT_ULong * length)112 tt_face_goto_table( TT_Face face, 113 FT_ULong tag, 114 FT_Stream stream, 115 FT_ULong* length ) 116 { 117 TT_Table table; 118 FT_Error error; 119 120 121 table = tt_face_lookup_table( face, tag ); 122 if ( table ) 123 { 124 if ( length ) 125 *length = table->Length; 126 127 if ( FT_STREAM_SEEK( table->Offset ) ) 128 goto Exit; 129 } 130 else 131 error = SFNT_Err_Table_Missing; 132 133 Exit: 134 return error; 135 } 136 137 138 /* In theory, we should check the values of `search_range', */ 139 /* `entry_selector', and `range_shift' to detect non-SFNT based files */ 140 /* whose header might also start with 0x100000L (yes, these exist). */ 141 /* */ 142 /* Very unfortunately, many TrueType fonts don't have these fields */ 143 /* set correctly and we must ignore them to support them. An alternative */ 144 /* way to check the font file is thus to: */ 145 /* */ 146 /* - check that `num_tables' is valid */ 147 /* - look for a "head" table, check its size, and parse it to */ 148 /* see if its "magic" field is correctly set */ 149 /* */ 150 /* When checking directory entries, ignore the tables `glyx' and `locx' */ 151 /* which are hacked-out versions of `glyf' and `loca' in some PostScript */ 152 /* Type 42 fonts, and will generally be invalid. */ 153 /* */ 154 static FT_Error sfnt_dir_check(FT_Stream stream,FT_ULong offset,FT_UInt num_tables)155 sfnt_dir_check( FT_Stream stream, 156 FT_ULong offset, 157 FT_UInt num_tables ) 158 { 159 FT_Error error; 160 FT_UInt nn, has_head = 0; 161 162 const FT_ULong glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' ); 163 const FT_ULong locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' ); 164 165 static const FT_Frame_Field sfnt_dir_entry_fields[] = 166 { 167 #undef FT_STRUCTURE 168 #define FT_STRUCTURE TT_TableRec 169 170 FT_FRAME_START( 16 ), 171 FT_FRAME_ULONG( Tag ), 172 FT_FRAME_ULONG( CheckSum ), 173 FT_FRAME_ULONG( Offset ), 174 FT_FRAME_ULONG( Length ), 175 FT_FRAME_END 176 }; 177 178 179 /* if 'num_tables' is 0, read the table count from the file */ 180 if ( num_tables == 0 ) 181 { 182 FT_ULong format_tag; 183 184 185 if ( FT_STREAM_SEEK( offset ) || 186 FT_READ_ULONG ( format_tag ) || 187 FT_READ_USHORT( num_tables ) || 188 FT_STREAM_SKIP( 6 ) ) 189 goto Bad_Format; 190 191 if ( offset + 12 + num_tables*16 > stream->size ) 192 goto Bad_Format; 193 } 194 else if ( FT_STREAM_SEEK( offset + 12 ) ) 195 goto Bad_Format; 196 197 for ( nn = 0; nn < num_tables; nn++ ) 198 { 199 TT_TableRec table; 200 201 202 if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) ) 203 goto Bad_Format; 204 205 if ( table.Offset + table.Length > stream->size && 206 table.Tag != glyx_tag && table.Tag != locx_tag ) 207 goto Bad_Format; 208 209 if ( table.Tag == TTAG_head ) 210 { 211 FT_UInt32 magic; 212 213 214 has_head = 1; 215 216 if ( table.Length != 0x36 || 217 FT_STREAM_SEEK( table.Offset + 12 ) || 218 FT_READ_ULONG( magic ) || 219 magic != 0x5F0F3CF5UL ) 220 goto Bad_Format; 221 222 if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) ) 223 goto Bad_Format; 224 } 225 } 226 227 if ( has_head == 0 ) 228 goto Bad_Format; 229 230 Exit: 231 return error; 232 233 Bad_Format: 234 error = FT_Err_Unknown_File_Format; 235 goto Exit; 236 } 237 238 239 /*************************************************************************/ 240 /* */ 241 /* <Function> */ 242 /* tt_face_load_sfnt_header */ 243 /* */ 244 /* <Description> */ 245 /* Loads the header of a SFNT font file. Supports collections. */ 246 /* */ 247 /* <Input> */ 248 /* face :: A handle to the target face object. */ 249 /* */ 250 /* stream :: The input stream. */ 251 /* */ 252 /* face_index :: If the font is a collection, the number of the font */ 253 /* in the collection, ignored otherwise. */ 254 /* */ 255 /* <Output> */ 256 /* sfnt :: The SFNT header. */ 257 /* */ 258 /* <Return> */ 259 /* FreeType error code. 0 means success. */ 260 /* */ 261 /* <Note> */ 262 /* The stream cursor must be at the font file's origin. */ 263 /* */ 264 /* This function recognizes fonts embedded in a `TrueType collection' */ 265 /* */ 266 /* The header will be checked whether it is valid by looking at the */ 267 /* values of `search_range', `entry_selector', and `range_shift'. */ 268 /* */ 269 FT_LOCAL_DEF( FT_Error ) tt_face_load_sfnt_header(TT_Face face,FT_Stream stream,FT_Long face_index,SFNT_Header sfnt)270 tt_face_load_sfnt_header( TT_Face face, 271 FT_Stream stream, 272 FT_Long face_index, 273 SFNT_Header sfnt ) 274 { 275 FT_Error error; 276 FT_ULong format_tag, offset; 277 FT_Memory memory = stream->memory; 278 279 static const FT_Frame_Field sfnt_header_fields[] = 280 { 281 #undef FT_STRUCTURE 282 #define FT_STRUCTURE SFNT_HeaderRec 283 284 FT_FRAME_START( 8 ), 285 FT_FRAME_USHORT( num_tables ), 286 FT_FRAME_USHORT( search_range ), 287 FT_FRAME_USHORT( entry_selector ), 288 FT_FRAME_USHORT( range_shift ), 289 FT_FRAME_END 290 }; 291 292 static const FT_Frame_Field ttc_header_fields[] = 293 { 294 #undef FT_STRUCTURE 295 #define FT_STRUCTURE TTC_HeaderRec 296 297 FT_FRAME_START( 8 ), 298 FT_FRAME_LONG( version ), 299 FT_FRAME_LONG( count ), 300 FT_FRAME_END 301 }; 302 303 304 FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n", 305 face, face_index )); 306 307 face->ttc_header.tag = 0; 308 face->ttc_header.version = 0; 309 face->ttc_header.count = 0; 310 311 face->num_tables = 0; 312 313 /* first of all, read the first 4 bytes. If it is `ttcf', then the */ 314 /* file is a TrueType collection, otherwise it can be any other */ 315 /* kind of font. */ 316 /* */ 317 offset = FT_STREAM_POS(); 318 319 if ( FT_READ_ULONG( format_tag ) ) 320 goto Exit; 321 322 if ( format_tag == TTAG_ttcf ) 323 { 324 FT_Int n; 325 326 327 FT_TRACE3(( "tt_face_load_sfnt_header: file is a collection\n" )); 328 329 /* It is a TrueType collection, i.e. a file containing several */ 330 /* font files. Read the font directory now */ 331 if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) 332 goto Exit; 333 334 /* now read the offsets of each font in the file */ 335 if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) || 336 FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) 337 goto Exit; 338 339 for ( n = 0; n < face->ttc_header.count; n++ ) 340 face->ttc_header.offsets[n] = FT_GET_ULONG(); 341 342 FT_FRAME_EXIT(); 343 344 /* check face index */ 345 if ( face_index >= face->ttc_header.count ) 346 { 347 error = SFNT_Err_Bad_Argument; 348 goto Exit; 349 } 350 351 /* seek to the appropriate TrueType file, then read tag */ 352 offset = face->ttc_header.offsets[face_index]; 353 354 if ( FT_STREAM_SEEK( offset ) || 355 FT_READ_LONG( format_tag ) ) 356 goto Exit; 357 } 358 359 /* the format tag was read, now check the rest of the header */ 360 sfnt->format_tag = format_tag; 361 sfnt->offset = offset; 362 363 if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) ) 364 goto Exit; 365 366 /* now check the sfnt directory */ 367 error = sfnt_dir_check( stream, offset, sfnt->num_tables ); 368 if ( error ) 369 { 370 FT_TRACE2(( "tt_face_load_sfnt_header: file is not SFNT!\n" )); 371 error = SFNT_Err_Unknown_File_Format; 372 } 373 374 Exit: 375 return error; 376 } 377 378 379 /*************************************************************************/ 380 /* */ 381 /* <Function> */ 382 /* tt_face_load_directory */ 383 /* */ 384 /* <Description> */ 385 /* Loads the table directory into a face object. */ 386 /* */ 387 /* <InOut> */ 388 /* face :: A handle to the target face object. */ 389 /* */ 390 /* <Input> */ 391 /* stream :: The input stream. */ 392 /* */ 393 /* sfnt :: The SFNT directory header. */ 394 /* */ 395 /* <Return> */ 396 /* FreeType error code. 0 means success. */ 397 /* */ 398 /* <Note> */ 399 /* The stream cursor must be at the font file's origin. */ 400 /* */ 401 FT_LOCAL_DEF( FT_Error ) tt_face_load_directory(TT_Face face,FT_Stream stream,SFNT_Header sfnt)402 tt_face_load_directory( TT_Face face, 403 FT_Stream stream, 404 SFNT_Header sfnt ) 405 { 406 FT_Error error; 407 FT_Memory memory = stream->memory; 408 409 TT_TableRec *entry, *limit; 410 411 412 FT_TRACE2(( "tt_face_load_directory: %08p\n", face )); 413 414 FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables )); 415 FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag )); 416 417 face->num_tables = sfnt->num_tables; 418 419 if ( FT_NEW_ARRAY( face->dir_tables, face->num_tables ) ) 420 goto Exit; 421 422 if ( FT_STREAM_SEEK( sfnt->offset + 12 ) || 423 FT_FRAME_ENTER( face->num_tables * 16L ) ) 424 goto Exit; 425 426 entry = face->dir_tables; 427 limit = entry + face->num_tables; 428 429 for ( ; entry < limit; entry++ ) 430 { /* loop through the tables and get all entries */ 431 entry->Tag = FT_GET_TAG4(); 432 entry->CheckSum = FT_GET_ULONG(); 433 entry->Offset = FT_GET_LONG(); 434 entry->Length = FT_GET_LONG(); 435 436 FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n", 437 (FT_Char)( entry->Tag >> 24 ), 438 (FT_Char)( entry->Tag >> 16 ), 439 (FT_Char)( entry->Tag >> 8 ), 440 (FT_Char)( entry->Tag ), 441 entry->Offset, 442 entry->Length )); 443 } 444 445 FT_FRAME_EXIT(); 446 447 FT_TRACE2(( "Directory loaded\n\n" )); 448 449 Exit: 450 return error; 451 } 452 453 454 /*************************************************************************/ 455 /* */ 456 /* <Function> */ 457 /* tt_face_load_any */ 458 /* */ 459 /* <Description> */ 460 /* Loads any font table into client memory. */ 461 /* */ 462 /* <Input> */ 463 /* face :: The face object to look for. */ 464 /* */ 465 /* tag :: The tag of table to load. Use the value 0 if you want */ 466 /* to access the whole font file, else set this parameter */ 467 /* to a valid TrueType table tag that you can forge with */ 468 /* the MAKE_TT_TAG macro. */ 469 /* */ 470 /* offset :: The starting offset in the table (or the file if */ 471 /* tag == 0). */ 472 /* */ 473 /* length :: The address of the decision variable: */ 474 /* */ 475 /* If length == NULL: */ 476 /* Loads the whole table. Returns an error if */ 477 /* `offset' == 0! */ 478 /* */ 479 /* If *length == 0: */ 480 /* Exits immediately; returning the length of the given */ 481 /* table or of the font file, depending on the value of */ 482 /* `tag'. */ 483 /* */ 484 /* If *length != 0: */ 485 /* Loads the next `length' bytes of table or font, */ 486 /* starting at offset `offset' (in table or font too). */ 487 /* */ 488 /* <Output> */ 489 /* buffer :: The address of target buffer. */ 490 /* */ 491 /* <Return> */ 492 /* FreeType error code. 0 means success. */ 493 /* */ 494 FT_LOCAL_DEF( FT_Error ) tt_face_load_any(TT_Face face,FT_ULong tag,FT_Long offset,FT_Byte * buffer,FT_ULong * length)495 tt_face_load_any( TT_Face face, 496 FT_ULong tag, 497 FT_Long offset, 498 FT_Byte* buffer, 499 FT_ULong* length ) 500 { 501 FT_Error error; 502 FT_Stream stream; 503 TT_Table table; 504 FT_ULong size; 505 506 507 if ( tag != 0 ) 508 { 509 /* look for tag in font directory */ 510 table = tt_face_lookup_table( face, tag ); 511 if ( !table ) 512 { 513 error = SFNT_Err_Table_Missing; 514 goto Exit; 515 } 516 517 offset += table->Offset; 518 size = table->Length; 519 } 520 else 521 /* tag == 0 -- the user wants to access the font file directly */ 522 size = face->root.stream->size; 523 524 if ( length && *length == 0 ) 525 { 526 *length = size; 527 528 return SFNT_Err_Ok; 529 } 530 531 if ( length ) 532 size = *length; 533 534 stream = face->root.stream; 535 /* the `if' is syntactic sugar for picky compilers */ 536 if ( FT_STREAM_READ_AT( offset, buffer, size ) ) 537 goto Exit; 538 539 Exit: 540 return error; 541 } 542 543 544 /*************************************************************************/ 545 /* */ 546 /* <Function> */ 547 /* tt_face_load_generic_header */ 548 /* */ 549 /* <Description> */ 550 /* Loads the TrueType table `head' or `bhed'. */ 551 /* */ 552 /* <Input> */ 553 /* face :: A handle to the target face object. */ 554 /* */ 555 /* stream :: The input stream. */ 556 /* */ 557 /* <Return> */ 558 /* FreeType error code. 0 means success. */ 559 /* */ 560 static FT_Error tt_face_load_generic_header(TT_Face face,FT_Stream stream,FT_ULong tag)561 tt_face_load_generic_header( TT_Face face, 562 FT_Stream stream, 563 FT_ULong tag ) 564 { 565 FT_Error error; 566 TT_Header* header; 567 568 static const FT_Frame_Field header_fields[] = 569 { 570 #undef FT_STRUCTURE 571 #define FT_STRUCTURE TT_Header 572 573 FT_FRAME_START( 54 ), 574 FT_FRAME_ULONG ( Table_Version ), 575 FT_FRAME_ULONG ( Font_Revision ), 576 FT_FRAME_LONG ( CheckSum_Adjust ), 577 FT_FRAME_LONG ( Magic_Number ), 578 FT_FRAME_USHORT( Flags ), 579 FT_FRAME_USHORT( Units_Per_EM ), 580 FT_FRAME_LONG ( Created[0] ), 581 FT_FRAME_LONG ( Created[1] ), 582 FT_FRAME_LONG ( Modified[0] ), 583 FT_FRAME_LONG ( Modified[1] ), 584 FT_FRAME_SHORT ( xMin ), 585 FT_FRAME_SHORT ( yMin ), 586 FT_FRAME_SHORT ( xMax ), 587 FT_FRAME_SHORT ( yMax ), 588 FT_FRAME_USHORT( Mac_Style ), 589 FT_FRAME_USHORT( Lowest_Rec_PPEM ), 590 FT_FRAME_SHORT ( Font_Direction ), 591 FT_FRAME_SHORT ( Index_To_Loc_Format ), 592 FT_FRAME_SHORT ( Glyph_Data_Format ), 593 FT_FRAME_END 594 }; 595 596 597 FT_TRACE2(( "tt_face_load_generic_header: " 598 "%08p, looking up font table `%c%c%c%c'.\n", 599 face, 600 (FT_Char)( tag >> 24 ), 601 (FT_Char)( tag >> 16 ), 602 (FT_Char)( tag >> 8 ), 603 (FT_Char)( tag ) )); 604 605 error = face->goto_table( face, tag, stream, 0 ); 606 if ( error ) 607 { 608 FT_TRACE2(( "tt_face_load_generic_header: Font table is missing!\n" )); 609 goto Exit; 610 } 611 612 header = &face->header; 613 614 if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) 615 goto Exit; 616 617 FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM )); 618 FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format )); 619 FT_TRACE2(( "tt_face_load_generic_header: Font table loaded.\n" )); 620 621 Exit: 622 return error; 623 } 624 625 626 FT_LOCAL_DEF( FT_Error ) tt_face_load_header(TT_Face face,FT_Stream stream)627 tt_face_load_header( TT_Face face, 628 FT_Stream stream ) 629 { 630 return tt_face_load_generic_header( face, stream, TTAG_head ); 631 } 632 633 634 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS 635 636 FT_LOCAL_DEF( FT_Error ) tt_face_load_bitmap_header(TT_Face face,FT_Stream stream)637 tt_face_load_bitmap_header( TT_Face face, 638 FT_Stream stream ) 639 { 640 return tt_face_load_generic_header( face, stream, TTAG_bhed ); 641 } 642 643 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ 644 645 646 /*************************************************************************/ 647 /* */ 648 /* <Function> */ 649 /* tt_face_load_max_profile */ 650 /* */ 651 /* <Description> */ 652 /* Loads the maximum profile into a face object. */ 653 /* */ 654 /* <Input> */ 655 /* face :: A handle to the target face object. */ 656 /* */ 657 /* stream :: The input stream. */ 658 /* */ 659 /* <Return> */ 660 /* FreeType error code. 0 means success. */ 661 /* */ 662 FT_LOCAL_DEF( FT_Error ) tt_face_load_max_profile(TT_Face face,FT_Stream stream)663 tt_face_load_max_profile( TT_Face face, 664 FT_Stream stream ) 665 { 666 FT_Error error; 667 TT_MaxProfile* maxProfile = &face->max_profile; 668 669 const FT_Frame_Field maxp_fields[] = 670 { 671 #undef FT_STRUCTURE 672 #define FT_STRUCTURE TT_MaxProfile 673 674 FT_FRAME_START( 6 ), 675 FT_FRAME_LONG ( version ), 676 FT_FRAME_USHORT( numGlyphs ), 677 FT_FRAME_END 678 }; 679 680 const FT_Frame_Field maxp_fields_extra[] = 681 { 682 FT_FRAME_START( 26 ), 683 FT_FRAME_USHORT( maxPoints ), 684 FT_FRAME_USHORT( maxContours ), 685 FT_FRAME_USHORT( maxCompositePoints ), 686 FT_FRAME_USHORT( maxCompositeContours ), 687 FT_FRAME_USHORT( maxZones ), 688 FT_FRAME_USHORT( maxTwilightPoints ), 689 FT_FRAME_USHORT( maxStorage ), 690 FT_FRAME_USHORT( maxFunctionDefs ), 691 FT_FRAME_USHORT( maxInstructionDefs ), 692 FT_FRAME_USHORT( maxStackElements ), 693 FT_FRAME_USHORT( maxSizeOfInstructions ), 694 FT_FRAME_USHORT( maxComponentElements ), 695 FT_FRAME_USHORT( maxComponentDepth ), 696 FT_FRAME_END 697 }; 698 699 700 FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face )); 701 702 error = face->goto_table( face, TTAG_maxp, stream, 0 ); 703 if ( error ) 704 goto Exit; 705 706 if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) 707 goto Exit; 708 709 maxProfile->maxPoints = 0; 710 maxProfile->maxContours = 0; 711 maxProfile->maxCompositePoints = 0; 712 maxProfile->maxCompositeContours = 0; 713 maxProfile->maxZones = 0; 714 maxProfile->maxTwilightPoints = 0; 715 maxProfile->maxStorage = 0; 716 maxProfile->maxFunctionDefs = 0; 717 maxProfile->maxInstructionDefs = 0; 718 maxProfile->maxStackElements = 0; 719 maxProfile->maxSizeOfInstructions = 0; 720 maxProfile->maxComponentElements = 0; 721 maxProfile->maxComponentDepth = 0; 722 723 if ( maxProfile->version >= 0x10000L ) 724 { 725 if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) 726 goto Exit; 727 728 /* XXX: an adjustment that is necessary to load certain */ 729 /* broken fonts like `Keystrokes MT' :-( */ 730 /* */ 731 /* We allocate 64 function entries by default when */ 732 /* the maxFunctionDefs field is null. */ 733 734 if ( maxProfile->maxFunctionDefs == 0 ) 735 maxProfile->maxFunctionDefs = 64; 736 737 face->root.num_glyphs = maxProfile->numGlyphs; 738 739 face->root.internal->max_points = 740 (FT_UShort)MAX( maxProfile->maxCompositePoints, 741 maxProfile->maxPoints ); 742 743 face->root.internal->max_contours = 744 (FT_Short)MAX( maxProfile->maxCompositeContours, 745 maxProfile->maxContours ); 746 747 face->max_components = (FT_ULong)maxProfile->maxComponentElements + 748 maxProfile->maxComponentDepth; 749 750 /* XXX: some fonts have maxComponents set to 0; we will */ 751 /* then use 16 of them by default. */ 752 if ( face->max_components == 0 ) 753 face->max_components = 16; 754 755 /* We also increase maxPoints and maxContours in order to support */ 756 /* some broken fonts. */ 757 face->root.internal->max_points += (FT_UShort)8; 758 face->root.internal->max_contours += (FT_Short) 4; 759 } 760 761 FT_TRACE2(( "MAXP loaded.\n" )); 762 763 Exit: 764 return error; 765 } 766 767 768 /*************************************************************************/ 769 /* */ 770 /* <Function> */ 771 /* tt_face_load_metrics */ 772 /* */ 773 /* <Description> */ 774 /* Loads the horizontal or vertical metrics table into a face object. */ 775 /* */ 776 /* <Input> */ 777 /* face :: A handle to the target face object. */ 778 /* */ 779 /* stream :: The input stream. */ 780 /* */ 781 /* vertical :: A boolean flag. If set, load vertical metrics. */ 782 /* */ 783 /* <Return> */ 784 /* FreeType error code. 0 means success. */ 785 /* */ 786 static FT_Error tt_face_load_metrics(TT_Face face,FT_Stream stream,FT_Bool vertical)787 tt_face_load_metrics( TT_Face face, 788 FT_Stream stream, 789 FT_Bool vertical ) 790 { 791 FT_Error error; 792 FT_Memory memory = stream->memory; 793 794 FT_ULong table_len; 795 FT_Long num_shorts, num_longs, num_shorts_checked; 796 797 TT_LongMetrics * longs; 798 TT_ShortMetrics** shorts; 799 800 801 FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical" 802 : "Horizontal", 803 face )); 804 805 if ( vertical ) 806 { 807 /* The table is optional, quit silently if it wasn't found */ 808 /* */ 809 /* XXX: Some fonts have a valid vertical header with a non-null */ 810 /* `number_of_VMetrics' fields, but no corresponding `vmtx' */ 811 /* table to get the metrics from (e.g. mingliu). */ 812 /* */ 813 /* For safety, we set the field to 0! */ 814 /* */ 815 error = face->goto_table( face, TTAG_vmtx, stream, &table_len ); 816 if ( error ) 817 { 818 /* Set number_Of_VMetrics to 0! */ 819 FT_TRACE2(( " no vertical header in file.\n" )); 820 face->vertical.number_Of_VMetrics = 0; 821 error = SFNT_Err_Ok; 822 goto Exit; 823 } 824 825 num_longs = face->vertical.number_Of_VMetrics; 826 longs = (TT_LongMetrics *)&face->vertical.long_metrics; 827 shorts = (TT_ShortMetrics**)&face->vertical.short_metrics; 828 } 829 else 830 { 831 error = face->goto_table( face, TTAG_hmtx, stream, &table_len ); 832 if ( error ) 833 { 834 FT_ERROR(( " no horizontal metrics in file!\n" )); 835 error = SFNT_Err_Hmtx_Table_Missing; 836 goto Exit; 837 } 838 839 num_longs = face->horizontal.number_Of_HMetrics; 840 longs = (TT_LongMetrics *)&face->horizontal.long_metrics; 841 shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics; 842 } 843 844 /* never trust derived values */ 845 846 num_shorts = face->max_profile.numGlyphs - num_longs; 847 num_shorts_checked = ( table_len - num_longs * 4L ) / 2; 848 849 if ( num_shorts < 0 ) 850 { 851 FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n", 852 vertical ? "Vertical" 853 : "Horizontal" )); 854 855 error = vertical ? SFNT_Err_Invalid_Vert_Metrics 856 : SFNT_Err_Invalid_Horiz_Metrics; 857 goto Exit; 858 } 859 860 if ( FT_NEW_ARRAY( *longs, num_longs ) || 861 FT_NEW_ARRAY( *shorts, num_shorts ) ) 862 goto Exit; 863 864 if ( FT_FRAME_ENTER( table_len ) ) 865 goto Exit; 866 867 { 868 TT_LongMetrics cur = *longs; 869 TT_LongMetrics limit = cur + num_longs; 870 871 872 for ( ; cur < limit; cur++ ) 873 { 874 cur->advance = FT_GET_USHORT(); 875 cur->bearing = FT_GET_SHORT(); 876 } 877 } 878 879 /* do we have an inconsistent number of metric values? */ 880 { 881 TT_ShortMetrics* cur = *shorts; 882 TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked ); 883 884 885 for ( ; cur < limit; cur++ ) 886 *cur = FT_GET_SHORT(); 887 888 /* we fill up the missing left side bearings with the */ 889 /* last valid value. Since this will occur for buggy CJK */ 890 /* fonts usually only, nothing serious will happen */ 891 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 ) 892 { 893 FT_Short val = (*shorts)[num_shorts_checked - 1]; 894 895 896 limit = *shorts + num_shorts; 897 for ( ; cur < limit; cur++ ) 898 *cur = val; 899 } 900 } 901 902 FT_FRAME_EXIT(); 903 904 FT_TRACE2(( "loaded\n" )); 905 906 Exit: 907 return error; 908 } 909 910 911 /*************************************************************************/ 912 /* */ 913 /* <Function> */ 914 /* tt_face_load_metrics_header */ 915 /* */ 916 /* <Description> */ 917 /* Loads the horizontal or vertical header in a face object. */ 918 /* */ 919 /* <Input> */ 920 /* face :: A handle to the target face object. */ 921 /* */ 922 /* stream :: The input stream. */ 923 /* */ 924 /* vertical :: A boolean flag. If set, load vertical metrics. */ 925 /* */ 926 /* <Return> */ 927 /* FreeType error code. 0 means success. */ 928 /* */ 929 FT_LOCAL_DEF( FT_Error ) tt_face_load_metrics_header(TT_Face face,FT_Stream stream,FT_Bool vertical)930 tt_face_load_metrics_header( TT_Face face, 931 FT_Stream stream, 932 FT_Bool vertical ) 933 { 934 FT_Error error; 935 TT_HoriHeader* header; 936 937 const FT_Frame_Field metrics_header_fields[] = 938 { 939 #undef FT_STRUCTURE 940 #define FT_STRUCTURE TT_HoriHeader 941 942 FT_FRAME_START( 36 ), 943 FT_FRAME_ULONG ( Version ), 944 FT_FRAME_SHORT ( Ascender ), 945 FT_FRAME_SHORT ( Descender ), 946 FT_FRAME_SHORT ( Line_Gap ), 947 FT_FRAME_USHORT( advance_Width_Max ), 948 FT_FRAME_SHORT ( min_Left_Side_Bearing ), 949 FT_FRAME_SHORT ( min_Right_Side_Bearing ), 950 FT_FRAME_SHORT ( xMax_Extent ), 951 FT_FRAME_SHORT ( caret_Slope_Rise ), 952 FT_FRAME_SHORT ( caret_Slope_Run ), 953 FT_FRAME_SHORT ( caret_Offset ), 954 FT_FRAME_SHORT ( Reserved[0] ), 955 FT_FRAME_SHORT ( Reserved[1] ), 956 FT_FRAME_SHORT ( Reserved[2] ), 957 FT_FRAME_SHORT ( Reserved[3] ), 958 FT_FRAME_SHORT ( metric_Data_Format ), 959 FT_FRAME_USHORT( number_Of_HMetrics ), 960 FT_FRAME_END 961 }; 962 963 964 FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " )); 965 966 if ( vertical ) 967 { 968 face->vertical_info = 0; 969 970 /* The vertical header table is optional, so return quietly if */ 971 /* we don't find it. */ 972 error = face->goto_table( face, TTAG_vhea, stream, 0 ); 973 if ( error ) 974 { 975 error = SFNT_Err_Ok; 976 goto Exit; 977 } 978 979 face->vertical_info = 1; 980 header = (TT_HoriHeader*)&face->vertical; 981 } 982 else 983 { 984 /* The horizontal header is mandatory; return an error if we */ 985 /* don't find it. */ 986 error = face->goto_table( face, TTAG_hhea, stream, 0 ); 987 if ( error ) 988 { 989 error = SFNT_Err_Horiz_Header_Missing; 990 goto Exit; 991 } 992 993 header = &face->horizontal; 994 } 995 996 if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) 997 goto Exit; 998 999 header->long_metrics = NULL; 1000 header->short_metrics = NULL; 1001 1002 FT_TRACE2(( "loaded\n" )); 1003 1004 /* Now try to load the corresponding metrics */ 1005 1006 error = tt_face_load_metrics( face, stream, vertical ); 1007 1008 Exit: 1009 return error; 1010 } 1011 1012 1013 /*************************************************************************/ 1014 /* */ 1015 /* <Function> */ 1016 /* tt_face_load_names */ 1017 /* */ 1018 /* <Description> */ 1019 /* Loads the name records. */ 1020 /* */ 1021 /* <Input> */ 1022 /* face :: A handle to the target face object. */ 1023 /* */ 1024 /* stream :: The input stream. */ 1025 /* */ 1026 /* <Return> */ 1027 /* FreeType error code. 0 means success. */ 1028 /* */ 1029 FT_LOCAL_DEF( FT_Error ) tt_face_load_names(TT_Face face,FT_Stream stream)1030 tt_face_load_names( TT_Face face, 1031 FT_Stream stream ) 1032 { 1033 FT_Error error; 1034 FT_Memory memory = stream->memory; 1035 FT_ULong table_pos, table_len; 1036 FT_ULong storage_start, storage_limit; 1037 FT_UInt count; 1038 TT_NameTable table; 1039 1040 static const FT_Frame_Field name_table_fields[] = 1041 { 1042 #undef FT_STRUCTURE 1043 #define FT_STRUCTURE TT_NameTableRec 1044 1045 FT_FRAME_START( 6 ), 1046 FT_FRAME_USHORT( format ), 1047 FT_FRAME_USHORT( numNameRecords ), 1048 FT_FRAME_USHORT( storageOffset ), 1049 FT_FRAME_END 1050 }; 1051 1052 static const FT_Frame_Field name_record_fields[] = 1053 { 1054 #undef FT_STRUCTURE 1055 #define FT_STRUCTURE TT_NameEntryRec 1056 1057 /* no FT_FRAME_START */ 1058 FT_FRAME_USHORT( platformID ), 1059 FT_FRAME_USHORT( encodingID ), 1060 FT_FRAME_USHORT( languageID ), 1061 FT_FRAME_USHORT( nameID ), 1062 FT_FRAME_USHORT( stringLength ), 1063 FT_FRAME_USHORT( stringOffset ), 1064 FT_FRAME_END 1065 }; 1066 1067 1068 table = &face->name_table; 1069 table->stream = stream; 1070 1071 FT_TRACE2(( "Names " )); 1072 1073 error = face->goto_table( face, TTAG_name, stream, &table_len ); 1074 if ( error ) 1075 { 1076 /* The name table is required so indicate failure. */ 1077 FT_TRACE2(( "is missing!\n" )); 1078 error = SFNT_Err_Name_Table_Missing; 1079 goto Exit; 1080 } 1081 1082 table_pos = FT_STREAM_POS(); 1083 1084 1085 if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) 1086 goto Exit; 1087 1088 /* Some popular asian fonts have an invalid `storageOffset' value */ 1089 /* (it should be at least "6 + 12*num_names"). However, the string */ 1090 /* offsets, computed as "storageOffset + entry->stringOffset", are */ 1091 /* valid pointers within the name table... */ 1092 /* */ 1093 /* We thus can't check `storageOffset' right now. */ 1094 /* */ 1095 storage_start = table_pos + 6 + 12*table->numNameRecords; 1096 storage_limit = table_pos + table_len; 1097 1098 if ( storage_start > storage_limit ) 1099 { 1100 FT_ERROR(( "tt_face_load_names: invalid `name' table\n" )); 1101 error = SFNT_Err_Name_Table_Missing; 1102 goto Exit; 1103 } 1104 1105 /* Allocate the array of name records. */ 1106 count = table->numNameRecords; 1107 table->numNameRecords = 0; 1108 1109 if ( FT_NEW_ARRAY( table->names, count ) || 1110 FT_FRAME_ENTER( count * 12 ) ) 1111 goto Exit; 1112 1113 /* Load the name records and determine how much storage is needed */ 1114 /* to hold the strings themselves. */ 1115 { 1116 TT_NameEntryRec* entry = table->names; 1117 1118 1119 for ( ; count > 0; count-- ) 1120 { 1121 if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) 1122 continue; 1123 1124 /* check that the name is not empty */ 1125 if ( entry->stringLength == 0 ) 1126 continue; 1127 1128 /* check that the name string is within the table */ 1129 entry->stringOffset += table_pos + table->storageOffset; 1130 if ( entry->stringOffset < storage_start || 1131 entry->stringOffset + entry->stringLength > storage_limit ) 1132 { 1133 /* invalid entry - ignore it */ 1134 entry->stringOffset = 0; 1135 entry->stringLength = 0; 1136 continue; 1137 } 1138 1139 entry++; 1140 } 1141 1142 table->numNameRecords = (FT_UInt)( entry - table->names ); 1143 } 1144 1145 FT_FRAME_EXIT(); 1146 1147 FT_TRACE2(( "loaded\n" )); 1148 1149 /* everything went well, update face->num_names */ 1150 face->num_names = (FT_UShort) table->numNameRecords; 1151 1152 Exit: 1153 return error; 1154 } 1155 1156 1157 /*************************************************************************/ 1158 /* */ 1159 /* <Function> */ 1160 /* tt_face_free_names */ 1161 /* */ 1162 /* <Description> */ 1163 /* Frees the name records. */ 1164 /* */ 1165 /* <Input> */ 1166 /* face :: A handle to the target face object. */ 1167 /* */ 1168 FT_LOCAL_DEF( void ) tt_face_free_names(TT_Face face)1169 tt_face_free_names( TT_Face face ) 1170 { 1171 FT_Memory memory = face->root.driver->root.memory; 1172 TT_NameTable table = &face->name_table; 1173 TT_NameEntry entry = table->names; 1174 FT_UInt count = table->numNameRecords; 1175 1176 1177 for ( ; count > 0; count--, entry++ ) 1178 { 1179 FT_FREE( entry->string ); 1180 entry->stringLength = 0; 1181 } 1182 1183 /* free strings table */ 1184 FT_FREE( table->names ); 1185 1186 table->numNameRecords = 0; 1187 table->format = 0; 1188 table->storageOffset = 0; 1189 } 1190 1191 1192 /*************************************************************************/ 1193 /* */ 1194 /* <Function> */ 1195 /* tt_face_load_cmap */ 1196 /* */ 1197 /* <Description> */ 1198 /* Loads the cmap directory in a face object. The cmaps itselves are */ 1199 /* loaded on demand in the `ttcmap.c' module. */ 1200 /* */ 1201 /* <Input> */ 1202 /* face :: A handle to the target face object. */ 1203 /* */ 1204 /* stream :: A handle to the input stream. */ 1205 /* */ 1206 /* <Return> */ 1207 /* FreeType error code. 0 means success. */ 1208 /* */ 1209 1210 FT_LOCAL_DEF( FT_Error ) tt_face_load_cmap(TT_Face face,FT_Stream stream)1211 tt_face_load_cmap( TT_Face face, 1212 FT_Stream stream ) 1213 { 1214 FT_Error error; 1215 1216 1217 error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); 1218 if ( error ) 1219 { 1220 FT_TRACE2(( "No `cmap' table in font !\n" )); 1221 error = SFNT_Err_CMap_Table_Missing; 1222 goto Exit; 1223 } 1224 1225 if ( !FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) 1226 FT_TRACE2(( "`cmap' table loaded\n" )); 1227 else 1228 { 1229 FT_ERROR(( "`cmap' table is too short!\n" )); 1230 face->cmap_size = 0; 1231 } 1232 1233 Exit: 1234 return error; 1235 } 1236 1237 1238 1239 /*************************************************************************/ 1240 /* */ 1241 /* <Function> */ 1242 /* tt_face_load_os2 */ 1243 /* */ 1244 /* <Description> */ 1245 /* Loads the OS2 table. */ 1246 /* */ 1247 /* <Input> */ 1248 /* face :: A handle to the target face object. */ 1249 /* */ 1250 /* stream :: A handle to the input stream. */ 1251 /* */ 1252 /* <Return> */ 1253 /* FreeType error code. 0 means success. */ 1254 /* */ 1255 FT_LOCAL_DEF( FT_Error ) tt_face_load_os2(TT_Face face,FT_Stream stream)1256 tt_face_load_os2( TT_Face face, 1257 FT_Stream stream ) 1258 { 1259 FT_Error error; 1260 TT_OS2* os2; 1261 1262 const FT_Frame_Field os2_fields[] = 1263 { 1264 #undef FT_STRUCTURE 1265 #define FT_STRUCTURE TT_OS2 1266 1267 FT_FRAME_START( 78 ), 1268 FT_FRAME_USHORT( version ), 1269 FT_FRAME_SHORT ( xAvgCharWidth ), 1270 FT_FRAME_USHORT( usWeightClass ), 1271 FT_FRAME_USHORT( usWidthClass ), 1272 FT_FRAME_SHORT ( fsType ), 1273 FT_FRAME_SHORT ( ySubscriptXSize ), 1274 FT_FRAME_SHORT ( ySubscriptYSize ), 1275 FT_FRAME_SHORT ( ySubscriptXOffset ), 1276 FT_FRAME_SHORT ( ySubscriptYOffset ), 1277 FT_FRAME_SHORT ( ySuperscriptXSize ), 1278 FT_FRAME_SHORT ( ySuperscriptYSize ), 1279 FT_FRAME_SHORT ( ySuperscriptXOffset ), 1280 FT_FRAME_SHORT ( ySuperscriptYOffset ), 1281 FT_FRAME_SHORT ( yStrikeoutSize ), 1282 FT_FRAME_SHORT ( yStrikeoutPosition ), 1283 FT_FRAME_SHORT ( sFamilyClass ), 1284 FT_FRAME_BYTE ( panose[0] ), 1285 FT_FRAME_BYTE ( panose[1] ), 1286 FT_FRAME_BYTE ( panose[2] ), 1287 FT_FRAME_BYTE ( panose[3] ), 1288 FT_FRAME_BYTE ( panose[4] ), 1289 FT_FRAME_BYTE ( panose[5] ), 1290 FT_FRAME_BYTE ( panose[6] ), 1291 FT_FRAME_BYTE ( panose[7] ), 1292 FT_FRAME_BYTE ( panose[8] ), 1293 FT_FRAME_BYTE ( panose[9] ), 1294 FT_FRAME_ULONG ( ulUnicodeRange1 ), 1295 FT_FRAME_ULONG ( ulUnicodeRange2 ), 1296 FT_FRAME_ULONG ( ulUnicodeRange3 ), 1297 FT_FRAME_ULONG ( ulUnicodeRange4 ), 1298 FT_FRAME_BYTE ( achVendID[0] ), 1299 FT_FRAME_BYTE ( achVendID[1] ), 1300 FT_FRAME_BYTE ( achVendID[2] ), 1301 FT_FRAME_BYTE ( achVendID[3] ), 1302 1303 FT_FRAME_USHORT( fsSelection ), 1304 FT_FRAME_USHORT( usFirstCharIndex ), 1305 FT_FRAME_USHORT( usLastCharIndex ), 1306 FT_FRAME_SHORT ( sTypoAscender ), 1307 FT_FRAME_SHORT ( sTypoDescender ), 1308 FT_FRAME_SHORT ( sTypoLineGap ), 1309 FT_FRAME_USHORT( usWinAscent ), 1310 FT_FRAME_USHORT( usWinDescent ), 1311 FT_FRAME_END 1312 }; 1313 1314 const FT_Frame_Field os2_fields_extra[] = 1315 { 1316 FT_FRAME_START( 8 ), 1317 FT_FRAME_ULONG( ulCodePageRange1 ), 1318 FT_FRAME_ULONG( ulCodePageRange2 ), 1319 FT_FRAME_END 1320 }; 1321 1322 const FT_Frame_Field os2_fields_extra2[] = 1323 { 1324 FT_FRAME_START( 10 ), 1325 FT_FRAME_SHORT ( sxHeight ), 1326 FT_FRAME_SHORT ( sCapHeight ), 1327 FT_FRAME_USHORT( usDefaultChar ), 1328 FT_FRAME_USHORT( usBreakChar ), 1329 FT_FRAME_USHORT( usMaxContext ), 1330 FT_FRAME_END 1331 }; 1332 1333 1334 FT_TRACE2(( "OS/2 Table " )); 1335 1336 /* We now support old Mac fonts where the OS/2 table doesn't */ 1337 /* exist. Simply put, we set the `version' field to 0xFFFF */ 1338 /* and test this value each time we need to access the table. */ 1339 error = face->goto_table( face, TTAG_OS2, stream, 0 ); 1340 if ( error ) 1341 { 1342 FT_TRACE2(( "is missing!\n" )); 1343 face->os2.version = 0xFFFFU; 1344 error = SFNT_Err_Ok; 1345 goto Exit; 1346 } 1347 1348 os2 = &face->os2; 1349 1350 if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) 1351 goto Exit; 1352 1353 os2->ulCodePageRange1 = 0; 1354 os2->ulCodePageRange2 = 0; 1355 os2->sxHeight = 0; 1356 os2->sCapHeight = 0; 1357 os2->usDefaultChar = 0; 1358 os2->usBreakChar = 0; 1359 os2->usMaxContext = 0; 1360 1361 if ( os2->version >= 0x0001 ) 1362 { 1363 /* only version 1 tables */ 1364 if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) ) 1365 goto Exit; 1366 1367 if ( os2->version >= 0x0002 ) 1368 { 1369 /* only version 2 tables */ 1370 if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) 1371 goto Exit; 1372 } 1373 } 1374 1375 FT_TRACE2(( "loaded\n" )); 1376 1377 Exit: 1378 return error; 1379 } 1380 1381 1382 /*************************************************************************/ 1383 /* */ 1384 /* <Function> */ 1385 /* tt_face_load_postscript */ 1386 /* */ 1387 /* <Description> */ 1388 /* Loads the Postscript table. */ 1389 /* */ 1390 /* <Input> */ 1391 /* face :: A handle to the target face object. */ 1392 /* */ 1393 /* stream :: A handle to the input stream. */ 1394 /* */ 1395 /* <Return> */ 1396 /* FreeType error code. 0 means success. */ 1397 /* */ 1398 FT_LOCAL_DEF( FT_Error ) tt_face_load_postscript(TT_Face face,FT_Stream stream)1399 tt_face_load_postscript( TT_Face face, 1400 FT_Stream stream ) 1401 { 1402 FT_Error error; 1403 TT_Postscript* post = &face->postscript; 1404 1405 static const FT_Frame_Field post_fields[] = 1406 { 1407 #undef FT_STRUCTURE 1408 #define FT_STRUCTURE TT_Postscript 1409 1410 FT_FRAME_START( 32 ), 1411 FT_FRAME_ULONG( FormatType ), 1412 FT_FRAME_ULONG( italicAngle ), 1413 FT_FRAME_SHORT( underlinePosition ), 1414 FT_FRAME_SHORT( underlineThickness ), 1415 FT_FRAME_ULONG( isFixedPitch ), 1416 FT_FRAME_ULONG( minMemType42 ), 1417 FT_FRAME_ULONG( maxMemType42 ), 1418 FT_FRAME_ULONG( minMemType1 ), 1419 FT_FRAME_ULONG( maxMemType1 ), 1420 FT_FRAME_END 1421 }; 1422 1423 1424 FT_TRACE2(( "PostScript " )); 1425 1426 error = face->goto_table( face, TTAG_post, stream, 0 ); 1427 if ( error ) 1428 return SFNT_Err_Post_Table_Missing; 1429 1430 if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) 1431 return error; 1432 1433 /* we don't load the glyph names, we do that in another */ 1434 /* module (ttpost). */ 1435 FT_TRACE2(( "loaded\n" )); 1436 1437 return SFNT_Err_Ok; 1438 } 1439 1440 1441 /*************************************************************************/ 1442 /* */ 1443 /* <Function> */ 1444 /* tt_face_load_pclt */ 1445 /* */ 1446 /* <Description> */ 1447 /* Loads the PCL 5 Table. */ 1448 /* */ 1449 /* <Input> */ 1450 /* face :: A handle to the target face object. */ 1451 /* */ 1452 /* stream :: A handle to the input stream. */ 1453 /* */ 1454 /* <Return> */ 1455 /* FreeType error code. 0 means success. */ 1456 /* */ 1457 FT_LOCAL_DEF( FT_Error ) tt_face_load_pclt(TT_Face face,FT_Stream stream)1458 tt_face_load_pclt( TT_Face face, 1459 FT_Stream stream ) 1460 { 1461 static const FT_Frame_Field pclt_fields[] = 1462 { 1463 #undef FT_STRUCTURE 1464 #define FT_STRUCTURE TT_PCLT 1465 1466 FT_FRAME_START( 54 ), 1467 FT_FRAME_ULONG ( Version ), 1468 FT_FRAME_ULONG ( FontNumber ), 1469 FT_FRAME_USHORT( Pitch ), 1470 FT_FRAME_USHORT( xHeight ), 1471 FT_FRAME_USHORT( Style ), 1472 FT_FRAME_USHORT( TypeFamily ), 1473 FT_FRAME_USHORT( CapHeight ), 1474 FT_FRAME_BYTES ( TypeFace, 16 ), 1475 FT_FRAME_BYTES ( CharacterComplement, 8 ), 1476 FT_FRAME_BYTES ( FileName, 6 ), 1477 FT_FRAME_CHAR ( StrokeWeight ), 1478 FT_FRAME_CHAR ( WidthType ), 1479 FT_FRAME_BYTE ( SerifStyle ), 1480 FT_FRAME_BYTE ( Reserved ), 1481 FT_FRAME_END 1482 }; 1483 1484 FT_Error error; 1485 TT_PCLT* pclt = &face->pclt; 1486 1487 1488 FT_TRACE2(( "PCLT " )); 1489 1490 /* optional table */ 1491 error = face->goto_table( face, TTAG_PCLT, stream, 0 ); 1492 if ( error ) 1493 { 1494 FT_TRACE2(( "missing (optional)\n" )); 1495 pclt->Version = 0; 1496 return SFNT_Err_Ok; 1497 } 1498 1499 if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) 1500 goto Exit; 1501 1502 FT_TRACE2(( "loaded\n" )); 1503 1504 Exit: 1505 return error; 1506 } 1507 1508 1509 /*************************************************************************/ 1510 /* */ 1511 /* <Function> */ 1512 /* tt_face_load_gasp */ 1513 /* */ 1514 /* <Description> */ 1515 /* Loads the `gasp' table into a face object. */ 1516 /* */ 1517 /* <Input> */ 1518 /* face :: A handle to the target face object. */ 1519 /* */ 1520 /* stream :: The input stream. */ 1521 /* */ 1522 /* <Return> */ 1523 /* FreeType error code. 0 means success. */ 1524 /* */ 1525 FT_LOCAL_DEF( FT_Error ) tt_face_load_gasp(TT_Face face,FT_Stream stream)1526 tt_face_load_gasp( TT_Face face, 1527 FT_Stream stream ) 1528 { 1529 FT_Error error; 1530 FT_Memory memory = stream->memory; 1531 1532 FT_UInt j,num_ranges; 1533 TT_GaspRange gaspranges; 1534 1535 1536 FT_TRACE2(( "tt_face_load_gasp: %08p\n", face )); 1537 1538 /* the gasp table is optional */ 1539 error = face->goto_table( face, TTAG_gasp, stream, 0 ); 1540 if ( error ) 1541 return SFNT_Err_Ok; 1542 1543 if ( FT_FRAME_ENTER( 4L ) ) 1544 goto Exit; 1545 1546 face->gasp.version = FT_GET_USHORT(); 1547 face->gasp.numRanges = FT_GET_USHORT(); 1548 1549 FT_FRAME_EXIT(); 1550 1551 num_ranges = face->gasp.numRanges; 1552 FT_TRACE3(( "number of ranges = %d\n", num_ranges )); 1553 1554 if ( FT_NEW_ARRAY( gaspranges, num_ranges ) || 1555 FT_FRAME_ENTER( num_ranges * 4L ) ) 1556 goto Exit; 1557 1558 face->gasp.gaspRanges = gaspranges; 1559 1560 for ( j = 0; j < num_ranges; j++ ) 1561 { 1562 gaspranges[j].maxPPEM = FT_GET_USHORT(); 1563 gaspranges[j].gaspFlag = FT_GET_USHORT(); 1564 1565 FT_TRACE3(( " [max:%d flag:%d]", 1566 gaspranges[j].maxPPEM, 1567 gaspranges[j].gaspFlag )); 1568 } 1569 FT_TRACE3(( "\n" )); 1570 1571 FT_FRAME_EXIT(); 1572 FT_TRACE2(( "GASP loaded\n" )); 1573 1574 Exit: 1575 return error; 1576 } 1577 1578 1579 FT_CALLBACK_DEF( int ) 1580 tt_kern_pair_compare( const void* a, 1581 const void* b ); 1582 1583 1584 /*************************************************************************/ 1585 /* */ 1586 /* <Function> */ 1587 /* tt_face_load_kern */ 1588 /* */ 1589 /* <Description> */ 1590 /* Loads the first kerning table with format 0 in the font. Only */ 1591 /* accepts the first horizontal kerning table. Developers should use */ 1592 /* the `ftxkern' extension to access other kerning tables in the font */ 1593 /* file, if they really want to. */ 1594 /* */ 1595 /* <Input> */ 1596 /* face :: A handle to the target face object. */ 1597 /* */ 1598 /* stream :: The input stream. */ 1599 /* */ 1600 /* <Return> */ 1601 /* FreeType error code. 0 means success. */ 1602 /* */ 1603 FT_LOCAL_DEF( FT_Error ) tt_face_load_kern(TT_Face face,FT_Stream stream)1604 tt_face_load_kern( TT_Face face, 1605 FT_Stream stream ) 1606 { 1607 FT_Error error; 1608 FT_Memory memory = stream->memory; 1609 1610 FT_UInt n, num_tables; 1611 1612 1613 /* the kern table is optional; exit silently if it is missing */ 1614 error = face->goto_table( face, TTAG_kern, stream, 0 ); 1615 if ( error ) 1616 return SFNT_Err_Ok; 1617 1618 if ( FT_FRAME_ENTER( 4L ) ) 1619 goto Exit; 1620 1621 (void)FT_GET_USHORT(); /* version */ 1622 num_tables = FT_GET_USHORT(); 1623 1624 FT_FRAME_EXIT(); 1625 1626 for ( n = 0; n < num_tables; n++ ) 1627 { 1628 FT_UInt coverage; 1629 FT_UInt length; 1630 1631 1632 if ( FT_FRAME_ENTER( 6L ) ) 1633 goto Exit; 1634 1635 (void)FT_GET_USHORT(); /* version */ 1636 length = FT_GET_USHORT() - 6; /* substract header length */ 1637 coverage = FT_GET_USHORT(); 1638 1639 FT_FRAME_EXIT(); 1640 1641 if ( coverage == 0x0001 ) 1642 { 1643 FT_UInt num_pairs; 1644 TT_Kern0_Pair pair; 1645 TT_Kern0_Pair limit; 1646 1647 1648 /* found a horizontal format 0 kerning table! */ 1649 if ( FT_FRAME_ENTER( 8L ) ) 1650 goto Exit; 1651 1652 num_pairs = FT_GET_USHORT(); 1653 1654 /* skip the rest */ 1655 1656 FT_FRAME_EXIT(); 1657 1658 /* allocate array of kerning pairs */ 1659 if ( FT_NEW_ARRAY( face->kern_pairs, num_pairs ) || 1660 FT_FRAME_ENTER( 6L * num_pairs ) ) 1661 goto Exit; 1662 1663 pair = face->kern_pairs; 1664 limit = pair + num_pairs; 1665 for ( ; pair < limit; pair++ ) 1666 { 1667 pair->left = FT_GET_USHORT(); 1668 pair->right = FT_GET_USHORT(); 1669 pair->value = FT_GET_USHORT(); 1670 } 1671 1672 FT_FRAME_EXIT(); 1673 1674 face->num_kern_pairs = num_pairs; 1675 face->kern_table_index = n; 1676 1677 /* ensure that the kerning pair table is sorted (yes, some */ 1678 /* fonts have unsorted tables!) */ 1679 { 1680 FT_UInt i; 1681 TT_Kern0_Pair pair0; 1682 1683 1684 pair0 = face->kern_pairs; 1685 1686 for ( i = 1; i < num_pairs; i++, pair0++ ) 1687 { 1688 if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 ) 1689 { 1690 ft_qsort( (void*)face->kern_pairs, (int)num_pairs, 1691 sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare ); 1692 break; 1693 } 1694 } 1695 } 1696 1697 goto Exit; 1698 } 1699 1700 if ( FT_STREAM_SKIP( length ) ) 1701 goto Exit; 1702 } 1703 1704 /* no kern table found -- doesn't matter */ 1705 face->kern_table_index = -1; 1706 face->num_kern_pairs = 0; 1707 face->kern_pairs = NULL; 1708 1709 Exit: 1710 return error; 1711 } 1712 1713 1714 #undef TT_KERN_INDEX 1715 #define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) 1716 1717 1718 FT_CALLBACK_DEF( int ) tt_kern_pair_compare(const void * a,const void * b)1719 tt_kern_pair_compare( const void* a, 1720 const void* b ) 1721 { 1722 TT_Kern0_Pair pair1 = (TT_Kern0_Pair)a; 1723 TT_Kern0_Pair pair2 = (TT_Kern0_Pair)b; 1724 1725 FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right ); 1726 FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right ); 1727 1728 1729 return ( index1 < index2 ? -1 : 1730 ( index1 > index2 ? 1 : 0 )); 1731 } 1732 1733 1734 #undef TT_KERN_INDEX 1735 1736 1737 /*************************************************************************/ 1738 /* */ 1739 /* <Function> */ 1740 /* tt_face_load_hdmx */ 1741 /* */ 1742 /* <Description> */ 1743 /* Loads the horizontal device metrics table. */ 1744 /* */ 1745 /* <Input> */ 1746 /* face :: A handle to the target face object. */ 1747 /* */ 1748 /* stream :: A handle to the input stream. */ 1749 /* */ 1750 /* <Return> */ 1751 /* FreeType error code. 0 means success. */ 1752 /* */ 1753 FT_LOCAL_DEF( FT_Error ) tt_face_load_hdmx(TT_Face face,FT_Stream stream)1754 tt_face_load_hdmx( TT_Face face, 1755 FT_Stream stream ) 1756 { 1757 FT_Error error; 1758 FT_Memory memory = stream->memory; 1759 1760 TT_Hdmx hdmx = &face->hdmx; 1761 FT_Long num_glyphs; 1762 FT_Long record_size; 1763 1764 1765 hdmx->version = 0; 1766 hdmx->num_records = 0; 1767 hdmx->records = 0; 1768 1769 /* this table is optional */ 1770 error = face->goto_table( face, TTAG_hdmx, stream, 0 ); 1771 if ( error ) 1772 return SFNT_Err_Ok; 1773 1774 if ( FT_FRAME_ENTER( 8L ) ) 1775 goto Exit; 1776 1777 hdmx->version = FT_GET_USHORT(); 1778 hdmx->num_records = FT_GET_SHORT(); 1779 record_size = FT_GET_LONG(); 1780 1781 FT_FRAME_EXIT(); 1782 1783 /* Only recognize format 0 */ 1784 if ( hdmx->version != 0 ) 1785 goto Exit; 1786 1787 if ( FT_NEW_ARRAY( hdmx->records, hdmx->num_records ) ) 1788 goto Exit; 1789 1790 num_glyphs = face->root.num_glyphs; 1791 record_size -= num_glyphs + 2; 1792 1793 { 1794 TT_HdmxEntry cur = hdmx->records; 1795 TT_HdmxEntry limit = cur + hdmx->num_records; 1796 1797 1798 for ( ; cur < limit; cur++ ) 1799 { 1800 /* read record */ 1801 if ( FT_READ_BYTE( cur->ppem ) || 1802 FT_READ_BYTE( cur->max_width ) ) 1803 goto Exit; 1804 1805 if ( FT_ALLOC( cur->widths, num_glyphs ) || 1806 FT_STREAM_READ( cur->widths, num_glyphs ) ) 1807 goto Exit; 1808 1809 /* skip padding bytes */ 1810 if ( record_size > 0 && FT_STREAM_SKIP( record_size ) ) 1811 goto Exit; 1812 } 1813 } 1814 1815 Exit: 1816 return error; 1817 } 1818 1819 1820 /*************************************************************************/ 1821 /* */ 1822 /* <Function> */ 1823 /* tt_face_free_hdmx */ 1824 /* */ 1825 /* <Description> */ 1826 /* Frees the horizontal device metrics table. */ 1827 /* */ 1828 /* <Input> */ 1829 /* face :: A handle to the target face object. */ 1830 /* */ 1831 FT_LOCAL_DEF( void ) tt_face_free_hdmx(TT_Face face)1832 tt_face_free_hdmx( TT_Face face ) 1833 { 1834 if ( face ) 1835 { 1836 FT_Int n; 1837 FT_Memory memory = face->root.driver->root.memory; 1838 1839 1840 for ( n = 0; n < face->hdmx.num_records; n++ ) 1841 FT_FREE( face->hdmx.records[n].widths ); 1842 1843 FT_FREE( face->hdmx.records ); 1844 face->hdmx.num_records = 0; 1845 } 1846 } 1847 1848 1849 /* END */ 1850