1 /***************************************************************************/ 2 /* */ 3 /* t1decode.c */ 4 /* */ 5 /* PostScript Type 1 decoding routines (body). */ 6 /* */ 7 /* Copyright 2000-2011 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 FT_INTERNAL_CALC_H 21 #include FT_INTERNAL_DEBUG_H 22 #include FT_INTERNAL_POSTSCRIPT_HINTS_H 23 #include FT_OUTLINE_H 24 25 #include "t1decode.h" 26 #include "psobjs.h" 27 28 #include "psauxerr.h" 29 30 /* ensure proper sign extension */ 31 #define Fix2Int( f ) ( (FT_Int)(FT_Short)( (f) >> 16 ) ) 32 33 /*************************************************************************/ 34 /* */ 35 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 36 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 37 /* messages during execution. */ 38 /* */ 39 #undef FT_COMPONENT 40 #define FT_COMPONENT trace_t1decode 41 42 43 typedef enum T1_Operator_ 44 { 45 op_none = 0, 46 op_endchar, 47 op_hsbw, 48 op_seac, 49 op_sbw, 50 op_closepath, 51 op_hlineto, 52 op_hmoveto, 53 op_hvcurveto, 54 op_rlineto, 55 op_rmoveto, 56 op_rrcurveto, 57 op_vhcurveto, 58 op_vlineto, 59 op_vmoveto, 60 op_dotsection, 61 op_hstem, 62 op_hstem3, 63 op_vstem, 64 op_vstem3, 65 op_div, 66 op_callothersubr, 67 op_callsubr, 68 op_pop, 69 op_return, 70 op_setcurrentpoint, 71 op_unknown15, 72 73 op_max /* never remove this one */ 74 75 } T1_Operator; 76 77 78 static 79 const FT_Int t1_args_count[op_max] = 80 { 81 0, /* none */ 82 0, /* endchar */ 83 2, /* hsbw */ 84 5, /* seac */ 85 4, /* sbw */ 86 0, /* closepath */ 87 1, /* hlineto */ 88 1, /* hmoveto */ 89 4, /* hvcurveto */ 90 2, /* rlineto */ 91 2, /* rmoveto */ 92 6, /* rrcurveto */ 93 4, /* vhcurveto */ 94 1, /* vlineto */ 95 1, /* vmoveto */ 96 0, /* dotsection */ 97 2, /* hstem */ 98 6, /* hstem3 */ 99 2, /* vstem */ 100 6, /* vstem3 */ 101 2, /* div */ 102 -1, /* callothersubr */ 103 1, /* callsubr */ 104 0, /* pop */ 105 0, /* return */ 106 2, /* setcurrentpoint */ 107 2 /* opcode 15 (undocumented and obsolete) */ 108 }; 109 110 111 /*************************************************************************/ 112 /* */ 113 /* <Function> */ 114 /* t1_lookup_glyph_by_stdcharcode */ 115 /* */ 116 /* <Description> */ 117 /* Looks up a given glyph by its StandardEncoding charcode. Used to */ 118 /* implement the SEAC Type 1 operator. */ 119 /* */ 120 /* <Input> */ 121 /* face :: The current face object. */ 122 /* */ 123 /* charcode :: The character code to look for. */ 124 /* */ 125 /* <Return> */ 126 /* A glyph index in the font face. Returns -1 if the corresponding */ 127 /* glyph wasn't found. */ 128 /* */ 129 static FT_Int 130 t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder, 131 FT_Int charcode ) 132 { 133 FT_UInt n; 134 const FT_String* glyph_name; 135 FT_Service_PsCMaps psnames = decoder->psnames; 136 137 138 /* check range of standard char code */ 139 if ( charcode < 0 || charcode > 255 ) 140 return -1; 141 142 glyph_name = psnames->adobe_std_strings( 143 psnames->adobe_std_encoding[charcode]); 144 145 for ( n = 0; n < decoder->num_glyphs; n++ ) 146 { 147 FT_String* name = (FT_String*)decoder->glyph_names[n]; 148 149 150 if ( name && 151 name[0] == glyph_name[0] && 152 ft_strcmp( name, glyph_name ) == 0 ) 153 return n; 154 } 155 156 return -1; 157 } 158 159 160 /*************************************************************************/ 161 /* */ 162 /* <Function> */ 163 /* t1operator_seac */ 164 /* */ 165 /* <Description> */ 166 /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ 167 /* */ 168 /* <Input> */ 169 /* decoder :: The current CID decoder. */ 170 /* */ 171 /* asb :: The accent's side bearing. */ 172 /* */ 173 /* adx :: The horizontal offset of the accent. */ 174 /* */ 175 /* ady :: The vertical offset of the accent. */ 176 /* */ 177 /* bchar :: The base character's StandardEncoding charcode. */ 178 /* */ 179 /* achar :: The accent character's StandardEncoding charcode. */ 180 /* */ 181 /* <Return> */ 182 /* FreeType error code. 0 means success. */ 183 /* */ 184 static FT_Error 185 t1operator_seac( T1_Decoder decoder, 186 FT_Pos asb, 187 FT_Pos adx, 188 FT_Pos ady, 189 FT_Int bchar, 190 FT_Int achar ) 191 { 192 FT_Error error; 193 FT_Int bchar_index, achar_index; 194 #if 0 195 FT_Int n_base_points; 196 FT_Outline* base = decoder->builder.base; 197 #endif 198 FT_Vector left_bearing, advance; 199 200 #ifdef FT_CONFIG_OPTION_INCREMENTAL 201 T1_Face face = (T1_Face)decoder->builder.face; 202 #endif 203 204 205 if ( decoder->seac ) 206 { 207 FT_ERROR(( "t1operator_seac: invalid nested seac\n" )); 208 return PSaux_Err_Syntax_Error; 209 } 210 211 /* seac weirdness */ 212 adx += decoder->builder.left_bearing.x; 213 214 /* `glyph_names' is set to 0 for CID fonts which do not */ 215 /* include an encoding. How can we deal with these? */ 216 #ifdef FT_CONFIG_OPTION_INCREMENTAL 217 if ( decoder->glyph_names == 0 && 218 !face->root.internal->incremental_interface ) 219 #else 220 if ( decoder->glyph_names == 0 ) 221 #endif /* FT_CONFIG_OPTION_INCREMENTAL */ 222 { 223 FT_ERROR(( "t1operator_seac:" 224 " glyph names table not available in this font\n" )); 225 return PSaux_Err_Syntax_Error; 226 } 227 228 #ifdef FT_CONFIG_OPTION_INCREMENTAL 229 if ( face->root.internal->incremental_interface ) 230 { 231 /* the caller must handle the font encoding also */ 232 bchar_index = bchar; 233 achar_index = achar; 234 } 235 else 236 #endif 237 { 238 bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar ); 239 achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar ); 240 } 241 242 if ( bchar_index < 0 || achar_index < 0 ) 243 { 244 FT_ERROR(( "t1operator_seac:" 245 " invalid seac character code arguments\n" )); 246 return PSaux_Err_Syntax_Error; 247 } 248 249 /* if we are trying to load a composite glyph, do not load the */ 250 /* accent character and return the array of subglyphs. */ 251 if ( decoder->builder.no_recurse ) 252 { 253 FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; 254 FT_GlyphLoader loader = glyph->internal->loader; 255 FT_SubGlyph subg; 256 257 258 /* reallocate subglyph array if necessary */ 259 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); 260 if ( error ) 261 goto Exit; 262 263 subg = loader->current.subglyphs; 264 265 /* subglyph 0 = base character */ 266 subg->index = bchar_index; 267 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | 268 FT_SUBGLYPH_FLAG_USE_MY_METRICS; 269 subg->arg1 = 0; 270 subg->arg2 = 0; 271 subg++; 272 273 /* subglyph 1 = accent character */ 274 subg->index = achar_index; 275 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; 276 subg->arg1 = (FT_Int)FIXED_TO_INT( adx - asb ); 277 subg->arg2 = (FT_Int)FIXED_TO_INT( ady ); 278 279 /* set up remaining glyph fields */ 280 glyph->num_subglyphs = 2; 281 glyph->subglyphs = loader->base.subglyphs; 282 glyph->format = FT_GLYPH_FORMAT_COMPOSITE; 283 284 loader->current.num_subglyphs = 2; 285 goto Exit; 286 } 287 288 /* First load `bchar' in builder */ 289 /* now load the unscaled outline */ 290 291 FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ 292 293 /* the seac operator must not be nested */ 294 decoder->seac = TRUE; 295 error = t1_decoder_parse_glyph( decoder, bchar_index ); 296 decoder->seac = FALSE; 297 if ( error ) 298 goto Exit; 299 300 /* save the left bearing and width of the base character */ 301 /* as they will be erased by the next load. */ 302 303 left_bearing = decoder->builder.left_bearing; 304 advance = decoder->builder.advance; 305 306 decoder->builder.left_bearing.x = 0; 307 decoder->builder.left_bearing.y = 0; 308 309 decoder->builder.pos_x = adx - asb; 310 decoder->builder.pos_y = ady; 311 312 /* Now load `achar' on top of */ 313 /* the base outline */ 314 315 /* the seac operator must not be nested */ 316 decoder->seac = TRUE; 317 error = t1_decoder_parse_glyph( decoder, achar_index ); 318 decoder->seac = FALSE; 319 if ( error ) 320 goto Exit; 321 322 /* restore the left side bearing and */ 323 /* advance width of the base character */ 324 325 decoder->builder.left_bearing = left_bearing; 326 decoder->builder.advance = advance; 327 328 decoder->builder.pos_x = 0; 329 decoder->builder.pos_y = 0; 330 331 Exit: 332 return error; 333 } 334 335 336 /*************************************************************************/ 337 /* */ 338 /* <Function> */ 339 /* t1_decoder_parse_charstrings */ 340 /* */ 341 /* <Description> */ 342 /* Parses a given Type 1 charstrings program. */ 343 /* */ 344 /* <Input> */ 345 /* decoder :: The current Type 1 decoder. */ 346 /* */ 347 /* charstring_base :: The base address of the charstring stream. */ 348 /* */ 349 /* charstring_len :: The length in bytes of the charstring stream. */ 350 /* */ 351 /* <Return> */ 352 /* FreeType error code. 0 means success. */ 353 /* */ 354 FT_LOCAL_DEF( FT_Error ) 355 t1_decoder_parse_charstrings( T1_Decoder decoder, 356 FT_Byte* charstring_base, 357 FT_UInt charstring_len ) 358 { 359 FT_Error error; 360 T1_Decoder_Zone zone; 361 FT_Byte* ip; 362 FT_Byte* limit; 363 T1_Builder builder = &decoder->builder; 364 FT_Pos x, y, orig_x, orig_y; 365 FT_Int known_othersubr_result_cnt = 0; 366 FT_Int unknown_othersubr_result_cnt = 0; 367 FT_Bool large_int; 368 FT_Fixed seed; 369 370 T1_Hints_Funcs hinter; 371 372 #ifdef FT_DEBUG_LEVEL_TRACE 373 FT_Bool bol = TRUE; 374 #endif 375 376 377 /* compute random seed from stack address of parameter */ 378 seed = (FT_Fixed)( ( (FT_PtrDist)(char*)&seed ^ 379 (FT_PtrDist)(char*)&decoder ^ 380 (FT_PtrDist)(char*)&charstring_base ) & 381 FT_ULONG_MAX ) ; 382 seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL; 383 if ( seed == 0 ) 384 seed = 0x7384; 385 386 /* First of all, initialize the decoder */ 387 decoder->top = decoder->stack; 388 decoder->zone = decoder->zones; 389 zone = decoder->zones; 390 391 builder->parse_state = T1_Parse_Start; 392 393 hinter = (T1_Hints_Funcs)builder->hints_funcs; 394 395 /* a font that reads BuildCharArray without setting */ 396 /* its values first is buggy, but ... */ 397 FT_ASSERT( ( decoder->len_buildchar == 0 ) == 398 ( decoder->buildchar == NULL ) ); 399 400 if ( decoder->buildchar && decoder->len_buildchar > 0 ) 401 ft_memset( &decoder->buildchar[0], 402 0, 403 sizeof ( decoder->buildchar[0] ) * decoder->len_buildchar ); 404 405 FT_TRACE4(( "\n" 406 "Start charstring\n" )); 407 408 zone->base = charstring_base; 409 limit = zone->limit = charstring_base + charstring_len; 410 ip = zone->cursor = zone->base; 411 412 error = PSaux_Err_Ok; 413 414 x = orig_x = builder->pos_x; 415 y = orig_y = builder->pos_y; 416 417 /* begin hints recording session, if any */ 418 if ( hinter ) 419 hinter->open( hinter->hints ); 420 421 large_int = FALSE; 422 423 /* now, execute loop */ 424 while ( ip < limit ) 425 { 426 FT_Long* top = decoder->top; 427 T1_Operator op = op_none; 428 FT_Int32 value = 0; 429 430 431 FT_ASSERT( known_othersubr_result_cnt == 0 || 432 unknown_othersubr_result_cnt == 0 ); 433 434 #ifdef FT_DEBUG_LEVEL_TRACE 435 if ( bol ) 436 { 437 FT_TRACE5(( " (%d)", decoder->top - decoder->stack )); 438 bol = FALSE; 439 } 440 #endif 441 442 /*********************************************************************/ 443 /* */ 444 /* Decode operator or operand */ 445 /* */ 446 /* */ 447 448 /* first of all, decompress operator or value */ 449 switch ( *ip++ ) 450 { 451 case 1: 452 op = op_hstem; 453 break; 454 455 case 3: 456 op = op_vstem; 457 break; 458 case 4: 459 op = op_vmoveto; 460 break; 461 case 5: 462 op = op_rlineto; 463 break; 464 case 6: 465 op = op_hlineto; 466 break; 467 case 7: 468 op = op_vlineto; 469 break; 470 case 8: 471 op = op_rrcurveto; 472 break; 473 case 9: 474 op = op_closepath; 475 break; 476 case 10: 477 op = op_callsubr; 478 break; 479 case 11: 480 op = op_return; 481 break; 482 483 case 13: 484 op = op_hsbw; 485 break; 486 case 14: 487 op = op_endchar; 488 break; 489 490 case 15: /* undocumented, obsolete operator */ 491 op = op_unknown15; 492 break; 493 494 case 21: 495 op = op_rmoveto; 496 break; 497 case 22: 498 op = op_hmoveto; 499 break; 500 501 case 30: 502 op = op_vhcurveto; 503 break; 504 case 31: 505 op = op_hvcurveto; 506 break; 507 508 case 12: 509 if ( ip > limit ) 510 { 511 FT_ERROR(( "t1_decoder_parse_charstrings:" 512 " invalid escape (12+EOF)\n" )); 513 goto Syntax_Error; 514 } 515 516 switch ( *ip++ ) 517 { 518 case 0: 519 op = op_dotsection; 520 break; 521 case 1: 522 op = op_vstem3; 523 break; 524 case 2: 525 op = op_hstem3; 526 break; 527 case 6: 528 op = op_seac; 529 break; 530 case 7: 531 op = op_sbw; 532 break; 533 case 12: 534 op = op_div; 535 break; 536 case 16: 537 op = op_callothersubr; 538 break; 539 case 17: 540 op = op_pop; 541 break; 542 case 33: 543 op = op_setcurrentpoint; 544 break; 545 546 default: 547 FT_ERROR(( "t1_decoder_parse_charstrings:" 548 " invalid escape (12+%d)\n", 549 ip[-1] )); 550 goto Syntax_Error; 551 } 552 break; 553 554 case 255: /* four bytes integer */ 555 if ( ip + 4 > limit ) 556 { 557 FT_ERROR(( "t1_decoder_parse_charstrings:" 558 " unexpected EOF in integer\n" )); 559 goto Syntax_Error; 560 } 561 562 value = (FT_Int32)( ( (FT_Long)ip[0] << 24 ) | 563 ( (FT_Long)ip[1] << 16 ) | 564 ( (FT_Long)ip[2] << 8 ) | 565 ip[3] ); 566 ip += 4; 567 568 /* According to the specification, values > 32000 or < -32000 must */ 569 /* be followed by a `div' operator to make the result be in the */ 570 /* range [-32000;32000]. We expect that the second argument of */ 571 /* `div' is not a large number. Additionally, we don't handle */ 572 /* stuff like `<large1> <large2> <num> div <num> div' or */ 573 /* <large1> <large2> <num> div div'. This is probably not allowed */ 574 /* anyway. */ 575 if ( value > 32000 || value < -32000 ) 576 { 577 if ( large_int ) 578 { 579 FT_ERROR(( "t1_decoder_parse_charstrings:" 580 " no `div' after large integer\n" )); 581 } 582 else 583 large_int = TRUE; 584 } 585 else 586 { 587 if ( !large_int ) 588 value <<= 16; 589 } 590 591 break; 592 593 default: 594 if ( ip[-1] >= 32 ) 595 { 596 if ( ip[-1] < 247 ) 597 value = (FT_Int32)ip[-1] - 139; 598 else 599 { 600 if ( ++ip > limit ) 601 { 602 FT_ERROR(( "t1_decoder_parse_charstrings:" 603 " unexpected EOF in integer\n" )); 604 goto Syntax_Error; 605 } 606 607 if ( ip[-2] < 251 ) 608 value = ( ( (FT_Int32)ip[-2] - 247 ) << 8 ) + ip[-1] + 108; 609 else 610 value = -( ( ( (FT_Int32)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); 611 } 612 613 if ( !large_int ) 614 value <<= 16; 615 } 616 else 617 { 618 FT_ERROR(( "t1_decoder_parse_charstrings:" 619 " invalid byte (%d)\n", ip[-1] )); 620 goto Syntax_Error; 621 } 622 } 623 624 if ( unknown_othersubr_result_cnt > 0 ) 625 { 626 switch ( op ) 627 { 628 case op_callsubr: 629 case op_return: 630 case op_none: 631 case op_pop: 632 break; 633 634 default: 635 /* all operands have been transferred by previous pops */ 636 unknown_othersubr_result_cnt = 0; 637 break; 638 } 639 } 640 641 if ( large_int && !( op == op_none || op == op_div ) ) 642 { 643 FT_ERROR(( "t1_decoder_parse_charstrings:" 644 " no `div' after large integer\n" )); 645 646 large_int = FALSE; 647 } 648 649 /*********************************************************************/ 650 /* */ 651 /* Push value on stack, or process operator */ 652 /* */ 653 /* */ 654 if ( op == op_none ) 655 { 656 if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) 657 { 658 FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow\n" )); 659 goto Syntax_Error; 660 } 661 662 #ifdef FT_DEBUG_LEVEL_TRACE 663 if ( large_int ) 664 FT_TRACE4(( " %ld", value )); 665 else 666 FT_TRACE4(( " %ld", Fix2Int( value ) )); 667 #endif 668 669 *top++ = value; 670 decoder->top = top; 671 } 672 else if ( op == op_callothersubr ) /* callothersubr */ 673 { 674 FT_Int subr_no; 675 FT_Int arg_cnt; 676 677 678 #ifdef FT_DEBUG_LEVEL_TRACE 679 FT_TRACE4(( " callothersubr\n" )); 680 bol = TRUE; 681 #endif 682 683 if ( top - decoder->stack < 2 ) 684 goto Stack_Underflow; 685 686 top -= 2; 687 688 subr_no = Fix2Int( top[1] ); 689 arg_cnt = Fix2Int( top[0] ); 690 691 /***********************************************************/ 692 /* */ 693 /* remove all operands to callothersubr from the stack */ 694 /* */ 695 /* for handled othersubrs, where we know the number of */ 696 /* arguments, we increase the stack by the value of */ 697 /* known_othersubr_result_cnt */ 698 /* */ 699 /* for unhandled othersubrs the following pops adjust the */ 700 /* stack pointer as necessary */ 701 702 if ( arg_cnt > top - decoder->stack ) 703 goto Stack_Underflow; 704 705 top -= arg_cnt; 706 707 known_othersubr_result_cnt = 0; 708 unknown_othersubr_result_cnt = 0; 709 710 /* XXX TODO: The checks to `arg_count == <whatever>' */ 711 /* might not be correct; an othersubr expects a certain */ 712 /* number of operands on the PostScript stack (as opposed */ 713 /* to the T1 stack) but it doesn't have to put them there */ 714 /* by itself; previous othersubrs might have left the */ 715 /* operands there if they were not followed by an */ 716 /* appropriate number of pops */ 717 /* */ 718 /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */ 719 /* accept a font that contains charstrings like */ 720 /* */ 721 /* 100 200 2 20 callothersubr */ 722 /* 300 1 20 callothersubr pop */ 723 /* */ 724 /* Perhaps this is the reason why BuildCharArray exists. */ 725 726 switch ( subr_no ) 727 { 728 case 0: /* end flex feature */ 729 if ( arg_cnt != 3 ) 730 goto Unexpected_OtherSubr; 731 732 if ( decoder->flex_state == 0 || 733 decoder->num_flex_vectors != 7 ) 734 { 735 FT_ERROR(( "t1_decoder_parse_charstrings:" 736 " unexpected flex end\n" )); 737 goto Syntax_Error; 738 } 739 740 /* the two `results' are popped by the following setcurrentpoint */ 741 top[0] = x; 742 top[1] = y; 743 known_othersubr_result_cnt = 2; 744 break; 745 746 case 1: /* start flex feature */ 747 if ( arg_cnt != 0 ) 748 goto Unexpected_OtherSubr; 749 750 decoder->flex_state = 1; 751 decoder->num_flex_vectors = 0; 752 if ( ( error = t1_builder_start_point( builder, x, y ) ) 753 != PSaux_Err_Ok || 754 ( error = t1_builder_check_points( builder, 6 ) ) 755 != PSaux_Err_Ok ) 756 goto Fail; 757 break; 758 759 case 2: /* add flex vectors */ 760 { 761 FT_Int idx; 762 763 764 if ( arg_cnt != 0 ) 765 goto Unexpected_OtherSubr; 766 767 if ( decoder->flex_state == 0 ) 768 { 769 FT_ERROR(( "t1_decoder_parse_charstrings:" 770 " missing flex start\n" )); 771 goto Syntax_Error; 772 } 773 774 /* note that we should not add a point for index 0; */ 775 /* this will move our current position to the flex */ 776 /* point without adding any point to the outline */ 777 idx = decoder->num_flex_vectors++; 778 if ( idx > 0 && idx < 7 ) 779 t1_builder_add_point( builder, 780 x, 781 y, 782 (FT_Byte)( idx == 3 || idx == 6 ) ); 783 } 784 break; 785 786 case 3: /* change hints */ 787 if ( arg_cnt != 1 ) 788 goto Unexpected_OtherSubr; 789 790 known_othersubr_result_cnt = 1; 791 792 if ( hinter ) 793 hinter->reset( hinter->hints, builder->current->n_points ); 794 break; 795 796 case 12: 797 case 13: 798 /* counter control hints, clear stack */ 799 top = decoder->stack; 800 break; 801 802 case 14: 803 case 15: 804 case 16: 805 case 17: 806 case 18: /* multiple masters */ 807 { 808 PS_Blend blend = decoder->blend; 809 FT_UInt num_points, nn, mm; 810 FT_Long* delta; 811 FT_Long* values; 812 813 814 if ( !blend ) 815 { 816 FT_ERROR(( "t1_decoder_parse_charstrings:" 817 " unexpected multiple masters operator\n" )); 818 goto Syntax_Error; 819 } 820 821 num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 ); 822 if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) ) 823 { 824 FT_ERROR(( "t1_decoder_parse_charstrings:" 825 " incorrect number of multiple masters arguments\n" )); 826 goto Syntax_Error; 827 } 828 829 /* We want to compute */ 830 /* */ 831 /* a0*w0 + a1*w1 + ... + ak*wk */ 832 /* */ 833 /* but we only have a0, a1-a0, a2-a0, ..., ak-a0. */ 834 /* */ 835 /* However, given that w0 + w1 + ... + wk == 1, we can */ 836 /* rewrite it easily as */ 837 /* */ 838 /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk */ 839 /* */ 840 /* where k == num_designs-1. */ 841 /* */ 842 /* I guess that's why it's written in this `compact' */ 843 /* form. */ 844 /* */ 845 delta = top + num_points; 846 values = top; 847 for ( nn = 0; nn < num_points; nn++ ) 848 { 849 FT_Long tmp = values[0]; 850 851 852 for ( mm = 1; mm < blend->num_designs; mm++ ) 853 tmp += FT_MulFix( *delta++, blend->weight_vector[mm] ); 854 855 *values++ = tmp; 856 } 857 858 known_othersubr_result_cnt = num_points; 859 break; 860 } 861 862 case 19: 863 /* <idx> 1 19 callothersubr */ 864 /* => replace elements starting from index cvi( <idx> ) */ 865 /* of BuildCharArray with WeightVector */ 866 { 867 FT_Int idx; 868 PS_Blend blend = decoder->blend; 869 870 871 if ( arg_cnt != 1 || blend == NULL ) 872 goto Unexpected_OtherSubr; 873 874 idx = Fix2Int( top[0] ); 875 876 if ( idx < 0 || 877 idx + blend->num_designs > decoder->len_buildchar ) 878 goto Unexpected_OtherSubr; 879 880 ft_memcpy( &decoder->buildchar[idx], 881 blend->weight_vector, 882 blend->num_designs * 883 sizeof ( blend->weight_vector[0] ) ); 884 } 885 break; 886 887 case 20: 888 /* <arg1> <arg2> 2 20 callothersubr pop */ 889 /* ==> push <arg1> + <arg2> onto T1 stack */ 890 if ( arg_cnt != 2 ) 891 goto Unexpected_OtherSubr; 892 893 top[0] += top[1]; /* XXX (over|under)flow */ 894 895 known_othersubr_result_cnt = 1; 896 break; 897 898 case 21: 899 /* <arg1> <arg2> 2 21 callothersubr pop */ 900 /* ==> push <arg1> - <arg2> onto T1 stack */ 901 if ( arg_cnt != 2 ) 902 goto Unexpected_OtherSubr; 903 904 top[0] -= top[1]; /* XXX (over|under)flow */ 905 906 known_othersubr_result_cnt = 1; 907 break; 908 909 case 22: 910 /* <arg1> <arg2> 2 22 callothersubr pop */ 911 /* ==> push <arg1> * <arg2> onto T1 stack */ 912 if ( arg_cnt != 2 ) 913 goto Unexpected_OtherSubr; 914 915 top[0] = FT_MulFix( top[0], top[1] ); 916 917 known_othersubr_result_cnt = 1; 918 break; 919 920 case 23: 921 /* <arg1> <arg2> 2 23 callothersubr pop */ 922 /* ==> push <arg1> / <arg2> onto T1 stack */ 923 if ( arg_cnt != 2 || top[1] == 0 ) 924 goto Unexpected_OtherSubr; 925 926 top[0] = FT_DivFix( top[0], top[1] ); 927 928 known_othersubr_result_cnt = 1; 929 break; 930 931 case 24: 932 /* <val> <idx> 2 24 callothersubr */ 933 /* ==> set BuildCharArray[cvi( <idx> )] = <val> */ 934 { 935 FT_Int idx; 936 PS_Blend blend = decoder->blend; 937 938 939 if ( arg_cnt != 2 || blend == NULL ) 940 goto Unexpected_OtherSubr; 941 942 idx = Fix2Int( top[1] ); 943 944 if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) 945 goto Unexpected_OtherSubr; 946 947 decoder->buildchar[idx] = top[0]; 948 } 949 break; 950 951 case 25: 952 /* <idx> 1 25 callothersubr pop */ 953 /* ==> push BuildCharArray[cvi( idx )] */ 954 /* onto T1 stack */ 955 { 956 FT_Int idx; 957 PS_Blend blend = decoder->blend; 958 959 960 if ( arg_cnt != 1 || blend == NULL ) 961 goto Unexpected_OtherSubr; 962 963 idx = Fix2Int( top[0] ); 964 965 if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) 966 goto Unexpected_OtherSubr; 967 968 top[0] = decoder->buildchar[idx]; 969 } 970 971 known_othersubr_result_cnt = 1; 972 break; 973 974 #if 0 975 case 26: 976 /* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */ 977 /* leave mark on T1 stack */ 978 /* <val> <idx> ==> set BuildCharArray[cvi( <idx> )] = <val> */ 979 XXX which routine has left its mark on the (PostScript) stack?; 980 break; 981 #endif 982 983 case 27: 984 /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */ 985 /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */ 986 /* otherwise push <res2> */ 987 if ( arg_cnt != 4 ) 988 goto Unexpected_OtherSubr; 989 990 if ( top[2] > top[3] ) 991 top[0] = top[1]; 992 993 known_othersubr_result_cnt = 1; 994 break; 995 996 case 28: 997 /* 0 28 callothersubr pop */ 998 /* => push random value from interval [0, 1) onto stack */ 999 if ( arg_cnt != 0 ) 1000 goto Unexpected_OtherSubr; 1001 1002 { 1003 FT_Fixed Rand; 1004 1005 1006 Rand = seed; 1007 if ( Rand >= 0x8000L ) 1008 Rand++; 1009 1010 top[0] = Rand; 1011 1012 seed = FT_MulFix( seed, 0x10000L - seed ); 1013 if ( seed == 0 ) 1014 seed += 0x2873; 1015 } 1016 1017 known_othersubr_result_cnt = 1; 1018 break; 1019 1020 default: 1021 if ( arg_cnt >= 0 && subr_no >= 0 ) 1022 { 1023 FT_ERROR(( "t1_decoder_parse_charstrings:" 1024 " unknown othersubr [%d %d], wish me luck\n", 1025 arg_cnt, subr_no )); 1026 unknown_othersubr_result_cnt = arg_cnt; 1027 break; 1028 } 1029 /* fall through */ 1030 1031 Unexpected_OtherSubr: 1032 FT_ERROR(( "t1_decoder_parse_charstrings:" 1033 " invalid othersubr [%d %d]\n", arg_cnt, subr_no )); 1034 goto Syntax_Error; 1035 } 1036 1037 top += known_othersubr_result_cnt; 1038 1039 decoder->top = top; 1040 } 1041 else /* general operator */ 1042 { 1043 FT_Int num_args = t1_args_count[op]; 1044 1045 1046 FT_ASSERT( num_args >= 0 ); 1047 1048 if ( top - decoder->stack < num_args ) 1049 goto Stack_Underflow; 1050 1051 /* XXX Operators usually take their operands from the */ 1052 /* bottom of the stack, i.e., the operands are */ 1053 /* decoder->stack[0], ..., decoder->stack[num_args - 1]; */ 1054 /* only div, callsubr, and callothersubr are different. */ 1055 /* In practice it doesn't matter (?). */ 1056 1057 #ifdef FT_DEBUG_LEVEL_TRACE 1058 1059 switch ( op ) 1060 { 1061 case op_callsubr: 1062 case op_div: 1063 case op_callothersubr: 1064 case op_pop: 1065 case op_return: 1066 break; 1067 1068 default: 1069 if ( top - decoder->stack != num_args ) 1070 FT_TRACE0(( "t1_decoder_parse_charstrings:" 1071 " too much operands on the stack" 1072 " (seen %d, expected %d)\n", 1073 top - decoder->stack, num_args )); 1074 break; 1075 } 1076 1077 #endif /* FT_DEBUG_LEVEL_TRACE */ 1078 1079 top -= num_args; 1080 1081 switch ( op ) 1082 { 1083 case op_endchar: 1084 FT_TRACE4(( " endchar\n" )); 1085 1086 t1_builder_close_contour( builder ); 1087 1088 /* close hints recording session */ 1089 if ( hinter ) 1090 { 1091 if ( hinter->close( hinter->hints, builder->current->n_points ) ) 1092 goto Syntax_Error; 1093 1094 /* apply hints to the loaded glyph outline now */ 1095 hinter->apply( hinter->hints, 1096 builder->current, 1097 (PSH_Globals)builder->hints_globals, 1098 decoder->hint_mode ); 1099 } 1100 1101 /* add current outline to the glyph slot */ 1102 FT_GlyphLoader_Add( builder->loader ); 1103 1104 /* the compiler should optimize away this empty loop but ... */ 1105 1106 #ifdef FT_DEBUG_LEVEL_TRACE 1107 1108 if ( decoder->len_buildchar > 0 ) 1109 { 1110 FT_UInt i; 1111 1112 1113 FT_TRACE4(( "BuildCharArray = [ " )); 1114 1115 for ( i = 0; i < decoder->len_buildchar; ++i ) 1116 FT_TRACE4(( "%d ", decoder->buildchar[i] )); 1117 1118 FT_TRACE4(( "]\n" )); 1119 } 1120 1121 #endif /* FT_DEBUG_LEVEL_TRACE */ 1122 1123 FT_TRACE4(( "\n" )); 1124 1125 /* return now! */ 1126 return PSaux_Err_Ok; 1127 1128 case op_hsbw: 1129 FT_TRACE4(( " hsbw" )); 1130 1131 builder->parse_state = T1_Parse_Have_Width; 1132 1133 builder->left_bearing.x += top[0]; 1134 builder->advance.x = top[1]; 1135 builder->advance.y = 0; 1136 1137 orig_x = x = builder->pos_x + top[0]; 1138 orig_y = y = builder->pos_y; 1139 1140 FT_UNUSED( orig_y ); 1141 1142 /* the `metrics_only' indicates that we only want to compute */ 1143 /* the glyph's metrics (lsb + advance width), not load the */ 1144 /* rest of it; so exit immediately */ 1145 if ( builder->metrics_only ) 1146 return PSaux_Err_Ok; 1147 1148 break; 1149 1150 case op_seac: 1151 return t1operator_seac( decoder, 1152 top[0], 1153 top[1], 1154 top[2], 1155 Fix2Int( top[3] ), 1156 Fix2Int( top[4] ) ); 1157 1158 case op_sbw: 1159 FT_TRACE4(( " sbw" )); 1160 1161 builder->parse_state = T1_Parse_Have_Width; 1162 1163 builder->left_bearing.x += top[0]; 1164 builder->left_bearing.y += top[1]; 1165 builder->advance.x = top[2]; 1166 builder->advance.y = top[3]; 1167 1168 x = builder->pos_x + top[0]; 1169 y = builder->pos_y + top[1]; 1170 1171 /* the `metrics_only' indicates that we only want to compute */ 1172 /* the glyph's metrics (lsb + advance width), not load the */ 1173 /* rest of it; so exit immediately */ 1174 if ( builder->metrics_only ) 1175 return PSaux_Err_Ok; 1176 1177 break; 1178 1179 case op_closepath: 1180 FT_TRACE4(( " closepath" )); 1181 1182 /* if there is no path, `closepath' is a no-op */ 1183 if ( builder->parse_state == T1_Parse_Have_Path || 1184 builder->parse_state == T1_Parse_Have_Moveto ) 1185 t1_builder_close_contour( builder ); 1186 1187 builder->parse_state = T1_Parse_Have_Width; 1188 break; 1189 1190 case op_hlineto: 1191 FT_TRACE4(( " hlineto" )); 1192 1193 if ( ( error = t1_builder_start_point( builder, x, y ) ) 1194 != PSaux_Err_Ok ) 1195 goto Fail; 1196 1197 x += top[0]; 1198 goto Add_Line; 1199 1200 case op_hmoveto: 1201 FT_TRACE4(( " hmoveto" )); 1202 1203 x += top[0]; 1204 if ( !decoder->flex_state ) 1205 { 1206 if ( builder->parse_state == T1_Parse_Start ) 1207 goto Syntax_Error; 1208 builder->parse_state = T1_Parse_Have_Moveto; 1209 } 1210 break; 1211 1212 case op_hvcurveto: 1213 FT_TRACE4(( " hvcurveto" )); 1214 1215 if ( ( error = t1_builder_start_point( builder, x, y ) ) 1216 != PSaux_Err_Ok || 1217 ( error = t1_builder_check_points( builder, 3 ) ) 1218 != PSaux_Err_Ok ) 1219 goto Fail; 1220 1221 x += top[0]; 1222 t1_builder_add_point( builder, x, y, 0 ); 1223 x += top[1]; 1224 y += top[2]; 1225 t1_builder_add_point( builder, x, y, 0 ); 1226 y += top[3]; 1227 t1_builder_add_point( builder, x, y, 1 ); 1228 break; 1229 1230 case op_rlineto: 1231 FT_TRACE4(( " rlineto" )); 1232 1233 if ( ( error = t1_builder_start_point( builder, x, y ) ) 1234 != PSaux_Err_Ok ) 1235 goto Fail; 1236 1237 x += top[0]; 1238 y += top[1]; 1239 1240 Add_Line: 1241 if ( ( error = t1_builder_add_point1( builder, x, y ) ) 1242 != PSaux_Err_Ok ) 1243 goto Fail; 1244 break; 1245 1246 case op_rmoveto: 1247 FT_TRACE4(( " rmoveto" )); 1248 1249 x += top[0]; 1250 y += top[1]; 1251 if ( !decoder->flex_state ) 1252 { 1253 if ( builder->parse_state == T1_Parse_Start ) 1254 goto Syntax_Error; 1255 builder->parse_state = T1_Parse_Have_Moveto; 1256 } 1257 break; 1258 1259 case op_rrcurveto: 1260 FT_TRACE4(( " rrcurveto" )); 1261 1262 if ( ( error = t1_builder_start_point( builder, x, y ) ) 1263 != PSaux_Err_Ok || 1264 ( error = t1_builder_check_points( builder, 3 ) ) 1265 != PSaux_Err_Ok ) 1266 goto Fail; 1267 1268 x += top[0]; 1269 y += top[1]; 1270 t1_builder_add_point( builder, x, y, 0 ); 1271 1272 x += top[2]; 1273 y += top[3]; 1274 t1_builder_add_point( builder, x, y, 0 ); 1275 1276 x += top[4]; 1277 y += top[5]; 1278 t1_builder_add_point( builder, x, y, 1 ); 1279 break; 1280 1281 case op_vhcurveto: 1282 FT_TRACE4(( " vhcurveto" )); 1283 1284 if ( ( error = t1_builder_start_point( builder, x, y ) ) 1285 != PSaux_Err_Ok || 1286 ( error = t1_builder_check_points( builder, 3 ) ) 1287 != PSaux_Err_Ok ) 1288 goto Fail; 1289 1290 y += top[0]; 1291 t1_builder_add_point( builder, x, y, 0 ); 1292 x += top[1]; 1293 y += top[2]; 1294 t1_builder_add_point( builder, x, y, 0 ); 1295 x += top[3]; 1296 t1_builder_add_point( builder, x, y, 1 ); 1297 break; 1298 1299 case op_vlineto: 1300 FT_TRACE4(( " vlineto" )); 1301 1302 if ( ( error = t1_builder_start_point( builder, x, y ) ) 1303 != PSaux_Err_Ok ) 1304 goto Fail; 1305 1306 y += top[0]; 1307 goto Add_Line; 1308 1309 case op_vmoveto: 1310 FT_TRACE4(( " vmoveto" )); 1311 1312 y += top[0]; 1313 if ( !decoder->flex_state ) 1314 { 1315 if ( builder->parse_state == T1_Parse_Start ) 1316 goto Syntax_Error; 1317 builder->parse_state = T1_Parse_Have_Moveto; 1318 } 1319 break; 1320 1321 case op_div: 1322 FT_TRACE4(( " div" )); 1323 1324 /* if `large_int' is set, we divide unscaled numbers; */ 1325 /* otherwise, we divide numbers in 16.16 format -- */ 1326 /* in both cases, it is the same operation */ 1327 *top = FT_DivFix( top[0], top[1] ); 1328 ++top; 1329 1330 large_int = FALSE; 1331 break; 1332 1333 case op_callsubr: 1334 { 1335 FT_Int idx; 1336 1337 1338 FT_TRACE4(( " callsubr" )); 1339 1340 idx = Fix2Int( top[0] ); 1341 if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs ) 1342 { 1343 FT_ERROR(( "t1_decoder_parse_charstrings:" 1344 " invalid subrs index\n" )); 1345 goto Syntax_Error; 1346 } 1347 1348 if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) 1349 { 1350 FT_ERROR(( "t1_decoder_parse_charstrings:" 1351 " too many nested subrs\n" )); 1352 goto Syntax_Error; 1353 } 1354 1355 zone->cursor = ip; /* save current instruction pointer */ 1356 1357 zone++; 1358 1359 /* The Type 1 driver stores subroutines without the seed bytes. */ 1360 /* The CID driver stores subroutines with seed bytes. This */ 1361 /* case is taken care of when decoder->subrs_len == 0. */ 1362 zone->base = decoder->subrs[idx]; 1363 1364 if ( decoder->subrs_len ) 1365 zone->limit = zone->base + decoder->subrs_len[idx]; 1366 else 1367 { 1368 /* We are using subroutines from a CID font. We must adjust */ 1369 /* for the seed bytes. */ 1370 zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); 1371 zone->limit = decoder->subrs[idx + 1]; 1372 } 1373 1374 zone->cursor = zone->base; 1375 1376 if ( !zone->base ) 1377 { 1378 FT_ERROR(( "t1_decoder_parse_charstrings:" 1379 " invoking empty subrs\n" )); 1380 goto Syntax_Error; 1381 } 1382 1383 decoder->zone = zone; 1384 ip = zone->base; 1385 limit = zone->limit; 1386 break; 1387 } 1388 1389 case op_pop: 1390 FT_TRACE4(( " pop" )); 1391 1392 if ( known_othersubr_result_cnt > 0 ) 1393 { 1394 known_othersubr_result_cnt--; 1395 /* ignore, we pushed the operands ourselves */ 1396 break; 1397 } 1398 1399 if ( unknown_othersubr_result_cnt == 0 ) 1400 { 1401 FT_ERROR(( "t1_decoder_parse_charstrings:" 1402 " no more operands for othersubr\n" )); 1403 goto Syntax_Error; 1404 } 1405 1406 unknown_othersubr_result_cnt--; 1407 top++; /* `push' the operand to callothersubr onto the stack */ 1408 break; 1409 1410 case op_return: 1411 FT_TRACE4(( " return" )); 1412 1413 if ( zone <= decoder->zones ) 1414 { 1415 FT_ERROR(( "t1_decoder_parse_charstrings:" 1416 " unexpected return\n" )); 1417 goto Syntax_Error; 1418 } 1419 1420 zone--; 1421 ip = zone->cursor; 1422 limit = zone->limit; 1423 decoder->zone = zone; 1424 break; 1425 1426 case op_dotsection: 1427 FT_TRACE4(( " dotsection" )); 1428 1429 break; 1430 1431 case op_hstem: 1432 FT_TRACE4(( " hstem" )); 1433 1434 /* record horizontal hint */ 1435 if ( hinter ) 1436 { 1437 /* top[0] += builder->left_bearing.y; */ 1438 hinter->stem( hinter->hints, 1, top ); 1439 } 1440 break; 1441 1442 case op_hstem3: 1443 FT_TRACE4(( " hstem3" )); 1444 1445 /* record horizontal counter-controlled hints */ 1446 if ( hinter ) 1447 hinter->stem3( hinter->hints, 1, top ); 1448 break; 1449 1450 case op_vstem: 1451 FT_TRACE4(( " vstem" )); 1452 1453 /* record vertical hint */ 1454 if ( hinter ) 1455 { 1456 top[0] += orig_x; 1457 hinter->stem( hinter->hints, 0, top ); 1458 } 1459 break; 1460 1461 case op_vstem3: 1462 FT_TRACE4(( " vstem3" )); 1463 1464 /* record vertical counter-controlled hints */ 1465 if ( hinter ) 1466 { 1467 FT_Pos dx = orig_x; 1468 1469 1470 top[0] += dx; 1471 top[2] += dx; 1472 top[4] += dx; 1473 hinter->stem3( hinter->hints, 0, top ); 1474 } 1475 break; 1476 1477 case op_setcurrentpoint: 1478 FT_TRACE4(( " setcurrentpoint" )); 1479 1480 /* From the T1 specification, section 6.4: */ 1481 /* */ 1482 /* The setcurrentpoint command is used only in */ 1483 /* conjunction with results from OtherSubrs procedures. */ 1484 1485 /* known_othersubr_result_cnt != 0 is already handled */ 1486 /* above. */ 1487 1488 /* Note, however, that both Ghostscript and Adobe */ 1489 /* Distiller handle this situation by silently ignoring */ 1490 /* the inappropriate `setcurrentpoint' instruction. So */ 1491 /* we do the same. */ 1492 #if 0 1493 1494 if ( decoder->flex_state != 1 ) 1495 { 1496 FT_ERROR(( "t1_decoder_parse_charstrings:" 1497 " unexpected `setcurrentpoint'\n" )); 1498 goto Syntax_Error; 1499 } 1500 else 1501 ... 1502 #endif 1503 1504 x = top[0]; 1505 y = top[1]; 1506 decoder->flex_state = 0; 1507 break; 1508 1509 case op_unknown15: 1510 FT_TRACE4(( " opcode_15" )); 1511 /* nothing to do except to pop the two arguments */ 1512 break; 1513 1514 default: 1515 FT_ERROR(( "t1_decoder_parse_charstrings:" 1516 " unhandled opcode %d\n", op )); 1517 goto Syntax_Error; 1518 } 1519 1520 /* XXX Operators usually clear the operand stack; */ 1521 /* only div, callsubr, callothersubr, pop, and */ 1522 /* return are different. */ 1523 /* In practice it doesn't matter (?). */ 1524 1525 decoder->top = top; 1526 1527 #ifdef FT_DEBUG_LEVEL_TRACE 1528 FT_TRACE4(( "\n" )); 1529 bol = TRUE; 1530 #endif 1531 1532 } /* general operator processing */ 1533 1534 } /* while ip < limit */ 1535 1536 FT_TRACE4(( "..end..\n\n" )); 1537 1538 Fail: 1539 return error; 1540 1541 Syntax_Error: 1542 return PSaux_Err_Syntax_Error; 1543 1544 Stack_Underflow: 1545 return PSaux_Err_Stack_Underflow; 1546 } 1547 1548 1549 /* parse a single Type 1 glyph */ 1550 FT_LOCAL_DEF( FT_Error ) 1551 t1_decoder_parse_glyph( T1_Decoder decoder, 1552 FT_UInt glyph ) 1553 { 1554 return decoder->parse_callback( decoder, glyph ); 1555 } 1556 1557 1558 /* initialize T1 decoder */ 1559 FT_LOCAL_DEF( FT_Error ) 1560 t1_decoder_init( T1_Decoder decoder, 1561 FT_Face face, 1562 FT_Size size, 1563 FT_GlyphSlot slot, 1564 FT_Byte** glyph_names, 1565 PS_Blend blend, 1566 FT_Bool hinting, 1567 FT_Render_Mode hint_mode, 1568 T1_Decoder_Callback parse_callback ) 1569 { 1570 FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); 1571 1572 /* retrieve PSNames interface from list of current modules */ 1573 { 1574 FT_Service_PsCMaps psnames = 0; 1575 1576 1577 FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); 1578 if ( !psnames ) 1579 { 1580 FT_ERROR(( "t1_decoder_init:" 1581 " the `psnames' module is not available\n" )); 1582 return PSaux_Err_Unimplemented_Feature; 1583 } 1584 1585 decoder->psnames = psnames; 1586 } 1587 1588 t1_builder_init( &decoder->builder, face, size, slot, hinting ); 1589 1590 /* decoder->buildchar and decoder->len_buildchar have to be */ 1591 /* initialized by the caller since we cannot know the length */ 1592 /* of the BuildCharArray */ 1593 1594 decoder->num_glyphs = (FT_UInt)face->num_glyphs; 1595 decoder->glyph_names = glyph_names; 1596 decoder->hint_mode = hint_mode; 1597 decoder->blend = blend; 1598 decoder->parse_callback = parse_callback; 1599 1600 decoder->funcs = t1_decoder_funcs; 1601 1602 return PSaux_Err_Ok; 1603 } 1604 1605 1606 /* finalize T1 decoder */ 1607 FT_LOCAL_DEF( void ) 1608 t1_decoder_done( T1_Decoder decoder ) 1609 { 1610 t1_builder_done( &decoder->builder ); 1611 } 1612 1613 1614 /* END */ 1615