1 /***************************************************************************/ 2 /* */ 3 /* t1decode.c */ 4 /* */ 5 /* PostScript Type 1 decoding routines (body). */ 6 /* */ 7 /* Copyright 2000-2001, 2002 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_DEBUG_H 21 #include FT_INTERNAL_POSTSCRIPT_HINTS_H 22 #include FT_OUTLINE_H 23 24 #include "t1decode.h" 25 #include "psobjs.h" 26 27 #include "psauxerr.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_t1decode 38 39 40 typedef enum T1_Operator_ 41 { 42 op_none = 0, 43 op_endchar, 44 op_hsbw, 45 op_seac, 46 op_sbw, 47 op_closepath, 48 op_hlineto, 49 op_hmoveto, 50 op_hvcurveto, 51 op_rlineto, 52 op_rmoveto, 53 op_rrcurveto, 54 op_vhcurveto, 55 op_vlineto, 56 op_vmoveto, 57 op_dotsection, 58 op_hstem, 59 op_hstem3, 60 op_vstem, 61 op_vstem3, 62 op_div, 63 op_callothersubr, 64 op_callsubr, 65 op_pop, 66 op_return, 67 op_setcurrentpoint, 68 69 op_max /* never remove this one */ 70 71 } T1_Operator; 72 73 74 static 75 const FT_Int t1_args_count[op_max] = 76 { 77 0, /* none */ 78 0, /* endchar */ 79 2, /* hsbw */ 80 5, /* seac */ 81 4, /* sbw */ 82 0, /* closepath */ 83 1, /* hlineto */ 84 1, /* hmoveto */ 85 4, /* hvcurveto */ 86 2, /* rlineto */ 87 2, /* rmoveto */ 88 6, /* rrcurveto */ 89 4, /* vhcurveto */ 90 1, /* vlineto */ 91 1, /* vmoveto */ 92 0, /* dotsection */ 93 2, /* hstem */ 94 6, /* hstem3 */ 95 2, /* vstem */ 96 6, /* vstem3 */ 97 2, /* div */ 98 -1, /* callothersubr */ 99 1, /* callsubr */ 100 0, /* pop */ 101 0, /* return */ 102 2 /* setcurrentpoint */ 103 }; 104 105 106 /*************************************************************************/ 107 /* */ 108 /* <Function> */ 109 /* t1_lookup_glyph_by_stdcharcode */ 110 /* */ 111 /* <Description> */ 112 /* Looks up a given glyph by its StandardEncoding charcode. Used to */ 113 /* implement the SEAC Type 1 operator. */ 114 /* */ 115 /* <Input> */ 116 /* face :: The current face object. */ 117 /* */ 118 /* charcode :: The character code to look for. */ 119 /* */ 120 /* <Return> */ 121 /* A glyph index in the font face. Returns -1 if the corresponding */ 122 /* glyph wasn't found. */ 123 /* */ 124 static FT_Int t1_lookup_glyph_by_stdcharcode(T1_Decoder decoder,FT_Int charcode)125 t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder, 126 FT_Int charcode ) 127 { 128 FT_UInt n; 129 const FT_String* glyph_name; 130 PSNames_Service psnames = decoder->psnames; 131 132 133 /* check range of standard char code */ 134 if ( charcode < 0 || charcode > 255 ) 135 return -1; 136 137 glyph_name = psnames->adobe_std_strings( 138 psnames->adobe_std_encoding[charcode]); 139 140 for ( n = 0; n < decoder->num_glyphs; n++ ) 141 { 142 FT_String* name = (FT_String*)decoder->glyph_names[n]; 143 144 145 if ( name && name[0] == glyph_name[0] && 146 ft_strcmp( name,glyph_name ) == 0 ) 147 return n; 148 } 149 150 return -1; 151 } 152 153 154 /*************************************************************************/ 155 /* */ 156 /* <Function> */ 157 /* t1operator_seac */ 158 /* */ 159 /* <Description> */ 160 /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ 161 /* */ 162 /* <Input> */ 163 /* decoder :: The current CID decoder. */ 164 /* */ 165 /* asb :: The accent's side bearing. */ 166 /* */ 167 /* adx :: The horizontal offset of the accent. */ 168 /* */ 169 /* ady :: The vertical offset of the accent. */ 170 /* */ 171 /* bchar :: The base character's StandardEncoding charcode. */ 172 /* */ 173 /* achar :: The accent character's StandardEncoding charcode. */ 174 /* */ 175 /* <Return> */ 176 /* FreeType error code. 0 means success. */ 177 /* */ 178 static FT_Error t1operator_seac(T1_Decoder decoder,FT_Pos asb,FT_Pos adx,FT_Pos ady,FT_Int bchar,FT_Int achar)179 t1operator_seac( T1_Decoder decoder, 180 FT_Pos asb, 181 FT_Pos adx, 182 FT_Pos ady, 183 FT_Int bchar, 184 FT_Int achar ) 185 { 186 FT_Error error; 187 FT_Int bchar_index, achar_index; 188 #if 0 189 FT_Int n_base_points; 190 FT_Outline* base = decoder->builder.base; 191 #endif 192 FT_Vector left_bearing, advance; 193 194 195 /* seac weirdness */ 196 adx += decoder->builder.left_bearing.x; 197 198 /* `glyph_names' is set to 0 for CID fonts which do not */ 199 /* include an encoding. How can we deal with these? */ 200 if ( decoder->glyph_names == 0 ) 201 { 202 FT_ERROR(( "t1operator_seac:" )); 203 FT_ERROR(( " glyph names table not available in this font!\n" )); 204 return PSaux_Err_Syntax_Error; 205 } 206 207 bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar ); 208 achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar ); 209 210 if ( bchar_index < 0 || achar_index < 0 ) 211 { 212 FT_ERROR(( "t1operator_seac:" )); 213 FT_ERROR(( " invalid seac character code arguments\n" )); 214 return PSaux_Err_Syntax_Error; 215 } 216 217 /* if we are trying to load a composite glyph, do not load the */ 218 /* accent character and return the array of subglyphs. */ 219 if ( decoder->builder.no_recurse ) 220 { 221 FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; 222 FT_GlyphLoader loader = glyph->internal->loader; 223 FT_SubGlyph subg; 224 225 226 /* reallocate subglyph array if necessary */ 227 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); 228 if ( error ) 229 goto Exit; 230 231 subg = loader->current.subglyphs; 232 233 /* subglyph 0 = base character */ 234 subg->index = bchar_index; 235 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | 236 FT_SUBGLYPH_FLAG_USE_MY_METRICS; 237 subg->arg1 = 0; 238 subg->arg2 = 0; 239 subg++; 240 241 /* subglyph 1 = accent character */ 242 subg->index = achar_index; 243 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; 244 subg->arg1 = adx - asb; 245 subg->arg2 = ady; 246 247 /* set up remaining glyph fields */ 248 glyph->num_subglyphs = 2; 249 glyph->subglyphs = loader->base.subglyphs; 250 glyph->format = FT_GLYPH_FORMAT_COMPOSITE; 251 252 loader->current.num_subglyphs = 2; 253 goto Exit; 254 } 255 256 /* First load `bchar' in builder */ 257 /* now load the unscaled outline */ 258 259 FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ 260 261 error = t1_decoder_parse_glyph( decoder, bchar_index ); 262 if ( error ) 263 goto Exit; 264 265 #if 0 266 n_base_points = base->n_points; 267 #endif 268 269 /* save the left bearing and width of the base character */ 270 /* as they will be erased by the next load. */ 271 272 left_bearing = decoder->builder.left_bearing; 273 advance = decoder->builder.advance; 274 275 decoder->builder.left_bearing.x = 0; 276 decoder->builder.left_bearing.y = 0; 277 278 decoder->builder.pos_x = adx - asb; 279 decoder->builder.pos_y = ady; 280 281 /* Now load `achar' on top of */ 282 /* the base outline */ 283 error = t1_decoder_parse_glyph( decoder, achar_index ); 284 if ( error ) 285 goto Exit; 286 287 /* restore the left side bearing and */ 288 /* advance width of the base character */ 289 290 decoder->builder.left_bearing = left_bearing; 291 decoder->builder.advance = advance; 292 293 /* XXX: old code doesn't work with PostScript hinter */ 294 #if 0 295 /* Finally, move the accent */ 296 if ( decoder->builder.load_points ) 297 { 298 FT_Outline dummy; 299 300 301 dummy.n_points = (short)( base->n_points - n_base_points ); 302 dummy.points = base->points + n_base_points; 303 304 FT_Outline_Translate( &dummy, adx - asb, ady ); 305 } 306 #else 307 decoder->builder.pos_x = 0; 308 decoder->builder.pos_y = 0; 309 #endif 310 311 Exit: 312 return error; 313 } 314 315 316 /*************************************************************************/ 317 /* */ 318 /* <Function> */ 319 /* t1_decoder_parse_charstrings */ 320 /* */ 321 /* <Description> */ 322 /* Parses a given Type 1 charstrings program. */ 323 /* */ 324 /* <Input> */ 325 /* decoder :: The current Type 1 decoder. */ 326 /* */ 327 /* charstring_base :: The base address of the charstring stream. */ 328 /* */ 329 /* charstring_len :: The length in bytes of the charstring stream. */ 330 /* */ 331 /* <Return> */ 332 /* FreeType error code. 0 means success. */ 333 /* */ 334 FT_LOCAL_DEF( FT_Error ) t1_decoder_parse_charstrings(T1_Decoder decoder,FT_Byte * charstring_base,FT_UInt charstring_len)335 t1_decoder_parse_charstrings( T1_Decoder decoder, 336 FT_Byte* charstring_base, 337 FT_UInt charstring_len ) 338 { 339 FT_Error error; 340 T1_Decoder_Zone zone; 341 FT_Byte* ip; 342 FT_Byte* limit; 343 T1_Builder builder = &decoder->builder; 344 FT_Pos x, y, orig_x, orig_y; 345 346 T1_Hints_Funcs hinter; 347 348 349 /* we don't want to touch the source code -- use macro trick */ 350 #define start_point t1_builder_start_point 351 #define check_points t1_builder_check_points 352 #define add_point t1_builder_add_point 353 #define add_point1 t1_builder_add_point1 354 #define add_contour t1_builder_add_contour 355 #define close_contour t1_builder_close_contour 356 357 /* First of all, initialize the decoder */ 358 decoder->top = decoder->stack; 359 decoder->zone = decoder->zones; 360 zone = decoder->zones; 361 362 builder->path_begun = 0; 363 364 hinter = (T1_Hints_Funcs)builder->hints_funcs; 365 366 zone->base = charstring_base; 367 limit = zone->limit = charstring_base + charstring_len; 368 ip = zone->cursor = zone->base; 369 370 error = PSaux_Err_Ok; 371 372 x = orig_x = builder->pos_x; 373 y = orig_y = builder->pos_y; 374 375 /* begin hints recording session, if any */ 376 if ( hinter ) 377 hinter->open( hinter->hints ); 378 379 /* now, execute loop */ 380 while ( ip < limit ) 381 { 382 FT_Long* top = decoder->top; 383 T1_Operator op = op_none; 384 FT_Long value = 0; 385 386 387 /*********************************************************************/ 388 /* */ 389 /* Decode operator or operand */ 390 /* */ 391 /* */ 392 393 /* first of all, decompress operator or value */ 394 switch ( *ip++ ) 395 { 396 case 1: 397 op = op_hstem; 398 break; 399 400 case 3: 401 op = op_vstem; 402 break; 403 case 4: 404 op = op_vmoveto; 405 break; 406 case 5: 407 op = op_rlineto; 408 break; 409 case 6: 410 op = op_hlineto; 411 break; 412 case 7: 413 op = op_vlineto; 414 break; 415 case 8: 416 op = op_rrcurveto; 417 break; 418 case 9: 419 op = op_closepath; 420 break; 421 case 10: 422 op = op_callsubr; 423 break; 424 case 11: 425 op = op_return; 426 break; 427 428 case 13: 429 op = op_hsbw; 430 break; 431 case 14: 432 op = op_endchar; 433 break; 434 435 case 15: /* undocumented, obsolete operator */ 436 op = op_none; 437 break; 438 439 case 21: 440 op = op_rmoveto; 441 break; 442 case 22: 443 op = op_hmoveto; 444 break; 445 446 case 30: 447 op = op_vhcurveto; 448 break; 449 case 31: 450 op = op_hvcurveto; 451 break; 452 453 case 12: 454 if ( ip > limit ) 455 { 456 FT_ERROR(( "t1_decoder_parse_charstrings: " 457 "invalid escape (12+EOF)\n" )); 458 goto Syntax_Error; 459 } 460 461 switch ( *ip++ ) 462 { 463 case 0: 464 op = op_dotsection; 465 break; 466 case 1: 467 op = op_vstem3; 468 break; 469 case 2: 470 op = op_hstem3; 471 break; 472 case 6: 473 op = op_seac; 474 break; 475 case 7: 476 op = op_sbw; 477 break; 478 case 12: 479 op = op_div; 480 break; 481 case 16: 482 op = op_callothersubr; 483 break; 484 case 17: 485 op = op_pop; 486 break; 487 case 33: 488 op = op_setcurrentpoint; 489 break; 490 491 default: 492 FT_ERROR(( "t1_decoder_parse_charstrings: " 493 "invalid escape (12+%d)\n", 494 ip[-1] )); 495 goto Syntax_Error; 496 } 497 break; 498 499 case 255: /* four bytes integer */ 500 if ( ip + 4 > limit ) 501 { 502 FT_ERROR(( "t1_decoder_parse_charstrings: " 503 "unexpected EOF in integer\n" )); 504 goto Syntax_Error; 505 } 506 507 value = (FT_Int32)( ((FT_Long)ip[0] << 24) | 508 ((FT_Long)ip[1] << 16) | 509 ((FT_Long)ip[2] << 8 ) | 510 ip[3] ); 511 ip += 4; 512 break; 513 514 default: 515 if ( ip[-1] >= 32 ) 516 { 517 if ( ip[-1] < 247 ) 518 value = (FT_Long)ip[-1] - 139; 519 else 520 { 521 if ( ++ip > limit ) 522 { 523 FT_ERROR(( "t1_decoder_parse_charstrings: " )); 524 FT_ERROR(( "unexpected EOF in integer\n" )); 525 goto Syntax_Error; 526 } 527 528 if ( ip[-2] < 251 ) 529 value = ( ( (FT_Long)ip[-2] - 247 ) << 8 ) + ip[-1] + 108; 530 else 531 value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); 532 } 533 } 534 else 535 { 536 FT_ERROR(( "t1_decoder_parse_charstrings: " 537 "invalid byte (%d)\n", ip[-1] )); 538 goto Syntax_Error; 539 } 540 } 541 542 /*********************************************************************/ 543 /* */ 544 /* Push value on stack, or process operator */ 545 /* */ 546 /* */ 547 if ( op == op_none ) 548 { 549 if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) 550 { 551 FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow!\n" )); 552 goto Syntax_Error; 553 } 554 555 FT_TRACE4(( " %ld", value )); 556 557 *top++ = value; 558 decoder->top = top; 559 } 560 else if ( op == op_callothersubr ) /* callothersubr */ 561 { 562 FT_TRACE4(( " callothersubr" )); 563 564 if ( top - decoder->stack < 2 ) 565 goto Stack_Underflow; 566 567 top -= 2; 568 switch ( top[1] ) 569 { 570 case 1: /* start flex feature */ 571 if ( top[0] != 0 ) 572 goto Unexpected_OtherSubr; 573 574 decoder->flex_state = 1; 575 decoder->num_flex_vectors = 0; 576 if ( start_point( builder, x, y ) || 577 check_points( builder, 6 ) ) 578 goto Memory_Error; 579 break; 580 581 case 2: /* add flex vectors */ 582 { 583 FT_Int idx; 584 585 586 if ( top[0] != 0 ) 587 goto Unexpected_OtherSubr; 588 589 /* note that we should not add a point for index 0; */ 590 /* this will move our current position to the flex */ 591 /* point without adding any point to the outline */ 592 idx = decoder->num_flex_vectors++; 593 if ( idx > 0 && idx < 7 ) 594 add_point( builder, 595 x, 596 y, 597 (FT_Byte)( idx == 3 || idx == 6 ) ); 598 } 599 break; 600 601 case 0: /* end flex feature */ 602 if ( top[0] != 3 ) 603 goto Unexpected_OtherSubr; 604 605 if ( decoder->flex_state == 0 || 606 decoder->num_flex_vectors != 7 ) 607 { 608 FT_ERROR(( "t1_decoder_parse_charstrings: " 609 "unexpected flex end\n" )); 610 goto Syntax_Error; 611 } 612 613 /* now consume the remaining `pop pop setcurpoint' */ 614 if ( ip + 6 > limit || 615 ip[0] != 12 || ip[1] != 17 || /* pop */ 616 ip[2] != 12 || ip[3] != 17 || /* pop */ 617 ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */ 618 { 619 FT_ERROR(( "t1_decoder_parse_charstrings: " 620 "invalid flex charstring\n" )); 621 goto Syntax_Error; 622 } 623 624 ip += 6; 625 decoder->flex_state = 0; 626 break; 627 628 case 3: /* change hints */ 629 if ( top[0] != 1 ) 630 goto Unexpected_OtherSubr; 631 632 /* eat the following `pop' */ 633 if ( ip + 2 > limit ) 634 { 635 FT_ERROR(( "t1_decoder_parse_charstrings: " 636 "invalid escape (12+%d)\n", ip[-1] )); 637 goto Syntax_Error; 638 } 639 640 if ( ip[0] != 12 || ip[1] != 17 ) 641 { 642 FT_ERROR(( "t1_decoder_parse_charstrings: " )); 643 FT_ERROR(( "`pop' expected, found (%d %d)\n", ip[0], ip[1] )); 644 goto Syntax_Error; 645 } 646 ip += 2; 647 648 if ( hinter ) 649 hinter->reset( hinter->hints, builder->current->n_points ); 650 651 break; 652 653 case 12: 654 case 13: 655 /* counter control hints, clear stack */ 656 top = decoder->stack; 657 break; 658 659 case 14: 660 case 15: 661 case 16: 662 case 17: 663 case 18: /* multiple masters */ 664 { 665 PS_Blend blend = decoder->blend; 666 FT_UInt num_points, nn, mm; 667 FT_Long* delta; 668 FT_Long* values; 669 670 671 if ( !blend ) 672 { 673 FT_ERROR(( "t1_decoder_parse_charstrings: " )); 674 FT_ERROR(( "unexpected multiple masters operator!\n" )); 675 goto Syntax_Error; 676 } 677 678 num_points = (FT_UInt)top[1] - 13 + ( top[1] == 18 ); 679 if ( top[0] != (FT_Int)( num_points * blend->num_designs ) ) 680 { 681 FT_ERROR(( "t1_decoder_parse_charstrings: " )); 682 FT_ERROR(( "incorrect number of mm arguments\n" )); 683 goto Syntax_Error; 684 } 685 686 top -= blend->num_designs * num_points; 687 if ( top < decoder->stack ) 688 goto Stack_Underflow; 689 690 /* we want to compute: */ 691 /* */ 692 /* a0*w0 + a1*w1 + ... + ak*wk */ 693 /* */ 694 /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */ 695 /* however, given that w0 + w1 + ... + wk == 1, we can */ 696 /* rewrite it easily as: */ 697 /* */ 698 /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */ 699 /* */ 700 /* where k == num_designs-1 */ 701 /* */ 702 /* I guess that's why it's written in this `compact' */ 703 /* form. */ 704 /* */ 705 delta = top + num_points; 706 values = top; 707 for ( nn = 0; nn < num_points; nn++ ) 708 { 709 FT_Int tmp = values[0]; 710 711 712 for ( mm = 1; mm < blend->num_designs; mm++ ) 713 tmp += FT_MulFix( *delta++, blend->weight_vector[mm] ); 714 715 *values++ = tmp; 716 } 717 /* note that `top' will be incremented later by calls to `pop' */ 718 break; 719 } 720 721 default: 722 Unexpected_OtherSubr: 723 FT_ERROR(( "t1_decoder_parse_charstrings: " 724 "invalid othersubr [%d %d]!\n", top[0], top[1] )); 725 goto Syntax_Error; 726 } 727 decoder->top = top; 728 } 729 else /* general operator */ 730 { 731 FT_Int num_args = t1_args_count[op]; 732 733 734 if ( top - decoder->stack < num_args ) 735 goto Stack_Underflow; 736 737 top -= num_args; 738 739 switch ( op ) 740 { 741 case op_endchar: 742 FT_TRACE4(( " endchar" )); 743 744 close_contour( builder ); 745 746 /* close hints recording session */ 747 if ( hinter ) 748 { 749 if (hinter->close( hinter->hints, builder->current->n_points )) 750 goto Syntax_Error; 751 752 /* apply hints to the loaded glyph outline now */ 753 hinter->apply( hinter->hints, 754 builder->current, 755 (PSH_Globals) builder->hints_globals, 756 decoder->hint_mode ); 757 } 758 759 /* add current outline to the glyph slot */ 760 FT_GlyphLoader_Add( builder->loader ); 761 762 /* return now! */ 763 FT_TRACE4(( "\n\n" )); 764 return PSaux_Err_Ok; 765 766 case op_hsbw: 767 FT_TRACE4(( " hsbw" )); 768 769 builder->left_bearing.x += top[0]; 770 builder->advance.x = top[1]; 771 builder->advance.y = 0; 772 773 orig_x = builder->last.x = x = builder->pos_x + top[0]; 774 orig_y = builder->last.y = y = builder->pos_y; 775 776 FT_UNUSED( orig_y ); 777 778 /* the `metrics_only' indicates that we only want to compute */ 779 /* the glyph's metrics (lsb + advance width), not load the */ 780 /* rest of it; so exit immediately */ 781 if ( builder->metrics_only ) 782 return PSaux_Err_Ok; 783 784 break; 785 786 case op_seac: 787 /* return immediately after the processing */ 788 return t1operator_seac( decoder, top[0], top[1], 789 top[2], top[3], top[4] ); 790 791 case op_sbw: 792 FT_TRACE4(( " sbw" )); 793 794 builder->left_bearing.x += top[0]; 795 builder->left_bearing.y += top[1]; 796 builder->advance.x = top[2]; 797 builder->advance.y = top[3]; 798 799 builder->last.x = x = builder->pos_x + top[0]; 800 builder->last.y = y = builder->pos_y + top[1]; 801 802 /* the `metrics_only' indicates that we only want to compute */ 803 /* the glyph's metrics (lsb + advance width), not load the */ 804 /* rest of it; so exit immediately */ 805 if ( builder->metrics_only ) 806 return PSaux_Err_Ok; 807 808 break; 809 810 case op_closepath: 811 FT_TRACE4(( " closepath" )); 812 813 close_contour( builder ); 814 builder->path_begun = 0; 815 break; 816 817 case op_hlineto: 818 FT_TRACE4(( " hlineto" )); 819 820 if ( start_point( builder, x, y ) ) 821 goto Memory_Error; 822 823 x += top[0]; 824 goto Add_Line; 825 826 case op_hmoveto: 827 FT_TRACE4(( " hmoveto" )); 828 829 x += top[0]; 830 if ( !decoder->flex_state ) 831 builder->path_begun = 0; 832 break; 833 834 case op_hvcurveto: 835 FT_TRACE4(( " hvcurveto" )); 836 837 if ( start_point( builder, x, y ) || 838 check_points( builder, 3 ) ) 839 goto Memory_Error; 840 841 x += top[0]; 842 add_point( builder, x, y, 0 ); 843 x += top[1]; 844 y += top[2]; 845 add_point( builder, x, y, 0 ); 846 y += top[3]; 847 add_point( builder, x, y, 1 ); 848 break; 849 850 case op_rlineto: 851 FT_TRACE4(( " rlineto" )); 852 853 if ( start_point( builder, x, y ) ) 854 goto Memory_Error; 855 856 x += top[0]; 857 y += top[1]; 858 859 Add_Line: 860 if ( add_point1( builder, x, y ) ) 861 goto Memory_Error; 862 break; 863 864 case op_rmoveto: 865 FT_TRACE4(( " rmoveto" )); 866 867 x += top[0]; 868 y += top[1]; 869 if ( !decoder->flex_state ) 870 builder->path_begun = 0; 871 break; 872 873 case op_rrcurveto: 874 FT_TRACE4(( " rcurveto" )); 875 876 if ( start_point( builder, x, y ) || 877 check_points( builder, 3 ) ) 878 goto Memory_Error; 879 880 x += top[0]; 881 y += top[1]; 882 add_point( builder, x, y, 0 ); 883 884 x += top[2]; 885 y += top[3]; 886 add_point( builder, x, y, 0 ); 887 888 x += top[4]; 889 y += top[5]; 890 add_point( builder, x, y, 1 ); 891 break; 892 893 case op_vhcurveto: 894 FT_TRACE4(( " vhcurveto" )); 895 896 if ( start_point( builder, x, y ) || 897 check_points( builder, 3 ) ) 898 goto Memory_Error; 899 900 y += top[0]; 901 add_point( builder, x, y, 0 ); 902 x += top[1]; 903 y += top[2]; 904 add_point( builder, x, y, 0 ); 905 x += top[3]; 906 add_point( builder, x, y, 1 ); 907 break; 908 909 case op_vlineto: 910 FT_TRACE4(( " vlineto" )); 911 912 if ( start_point( builder, x, y ) ) 913 goto Memory_Error; 914 915 y += top[0]; 916 goto Add_Line; 917 918 case op_vmoveto: 919 FT_TRACE4(( " vmoveto" )); 920 921 y += top[0]; 922 if ( !decoder->flex_state ) 923 builder->path_begun = 0; 924 break; 925 926 case op_div: 927 FT_TRACE4(( " div" )); 928 929 if ( top[1] ) 930 { 931 *top = top[0] / top[1]; 932 ++top; 933 } 934 else 935 { 936 FT_ERROR(( "t1_decoder_parse_charstrings: division by 0\n" )); 937 goto Syntax_Error; 938 } 939 break; 940 941 case op_callsubr: 942 { 943 FT_Int idx; 944 945 946 FT_TRACE4(( " callsubr" )); 947 948 idx = top[0]; 949 if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs ) 950 { 951 FT_ERROR(( "t1_decoder_parse_charstrings: " 952 "invalid subrs index\n" )); 953 goto Syntax_Error; 954 } 955 956 if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) 957 { 958 FT_ERROR(( "t1_decoder_parse_charstrings: " 959 "too many nested subrs\n" )); 960 goto Syntax_Error; 961 } 962 963 zone->cursor = ip; /* save current instruction pointer */ 964 965 zone++; 966 967 /* The Type 1 driver stores subroutines without the seed bytes. */ 968 /* The CID driver stores subroutines with seed bytes. This */ 969 /* case is taken care of when decoder->subrs_len == 0. */ 970 zone->base = decoder->subrs[idx]; 971 972 if ( decoder->subrs_len ) 973 zone->limit = zone->base + decoder->subrs_len[idx]; 974 else 975 { 976 /* We are using subroutines from a CID font. We must adjust */ 977 /* for the seed bytes. */ 978 zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); 979 zone->limit = decoder->subrs[idx + 1]; 980 } 981 982 zone->cursor = zone->base; 983 984 if ( !zone->base ) 985 { 986 FT_ERROR(( "t1_decoder_parse_charstrings: " 987 "invoking empty subrs!\n" )); 988 goto Syntax_Error; 989 } 990 991 decoder->zone = zone; 992 ip = zone->base; 993 limit = zone->limit; 994 break; 995 } 996 997 case op_pop: 998 FT_TRACE4(( " pop" )); 999 1000 /* theoretically, the arguments are already on the stack */ 1001 top++; 1002 break; 1003 1004 case op_return: 1005 FT_TRACE4(( " return" )); 1006 1007 if ( zone <= decoder->zones ) 1008 { 1009 FT_ERROR(( "t1_decoder_parse_charstrings: unexpected return\n" )); 1010 goto Syntax_Error; 1011 } 1012 1013 zone--; 1014 ip = zone->cursor; 1015 limit = zone->limit; 1016 decoder->zone = zone; 1017 break; 1018 1019 case op_dotsection: 1020 FT_TRACE4(( " dotsection" )); 1021 1022 break; 1023 1024 case op_hstem: 1025 FT_TRACE4(( " hstem" )); 1026 1027 /* record horizontal hint */ 1028 if ( hinter ) 1029 { 1030 /* top[0] += builder->left_bearing.y; */ 1031 hinter->stem( hinter->hints, 1, top ); 1032 } 1033 1034 break; 1035 1036 case op_hstem3: 1037 FT_TRACE4(( " hstem3" )); 1038 1039 /* record horizontal counter-controlled hints */ 1040 if ( hinter ) 1041 hinter->stem3( hinter->hints, 1, top ); 1042 1043 break; 1044 1045 case op_vstem: 1046 FT_TRACE4(( " vstem" )); 1047 1048 /* record vertical hint */ 1049 if ( hinter ) 1050 { 1051 top[0] += orig_x; 1052 hinter->stem( hinter->hints, 0, top ); 1053 } 1054 1055 break; 1056 1057 case op_vstem3: 1058 FT_TRACE4(( " vstem3" )); 1059 1060 /* record vertical counter-controlled hints */ 1061 if ( hinter ) 1062 { 1063 FT_Pos dx = orig_x; 1064 1065 1066 top[0] += dx; 1067 top[2] += dx; 1068 top[4] += dx; 1069 hinter->stem3( hinter->hints, 0, top ); 1070 } 1071 break; 1072 1073 case op_setcurrentpoint: 1074 FT_TRACE4(( " setcurrentpoint" )); 1075 1076 FT_ERROR(( "t1_decoder_parse_charstrings: " )); 1077 FT_ERROR(( "unexpected `setcurrentpoint'\n" )); 1078 goto Syntax_Error; 1079 1080 default: 1081 FT_ERROR(( "t1_decoder_parse_charstrings: " 1082 "unhandled opcode %d\n", op )); 1083 goto Syntax_Error; 1084 } 1085 1086 decoder->top = top; 1087 1088 } /* general operator processing */ 1089 1090 } /* while ip < limit */ 1091 1092 FT_TRACE4(( "..end..\n\n" )); 1093 1094 return error; 1095 1096 Syntax_Error: 1097 return PSaux_Err_Syntax_Error; 1098 1099 Stack_Underflow: 1100 return PSaux_Err_Stack_Underflow; 1101 1102 Memory_Error: 1103 return builder->error; 1104 } 1105 1106 1107 /* parse a single Type 1 glyph */ 1108 FT_LOCAL_DEF( FT_Error ) t1_decoder_parse_glyph(T1_Decoder decoder,FT_UInt glyph)1109 t1_decoder_parse_glyph( T1_Decoder decoder, 1110 FT_UInt glyph ) 1111 { 1112 return decoder->parse_callback( decoder, glyph ); 1113 } 1114 1115 1116 /* initialize T1 decoder */ 1117 FT_LOCAL_DEF( FT_Error ) t1_decoder_init(T1_Decoder decoder,FT_Face face,FT_Size size,FT_GlyphSlot slot,FT_Byte ** glyph_names,PS_Blend blend,FT_Bool hinting,FT_Render_Mode hint_mode,T1_Decoder_Callback parse_callback)1118 t1_decoder_init( T1_Decoder decoder, 1119 FT_Face face, 1120 FT_Size size, 1121 FT_GlyphSlot slot, 1122 FT_Byte** glyph_names, 1123 PS_Blend blend, 1124 FT_Bool hinting, 1125 FT_Render_Mode hint_mode, 1126 T1_Decoder_Callback parse_callback ) 1127 { 1128 FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); 1129 1130 /* retrieve PSNames interface from list of current modules */ 1131 { 1132 PSNames_Service psnames = 0; 1133 1134 1135 psnames = (PSNames_Service)FT_Get_Module_Interface( 1136 FT_FACE_LIBRARY(face), "psnames" ); 1137 if ( !psnames ) 1138 { 1139 FT_ERROR(( "t1_decoder_init: " )); 1140 FT_ERROR(( "the `psnames' module is not available\n" )); 1141 return PSaux_Err_Unimplemented_Feature; 1142 } 1143 1144 decoder->psnames = psnames; 1145 } 1146 1147 t1_builder_init( &decoder->builder, face, size, slot, hinting ); 1148 1149 decoder->num_glyphs = (FT_UInt)face->num_glyphs; 1150 decoder->glyph_names = glyph_names; 1151 decoder->hint_flags = face->internal->hint_flags; 1152 decoder->hint_mode = hint_mode; 1153 decoder->blend = blend; 1154 decoder->parse_callback = parse_callback; 1155 1156 decoder->funcs = t1_decoder_funcs; 1157 1158 return 0; 1159 } 1160 1161 1162 /* finalize T1 decoder */ 1163 FT_LOCAL_DEF( void ) t1_decoder_done(T1_Decoder decoder)1164 t1_decoder_done( T1_Decoder decoder ) 1165 { 1166 t1_builder_done( &decoder->builder ); 1167 } 1168 1169 1170 /* END */ 1171