1 /***************************************************************************/ 2 /* */ 3 /* psobjs.c */ 4 /* */ 5 /* Auxiliary functions for PostScript fonts (body). */ 6 /* */ 7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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_POSTSCRIPT_AUX_H 21 #include FT_INTERNAL_DEBUG_H 22 23 #include "psobjs.h" 24 #include "psconv.h" 25 26 #include "psauxerr.h" 27 28 29 /*************************************************************************/ 30 /* */ 31 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 32 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 33 /* messages during execution. */ 34 /* */ 35 #undef FT_COMPONENT 36 #define FT_COMPONENT trace_psobjs 37 38 39 /*************************************************************************/ 40 /*************************************************************************/ 41 /***** *****/ 42 /***** PS_TABLE *****/ 43 /***** *****/ 44 /*************************************************************************/ 45 /*************************************************************************/ 46 47 /*************************************************************************/ 48 /* */ 49 /* <Function> */ 50 /* ps_table_new */ 51 /* */ 52 /* <Description> */ 53 /* Initializes a PS_Table. */ 54 /* */ 55 /* <InOut> */ 56 /* table :: The address of the target table. */ 57 /* */ 58 /* <Input> */ 59 /* count :: The table size = the maximum number of elements. */ 60 /* */ 61 /* memory :: The memory object to use for all subsequent */ 62 /* reallocations. */ 63 /* */ 64 /* <Return> */ 65 /* FreeType error code. 0 means success. */ 66 /* */ 67 FT_LOCAL_DEF( FT_Error ) ps_table_new(PS_Table table,FT_Int count,FT_Memory memory)68 ps_table_new( PS_Table table, 69 FT_Int count, 70 FT_Memory memory ) 71 { 72 FT_Error error; 73 74 75 table->memory = memory; 76 if ( FT_NEW_ARRAY( table->elements, count ) || 77 FT_NEW_ARRAY( table->lengths, count ) ) 78 goto Exit; 79 80 table->max_elems = count; 81 table->init = 0xDEADBEEFUL; 82 table->num_elems = 0; 83 table->block = 0; 84 table->capacity = 0; 85 table->cursor = 0; 86 87 *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; 88 89 Exit: 90 if ( error ) 91 FT_FREE( table->elements ); 92 93 return error; 94 } 95 96 97 static void shift_elements(PS_Table table,FT_Byte * old_base)98 shift_elements( PS_Table table, 99 FT_Byte* old_base ) 100 { 101 FT_PtrDist delta = table->block - old_base; 102 FT_Byte** offset = table->elements; 103 FT_Byte** limit = offset + table->max_elems; 104 105 106 for ( ; offset < limit; offset++ ) 107 { 108 if ( offset[0] ) 109 offset[0] += delta; 110 } 111 } 112 113 114 static FT_Error reallocate_t1_table(PS_Table table,FT_Long new_size)115 reallocate_t1_table( PS_Table table, 116 FT_Long new_size ) 117 { 118 FT_Memory memory = table->memory; 119 FT_Byte* old_base = table->block; 120 FT_Error error; 121 122 123 /* allocate new base block */ 124 if ( FT_ALLOC( table->block, new_size ) ) 125 { 126 table->block = old_base; 127 return error; 128 } 129 130 /* copy elements and shift offsets */ 131 if ( old_base ) 132 { 133 FT_MEM_COPY( table->block, old_base, table->capacity ); 134 shift_elements( table, old_base ); 135 FT_FREE( old_base ); 136 } 137 138 table->capacity = new_size; 139 140 return PSaux_Err_Ok; 141 } 142 143 144 /*************************************************************************/ 145 /* */ 146 /* <Function> */ 147 /* ps_table_add */ 148 /* */ 149 /* <Description> */ 150 /* Adds an object to a PS_Table, possibly growing its memory block. */ 151 /* */ 152 /* <InOut> */ 153 /* table :: The target table. */ 154 /* */ 155 /* <Input> */ 156 /* idx :: The index of the object in the table. */ 157 /* */ 158 /* object :: The address of the object to copy in memory. */ 159 /* */ 160 /* length :: The length in bytes of the source object. */ 161 /* */ 162 /* <Return> */ 163 /* FreeType error code. 0 means success. An error is returned if a */ 164 /* reallocation fails. */ 165 /* */ 166 FT_LOCAL_DEF( FT_Error ) ps_table_add(PS_Table table,FT_Int idx,void * object,FT_PtrDist length)167 ps_table_add( PS_Table table, 168 FT_Int idx, 169 void* object, 170 FT_PtrDist length ) 171 { 172 if ( idx < 0 || idx >= table->max_elems ) 173 { 174 FT_ERROR(( "ps_table_add: invalid index\n" )); 175 return PSaux_Err_Invalid_Argument; 176 } 177 178 if ( length < 0 ) 179 { 180 FT_ERROR(( "ps_table_add: invalid length\n" )); 181 return PSaux_Err_Invalid_Argument; 182 } 183 184 /* grow the base block if needed */ 185 if ( table->cursor + length > table->capacity ) 186 { 187 FT_Error error; 188 FT_Offset new_size = table->capacity; 189 FT_Long in_offset; 190 191 192 in_offset = (FT_Long)((FT_Byte*)object - table->block); 193 if ( (FT_ULong)in_offset >= table->capacity ) 194 in_offset = -1; 195 196 while ( new_size < table->cursor + length ) 197 { 198 /* increase size by 25% and round up to the nearest multiple 199 of 1024 */ 200 new_size += ( new_size >> 2 ) + 1; 201 new_size = FT_PAD_CEIL( new_size, 1024 ); 202 } 203 204 error = reallocate_t1_table( table, new_size ); 205 if ( error ) 206 return error; 207 208 if ( in_offset >= 0 ) 209 object = table->block + in_offset; 210 } 211 212 /* add the object to the base block and adjust offset */ 213 table->elements[idx] = table->block + table->cursor; 214 table->lengths [idx] = length; 215 FT_MEM_COPY( table->block + table->cursor, object, length ); 216 217 table->cursor += length; 218 return PSaux_Err_Ok; 219 } 220 221 222 /*************************************************************************/ 223 /* */ 224 /* <Function> */ 225 /* ps_table_done */ 226 /* */ 227 /* <Description> */ 228 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */ 229 /* cursor). */ 230 /* */ 231 /* <InOut> */ 232 /* table :: The target table. */ 233 /* */ 234 /* <Note> */ 235 /* This function does NOT release the heap's memory block. It is up */ 236 /* to the caller to clean it, or reference it in its own structures. */ 237 /* */ 238 FT_LOCAL_DEF( void ) ps_table_done(PS_Table table)239 ps_table_done( PS_Table table ) 240 { 241 FT_Memory memory = table->memory; 242 FT_Error error; 243 FT_Byte* old_base = table->block; 244 245 246 /* should never fail, because rec.cursor <= rec.size */ 247 if ( !old_base ) 248 return; 249 250 if ( FT_ALLOC( table->block, table->cursor ) ) 251 return; 252 FT_MEM_COPY( table->block, old_base, table->cursor ); 253 shift_elements( table, old_base ); 254 255 table->capacity = table->cursor; 256 FT_FREE( old_base ); 257 258 FT_UNUSED( error ); 259 } 260 261 262 FT_LOCAL_DEF( void ) ps_table_release(PS_Table table)263 ps_table_release( PS_Table table ) 264 { 265 FT_Memory memory = table->memory; 266 267 268 if ( (FT_ULong)table->init == 0xDEADBEEFUL ) 269 { 270 FT_FREE( table->block ); 271 FT_FREE( table->elements ); 272 FT_FREE( table->lengths ); 273 table->init = 0; 274 } 275 } 276 277 278 /*************************************************************************/ 279 /*************************************************************************/ 280 /***** *****/ 281 /***** T1 PARSER *****/ 282 /***** *****/ 283 /*************************************************************************/ 284 /*************************************************************************/ 285 286 287 /* first character must be already part of the comment */ 288 289 static void skip_comment(FT_Byte ** acur,FT_Byte * limit)290 skip_comment( FT_Byte* *acur, 291 FT_Byte* limit ) 292 { 293 FT_Byte* cur = *acur; 294 295 296 while ( cur < limit ) 297 { 298 if ( IS_PS_NEWLINE( *cur ) ) 299 break; 300 cur++; 301 } 302 303 *acur = cur; 304 } 305 306 307 static void skip_spaces(FT_Byte ** acur,FT_Byte * limit)308 skip_spaces( FT_Byte* *acur, 309 FT_Byte* limit ) 310 { 311 FT_Byte* cur = *acur; 312 313 314 while ( cur < limit ) 315 { 316 if ( !IS_PS_SPACE( *cur ) ) 317 { 318 if ( *cur == '%' ) 319 /* According to the PLRM, a comment is equal to a space. */ 320 skip_comment( &cur, limit ); 321 else 322 break; 323 } 324 cur++; 325 } 326 327 *acur = cur; 328 } 329 330 331 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) 332 333 334 /* first character must be `('; */ 335 /* *acur is positioned at the character after the closing `)' */ 336 337 static FT_Error skip_literal_string(FT_Byte ** acur,FT_Byte * limit)338 skip_literal_string( FT_Byte* *acur, 339 FT_Byte* limit ) 340 { 341 FT_Byte* cur = *acur; 342 FT_Int embed = 0; 343 FT_Error error = PSaux_Err_Invalid_File_Format; 344 unsigned int i; 345 346 347 while ( cur < limit ) 348 { 349 FT_Byte c = *cur; 350 351 352 ++cur; 353 354 if ( c == '\\' ) 355 { 356 /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ 357 /* A backslash can introduce three different types */ 358 /* of escape sequences: */ 359 /* - a special escaped char like \r, \n, etc. */ 360 /* - a one-, two-, or three-digit octal number */ 361 /* - none of the above in which case the backslash is ignored */ 362 363 if ( cur == limit ) 364 /* error (or to be ignored?) */ 365 break; 366 367 switch ( *cur ) 368 { 369 /* skip `special' escape */ 370 case 'n': 371 case 'r': 372 case 't': 373 case 'b': 374 case 'f': 375 case '\\': 376 case '(': 377 case ')': 378 ++cur; 379 break; 380 381 default: 382 /* skip octal escape or ignore backslash */ 383 for ( i = 0; i < 3 && cur < limit; ++i ) 384 { 385 if ( !IS_OCTAL_DIGIT( *cur ) ) 386 break; 387 388 ++cur; 389 } 390 } 391 } 392 else if ( c == '(' ) 393 embed++; 394 else if ( c == ')' ) 395 { 396 embed--; 397 if ( embed == 0 ) 398 { 399 error = PSaux_Err_Ok; 400 break; 401 } 402 } 403 } 404 405 *acur = cur; 406 407 return error; 408 } 409 410 411 /* first character must be `<' */ 412 413 static FT_Error skip_string(FT_Byte ** acur,FT_Byte * limit)414 skip_string( FT_Byte* *acur, 415 FT_Byte* limit ) 416 { 417 FT_Byte* cur = *acur; 418 FT_Error err = PSaux_Err_Ok; 419 420 421 while ( ++cur < limit ) 422 { 423 /* All whitespace characters are ignored. */ 424 skip_spaces( &cur, limit ); 425 if ( cur >= limit ) 426 break; 427 428 if ( !IS_PS_XDIGIT( *cur ) ) 429 break; 430 } 431 432 if ( cur < limit && *cur != '>' ) 433 { 434 FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); 435 err = PSaux_Err_Invalid_File_Format; 436 } 437 else 438 cur++; 439 440 *acur = cur; 441 return err; 442 } 443 444 445 /* first character must be the opening brace that */ 446 /* starts the procedure */ 447 448 /* NB: [ and ] need not match: */ 449 /* `/foo {[} def' is a valid PostScript fragment, */ 450 /* even within a Type1 font */ 451 452 static FT_Error skip_procedure(FT_Byte ** acur,FT_Byte * limit)453 skip_procedure( FT_Byte* *acur, 454 FT_Byte* limit ) 455 { 456 FT_Byte* cur; 457 FT_Int embed = 0; 458 FT_Error error = PSaux_Err_Ok; 459 460 461 FT_ASSERT( **acur == '{' ); 462 463 for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur ) 464 { 465 switch ( *cur ) 466 { 467 case '{': 468 ++embed; 469 break; 470 471 case '}': 472 --embed; 473 if ( embed == 0 ) 474 { 475 ++cur; 476 goto end; 477 } 478 break; 479 480 case '(': 481 error = skip_literal_string( &cur, limit ); 482 break; 483 484 case '<': 485 error = skip_string( &cur, limit ); 486 break; 487 488 case '%': 489 skip_comment( &cur, limit ); 490 break; 491 } 492 } 493 494 end: 495 if ( embed != 0 ) 496 error = PSaux_Err_Invalid_File_Format; 497 498 *acur = cur; 499 500 return error; 501 } 502 503 504 /***********************************************************************/ 505 /* */ 506 /* All exported parsing routines handle leading whitespace and stop at */ 507 /* the first character which isn't part of the just handled token. */ 508 /* */ 509 /***********************************************************************/ 510 511 512 FT_LOCAL_DEF( void ) ps_parser_skip_PS_token(PS_Parser parser)513 ps_parser_skip_PS_token( PS_Parser parser ) 514 { 515 /* Note: PostScript allows any non-delimiting, non-whitespace */ 516 /* character in a name (PS Ref Manual, 3rd ed, p31). */ 517 /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ 518 519 FT_Byte* cur = parser->cursor; 520 FT_Byte* limit = parser->limit; 521 FT_Error error = PSaux_Err_Ok; 522 523 524 skip_spaces( &cur, limit ); /* this also skips comments */ 525 if ( cur >= limit ) 526 goto Exit; 527 528 /* self-delimiting, single-character tokens */ 529 if ( *cur == '[' || *cur == ']' ) 530 { 531 cur++; 532 goto Exit; 533 } 534 535 /* skip balanced expressions (procedures and strings) */ 536 537 if ( *cur == '{' ) /* {...} */ 538 { 539 error = skip_procedure( &cur, limit ); 540 goto Exit; 541 } 542 543 if ( *cur == '(' ) /* (...) */ 544 { 545 error = skip_literal_string( &cur, limit ); 546 goto Exit; 547 } 548 549 if ( *cur == '<' ) /* <...> */ 550 { 551 if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */ 552 { 553 cur++; 554 cur++; 555 } 556 else 557 error = skip_string( &cur, limit ); 558 559 goto Exit; 560 } 561 562 if ( *cur == '>' ) 563 { 564 cur++; 565 if ( cur >= limit || *cur != '>' ) /* >> */ 566 { 567 FT_ERROR(( "ps_parser_skip_PS_token: " 568 "unexpected closing delimiter `>'\n" )); 569 error = PSaux_Err_Invalid_File_Format; 570 goto Exit; 571 } 572 cur++; 573 goto Exit; 574 } 575 576 if ( *cur == '/' ) 577 cur++; 578 579 /* anything else */ 580 while ( cur < limit ) 581 { 582 /* *cur might be invalid (e.g., ')' or '}'), but this */ 583 /* is handled by the test `cur == parser->cursor' below */ 584 if ( IS_PS_DELIM( *cur ) ) 585 break; 586 587 cur++; 588 } 589 590 Exit: 591 if ( cur == parser->cursor ) 592 { 593 FT_ERROR(( "ps_parser_skip_PS_token: " 594 "current token is `%c', which is self-delimiting " 595 "but invalid at this point\n", 596 *cur )); 597 598 error = PSaux_Err_Invalid_File_Format; 599 } 600 601 parser->error = error; 602 parser->cursor = cur; 603 } 604 605 606 FT_LOCAL_DEF( void ) ps_parser_skip_spaces(PS_Parser parser)607 ps_parser_skip_spaces( PS_Parser parser ) 608 { 609 skip_spaces( &parser->cursor, parser->limit ); 610 } 611 612 613 /* `token' here means either something between balanced delimiters */ 614 /* or the next token; the delimiters are not removed. */ 615 616 FT_LOCAL_DEF( void ) ps_parser_to_token(PS_Parser parser,T1_Token token)617 ps_parser_to_token( PS_Parser parser, 618 T1_Token token ) 619 { 620 FT_Byte* cur; 621 FT_Byte* limit; 622 FT_Int embed; 623 624 625 token->type = T1_TOKEN_TYPE_NONE; 626 token->start = 0; 627 token->limit = 0; 628 629 /* first of all, skip leading whitespace */ 630 ps_parser_skip_spaces( parser ); 631 632 cur = parser->cursor; 633 limit = parser->limit; 634 635 if ( cur >= limit ) 636 return; 637 638 switch ( *cur ) 639 { 640 /************* check for literal string *****************/ 641 case '(': 642 token->type = T1_TOKEN_TYPE_STRING; 643 token->start = cur; 644 645 if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok ) 646 token->limit = cur; 647 break; 648 649 /************* check for programs/array *****************/ 650 case '{': 651 token->type = T1_TOKEN_TYPE_ARRAY; 652 token->start = cur; 653 654 if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok ) 655 token->limit = cur; 656 break; 657 658 /************* check for table/array ********************/ 659 /* XXX: in theory we should also look for "<<" */ 660 /* since this is semantically equivalent to "["; */ 661 /* in practice it doesn't matter (?) */ 662 case '[': 663 token->type = T1_TOKEN_TYPE_ARRAY; 664 embed = 1; 665 token->start = cur++; 666 667 /* we need this to catch `[ ]' */ 668 parser->cursor = cur; 669 ps_parser_skip_spaces( parser ); 670 cur = parser->cursor; 671 672 while ( cur < limit && !parser->error ) 673 { 674 /* XXX: this is wrong because it does not */ 675 /* skip comments, procedures, and strings */ 676 if ( *cur == '[' ) 677 embed++; 678 else if ( *cur == ']' ) 679 { 680 embed--; 681 if ( embed <= 0 ) 682 { 683 token->limit = ++cur; 684 break; 685 } 686 } 687 688 parser->cursor = cur; 689 ps_parser_skip_PS_token( parser ); 690 /* we need this to catch `[XXX ]' */ 691 ps_parser_skip_spaces ( parser ); 692 cur = parser->cursor; 693 } 694 break; 695 696 /* ************ otherwise, it is any token **************/ 697 default: 698 token->start = cur; 699 token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY ); 700 ps_parser_skip_PS_token( parser ); 701 cur = parser->cursor; 702 if ( !parser->error ) 703 token->limit = cur; 704 } 705 706 if ( !token->limit ) 707 { 708 token->start = 0; 709 token->type = T1_TOKEN_TYPE_NONE; 710 } 711 712 parser->cursor = cur; 713 } 714 715 716 /* NB: `tokens' can be NULL if we only want to count */ 717 /* the number of array elements */ 718 719 FT_LOCAL_DEF( void ) ps_parser_to_token_array(PS_Parser parser,T1_Token tokens,FT_UInt max_tokens,FT_Int * pnum_tokens)720 ps_parser_to_token_array( PS_Parser parser, 721 T1_Token tokens, 722 FT_UInt max_tokens, 723 FT_Int* pnum_tokens ) 724 { 725 T1_TokenRec master; 726 727 728 *pnum_tokens = -1; 729 730 /* this also handles leading whitespace */ 731 ps_parser_to_token( parser, &master ); 732 733 if ( master.type == T1_TOKEN_TYPE_ARRAY ) 734 { 735 FT_Byte* old_cursor = parser->cursor; 736 FT_Byte* old_limit = parser->limit; 737 T1_Token cur = tokens; 738 T1_Token limit = cur + max_tokens; 739 740 741 /* don't include outermost delimiters */ 742 parser->cursor = master.start + 1; 743 parser->limit = master.limit - 1; 744 745 while ( parser->cursor < parser->limit ) 746 { 747 T1_TokenRec token; 748 749 750 ps_parser_to_token( parser, &token ); 751 if ( !token.type ) 752 break; 753 754 if ( tokens != NULL && cur < limit ) 755 *cur = token; 756 757 cur++; 758 } 759 760 *pnum_tokens = (FT_Int)( cur - tokens ); 761 762 parser->cursor = old_cursor; 763 parser->limit = old_limit; 764 } 765 } 766 767 768 /* first character must be a delimiter or a part of a number */ 769 /* NB: `coords' can be NULL if we just want to skip the */ 770 /* array; in this case we ignore `max_coords' */ 771 772 static FT_Int ps_tocoordarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_coords,FT_Short * coords)773 ps_tocoordarray( FT_Byte* *acur, 774 FT_Byte* limit, 775 FT_Int max_coords, 776 FT_Short* coords ) 777 { 778 FT_Byte* cur = *acur; 779 FT_Int count = 0; 780 FT_Byte c, ender; 781 782 783 if ( cur >= limit ) 784 goto Exit; 785 786 /* check for the beginning of an array; otherwise, only one number */ 787 /* will be read */ 788 c = *cur; 789 ender = 0; 790 791 if ( c == '[' ) 792 ender = ']'; 793 else if ( c == '{' ) 794 ender = '}'; 795 796 if ( ender ) 797 cur++; 798 799 /* now, read the coordinates */ 800 while ( cur < limit ) 801 { 802 FT_Short dummy; 803 FT_Byte* old_cur; 804 805 806 /* skip whitespace in front of data */ 807 skip_spaces( &cur, limit ); 808 if ( cur >= limit ) 809 goto Exit; 810 811 if ( *cur == ender ) 812 { 813 cur++; 814 break; 815 } 816 817 old_cur = cur; 818 819 if ( coords != NULL && count >= max_coords ) 820 break; 821 822 /* call PS_Conv_ToFixed() even if coords == NULL */ 823 /* to properly parse number at `cur' */ 824 *( coords != NULL ? &coords[count] : &dummy ) = 825 (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); 826 827 if ( old_cur == cur ) 828 { 829 count = -1; 830 goto Exit; 831 } 832 else 833 count++; 834 835 if ( !ender ) 836 break; 837 } 838 839 Exit: 840 *acur = cur; 841 return count; 842 } 843 844 845 /* first character must be a delimiter or a part of a number */ 846 /* NB: `values' can be NULL if we just want to skip the */ 847 /* array; in this case we ignore `max_values' */ 848 849 static FT_Int ps_tofixedarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)850 ps_tofixedarray( FT_Byte* *acur, 851 FT_Byte* limit, 852 FT_Int max_values, 853 FT_Fixed* values, 854 FT_Int power_ten ) 855 { 856 FT_Byte* cur = *acur; 857 FT_Int count = 0; 858 FT_Byte c, ender; 859 860 861 if ( cur >= limit ) 862 goto Exit; 863 864 /* Check for the beginning of an array. Otherwise, only one number */ 865 /* will be read. */ 866 c = *cur; 867 ender = 0; 868 869 if ( c == '[' ) 870 ender = ']'; 871 else if ( c == '{' ) 872 ender = '}'; 873 874 if ( ender ) 875 cur++; 876 877 /* now, read the values */ 878 while ( cur < limit ) 879 { 880 FT_Fixed dummy; 881 FT_Byte* old_cur; 882 883 884 /* skip whitespace in front of data */ 885 skip_spaces( &cur, limit ); 886 if ( cur >= limit ) 887 goto Exit; 888 889 if ( *cur == ender ) 890 { 891 cur++; 892 break; 893 } 894 895 old_cur = cur; 896 897 if ( values != NULL && count >= max_values ) 898 break; 899 900 /* call PS_Conv_ToFixed() even if coords == NULL */ 901 /* to properly parse number at `cur' */ 902 *( values != NULL ? &values[count] : &dummy ) = 903 PS_Conv_ToFixed( &cur, limit, power_ten ); 904 905 if ( old_cur == cur ) 906 { 907 count = -1; 908 goto Exit; 909 } 910 else 911 count++; 912 913 if ( !ender ) 914 break; 915 } 916 917 Exit: 918 *acur = cur; 919 return count; 920 } 921 922 923 #if 0 924 925 static FT_String* 926 ps_tostring( FT_Byte** cursor, 927 FT_Byte* limit, 928 FT_Memory memory ) 929 { 930 FT_Byte* cur = *cursor; 931 FT_PtrDist len = 0; 932 FT_Int count; 933 FT_String* result; 934 FT_Error error; 935 936 937 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ 938 /* that simply doesn't begin with an opening parenthesis, even */ 939 /* though they have a closing one! E.g. "amuncial.pfb" */ 940 /* */ 941 /* We must deal with these ill-fated cases there. Note that */ 942 /* these fonts didn't work with the old Type 1 driver as the */ 943 /* notice/copyright was not recognized as a valid string token */ 944 /* and made the old token parser commit errors. */ 945 946 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) 947 cur++; 948 if ( cur + 1 >= limit ) 949 return 0; 950 951 if ( *cur == '(' ) 952 cur++; /* skip the opening parenthesis, if there is one */ 953 954 *cursor = cur; 955 count = 0; 956 957 /* then, count its length */ 958 for ( ; cur < limit; cur++ ) 959 { 960 if ( *cur == '(' ) 961 count++; 962 963 else if ( *cur == ')' ) 964 { 965 count--; 966 if ( count < 0 ) 967 break; 968 } 969 } 970 971 len = cur - *cursor; 972 if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) 973 return 0; 974 975 /* now copy the string */ 976 FT_MEM_COPY( result, *cursor, len ); 977 result[len] = '\0'; 978 *cursor = cur; 979 return result; 980 } 981 982 #endif /* 0 */ 983 984 985 static int ps_tobool(FT_Byte ** acur,FT_Byte * limit)986 ps_tobool( FT_Byte* *acur, 987 FT_Byte* limit ) 988 { 989 FT_Byte* cur = *acur; 990 FT_Bool result = 0; 991 992 993 /* return 1 if we find `true', 0 otherwise */ 994 if ( cur + 3 < limit && 995 cur[0] == 't' && 996 cur[1] == 'r' && 997 cur[2] == 'u' && 998 cur[3] == 'e' ) 999 { 1000 result = 1; 1001 cur += 5; 1002 } 1003 else if ( cur + 4 < limit && 1004 cur[0] == 'f' && 1005 cur[1] == 'a' && 1006 cur[2] == 'l' && 1007 cur[3] == 's' && 1008 cur[4] == 'e' ) 1009 { 1010 result = 0; 1011 cur += 6; 1012 } 1013 1014 *acur = cur; 1015 return result; 1016 } 1017 1018 1019 /* load a simple field (i.e. non-table) into the current list of objects */ 1020 1021 FT_LOCAL_DEF( FT_Error ) ps_parser_load_field(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)1022 ps_parser_load_field( PS_Parser parser, 1023 const T1_Field field, 1024 void** objects, 1025 FT_UInt max_objects, 1026 FT_ULong* pflags ) 1027 { 1028 T1_TokenRec token; 1029 FT_Byte* cur; 1030 FT_Byte* limit; 1031 FT_UInt count; 1032 FT_UInt idx; 1033 FT_Error error; 1034 1035 1036 /* this also skips leading whitespace */ 1037 ps_parser_to_token( parser, &token ); 1038 if ( !token.type ) 1039 goto Fail; 1040 1041 count = 1; 1042 idx = 0; 1043 cur = token.start; 1044 limit = token.limit; 1045 1046 /* we must detect arrays in /FontBBox */ 1047 if ( field->type == T1_FIELD_TYPE_BBOX ) 1048 { 1049 T1_TokenRec token2; 1050 FT_Byte* old_cur = parser->cursor; 1051 FT_Byte* old_limit = parser->limit; 1052 1053 1054 /* don't include delimiters */ 1055 parser->cursor = token.start + 1; 1056 parser->limit = token.limit - 1; 1057 1058 ps_parser_to_token( parser, &token2 ); 1059 parser->cursor = old_cur; 1060 parser->limit = old_limit; 1061 1062 if ( token2.type == T1_TOKEN_TYPE_ARRAY ) 1063 goto FieldArray; 1064 } 1065 else if ( token.type == T1_TOKEN_TYPE_ARRAY ) 1066 { 1067 FieldArray: 1068 /* if this is an array and we have no blend, an error occurs */ 1069 if ( max_objects == 0 ) 1070 goto Fail; 1071 1072 count = max_objects; 1073 idx = 1; 1074 1075 /* don't include delimiters */ 1076 cur++; 1077 limit--; 1078 } 1079 1080 for ( ; count > 0; count--, idx++ ) 1081 { 1082 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; 1083 FT_Long val; 1084 FT_String* string; 1085 1086 1087 skip_spaces( &cur, limit ); 1088 1089 switch ( field->type ) 1090 { 1091 case T1_FIELD_TYPE_BOOL: 1092 val = ps_tobool( &cur, limit ); 1093 goto Store_Integer; 1094 1095 case T1_FIELD_TYPE_FIXED: 1096 val = PS_Conv_ToFixed( &cur, limit, 0 ); 1097 goto Store_Integer; 1098 1099 case T1_FIELD_TYPE_FIXED_1000: 1100 val = PS_Conv_ToFixed( &cur, limit, 3 ); 1101 goto Store_Integer; 1102 1103 case T1_FIELD_TYPE_INTEGER: 1104 val = PS_Conv_ToInt( &cur, limit ); 1105 /* fall through */ 1106 1107 Store_Integer: 1108 switch ( field->size ) 1109 { 1110 case (8 / FT_CHAR_BIT): 1111 *(FT_Byte*)q = (FT_Byte)val; 1112 break; 1113 1114 case (16 / FT_CHAR_BIT): 1115 *(FT_UShort*)q = (FT_UShort)val; 1116 break; 1117 1118 case (32 / FT_CHAR_BIT): 1119 *(FT_UInt32*)q = (FT_UInt32)val; 1120 break; 1121 1122 default: /* for 64-bit systems */ 1123 *(FT_Long*)q = val; 1124 } 1125 break; 1126 1127 case T1_FIELD_TYPE_STRING: 1128 case T1_FIELD_TYPE_KEY: 1129 { 1130 FT_Memory memory = parser->memory; 1131 FT_UInt len = (FT_UInt)( limit - cur ); 1132 1133 1134 if ( cur >= limit ) 1135 break; 1136 1137 /* we allow both a string or a name */ 1138 /* for cases like /FontName (foo) def */ 1139 if ( token.type == T1_TOKEN_TYPE_KEY ) 1140 { 1141 /* don't include leading `/' */ 1142 len--; 1143 cur++; 1144 } 1145 else if ( token.type == T1_TOKEN_TYPE_STRING ) 1146 { 1147 /* don't include delimiting parentheses */ 1148 /* XXX we don't handle <<...>> here */ 1149 /* XXX should we convert octal escapes? */ 1150 /* if so, what encoding should we use? */ 1151 cur++; 1152 len -= 2; 1153 } 1154 else 1155 { 1156 FT_ERROR(( "ps_parser_load_field: expected a name or string " 1157 "but found token of type %d instead\n", 1158 token.type )); 1159 error = PSaux_Err_Invalid_File_Format; 1160 goto Exit; 1161 } 1162 1163 /* for this to work (FT_String**)q must have been */ 1164 /* initialized to NULL */ 1165 if ( *(FT_String**)q != NULL ) 1166 { 1167 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", 1168 field->ident )); 1169 FT_FREE( *(FT_String**)q ); 1170 *(FT_String**)q = NULL; 1171 } 1172 1173 if ( FT_ALLOC( string, len + 1 ) ) 1174 goto Exit; 1175 1176 FT_MEM_COPY( string, cur, len ); 1177 string[len] = 0; 1178 1179 *(FT_String**)q = string; 1180 } 1181 break; 1182 1183 case T1_FIELD_TYPE_BBOX: 1184 { 1185 FT_Fixed temp[4]; 1186 FT_BBox* bbox = (FT_BBox*)q; 1187 FT_Int result; 1188 1189 1190 result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); 1191 1192 if ( result < 0 ) 1193 { 1194 FT_ERROR(( "ps_parser_load_field: " 1195 "expected four integers in bounding box\n" )); 1196 error = PSaux_Err_Invalid_File_Format; 1197 goto Exit; 1198 } 1199 1200 bbox->xMin = FT_RoundFix( temp[0] ); 1201 bbox->yMin = FT_RoundFix( temp[1] ); 1202 bbox->xMax = FT_RoundFix( temp[2] ); 1203 bbox->yMax = FT_RoundFix( temp[3] ); 1204 } 1205 break; 1206 1207 default: 1208 /* an error occurred */ 1209 goto Fail; 1210 } 1211 } 1212 1213 #if 0 /* obsolete -- keep for reference */ 1214 if ( pflags ) 1215 *pflags |= 1L << field->flag_bit; 1216 #else 1217 FT_UNUSED( pflags ); 1218 #endif 1219 1220 error = PSaux_Err_Ok; 1221 1222 Exit: 1223 return error; 1224 1225 Fail: 1226 error = PSaux_Err_Invalid_File_Format; 1227 goto Exit; 1228 } 1229 1230 1231 #define T1_MAX_TABLE_ELEMENTS 32 1232 1233 1234 FT_LOCAL_DEF( FT_Error ) ps_parser_load_field_table(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)1235 ps_parser_load_field_table( PS_Parser parser, 1236 const T1_Field field, 1237 void** objects, 1238 FT_UInt max_objects, 1239 FT_ULong* pflags ) 1240 { 1241 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; 1242 T1_Token token; 1243 FT_Int num_elements; 1244 FT_Error error = PSaux_Err_Ok; 1245 FT_Byte* old_cursor; 1246 FT_Byte* old_limit; 1247 T1_FieldRec fieldrec = *(T1_Field)field; 1248 1249 1250 fieldrec.type = T1_FIELD_TYPE_INTEGER; 1251 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || 1252 field->type == T1_FIELD_TYPE_BBOX ) 1253 fieldrec.type = T1_FIELD_TYPE_FIXED; 1254 1255 ps_parser_to_token_array( parser, elements, 1256 T1_MAX_TABLE_ELEMENTS, &num_elements ); 1257 if ( num_elements < 0 ) 1258 { 1259 error = PSaux_Err_Ignore; 1260 goto Exit; 1261 } 1262 if ( (FT_UInt)num_elements > field->array_max ) 1263 num_elements = field->array_max; 1264 1265 old_cursor = parser->cursor; 1266 old_limit = parser->limit; 1267 1268 /* we store the elements count if necessary; */ 1269 /* we further assume that `count_offset' can't be zero */ 1270 if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) 1271 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = 1272 (FT_Byte)num_elements; 1273 1274 /* we now load each element, adjusting the field.offset on each one */ 1275 token = elements; 1276 for ( ; num_elements > 0; num_elements--, token++ ) 1277 { 1278 parser->cursor = token->start; 1279 parser->limit = token->limit; 1280 ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 ); 1281 fieldrec.offset += fieldrec.size; 1282 } 1283 1284 #if 0 /* obsolete -- keep for reference */ 1285 if ( pflags ) 1286 *pflags |= 1L << field->flag_bit; 1287 #else 1288 FT_UNUSED( pflags ); 1289 #endif 1290 1291 parser->cursor = old_cursor; 1292 parser->limit = old_limit; 1293 1294 Exit: 1295 return error; 1296 } 1297 1298 1299 FT_LOCAL_DEF( FT_Long ) ps_parser_to_int(PS_Parser parser)1300 ps_parser_to_int( PS_Parser parser ) 1301 { 1302 ps_parser_skip_spaces( parser ); 1303 return PS_Conv_ToInt( &parser->cursor, parser->limit ); 1304 } 1305 1306 1307 /* first character must be `<' if `delimiters' is non-zero */ 1308 1309 FT_LOCAL_DEF( FT_Error ) ps_parser_to_bytes(PS_Parser parser,FT_Byte * bytes,FT_Long max_bytes,FT_Long * pnum_bytes,FT_Bool delimiters)1310 ps_parser_to_bytes( PS_Parser parser, 1311 FT_Byte* bytes, 1312 FT_Long max_bytes, 1313 FT_Long* pnum_bytes, 1314 FT_Bool delimiters ) 1315 { 1316 FT_Error error = PSaux_Err_Ok; 1317 FT_Byte* cur; 1318 1319 1320 ps_parser_skip_spaces( parser ); 1321 cur = parser->cursor; 1322 1323 if ( cur >= parser->limit ) 1324 goto Exit; 1325 1326 if ( delimiters ) 1327 { 1328 if ( *cur != '<' ) 1329 { 1330 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); 1331 error = PSaux_Err_Invalid_File_Format; 1332 goto Exit; 1333 } 1334 1335 cur++; 1336 } 1337 1338 *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, 1339 parser->limit, 1340 bytes, 1341 max_bytes ); 1342 1343 if ( delimiters ) 1344 { 1345 if ( cur < parser->limit && *cur != '>' ) 1346 { 1347 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); 1348 error = PSaux_Err_Invalid_File_Format; 1349 goto Exit; 1350 } 1351 1352 cur++; 1353 } 1354 1355 parser->cursor = cur; 1356 1357 Exit: 1358 return error; 1359 } 1360 1361 1362 FT_LOCAL_DEF( FT_Fixed ) ps_parser_to_fixed(PS_Parser parser,FT_Int power_ten)1363 ps_parser_to_fixed( PS_Parser parser, 1364 FT_Int power_ten ) 1365 { 1366 ps_parser_skip_spaces( parser ); 1367 return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); 1368 } 1369 1370 1371 FT_LOCAL_DEF( FT_Int ) ps_parser_to_coord_array(PS_Parser parser,FT_Int max_coords,FT_Short * coords)1372 ps_parser_to_coord_array( PS_Parser parser, 1373 FT_Int max_coords, 1374 FT_Short* coords ) 1375 { 1376 ps_parser_skip_spaces( parser ); 1377 return ps_tocoordarray( &parser->cursor, parser->limit, 1378 max_coords, coords ); 1379 } 1380 1381 1382 FT_LOCAL_DEF( FT_Int ) ps_parser_to_fixed_array(PS_Parser parser,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)1383 ps_parser_to_fixed_array( PS_Parser parser, 1384 FT_Int max_values, 1385 FT_Fixed* values, 1386 FT_Int power_ten ) 1387 { 1388 ps_parser_skip_spaces( parser ); 1389 return ps_tofixedarray( &parser->cursor, parser->limit, 1390 max_values, values, power_ten ); 1391 } 1392 1393 1394 #if 0 1395 1396 FT_LOCAL_DEF( FT_String* ) 1397 T1_ToString( PS_Parser parser ) 1398 { 1399 return ps_tostring( &parser->cursor, parser->limit, parser->memory ); 1400 } 1401 1402 1403 FT_LOCAL_DEF( FT_Bool ) 1404 T1_ToBool( PS_Parser parser ) 1405 { 1406 return ps_tobool( &parser->cursor, parser->limit ); 1407 } 1408 1409 #endif /* 0 */ 1410 1411 1412 FT_LOCAL_DEF( void ) ps_parser_init(PS_Parser parser,FT_Byte * base,FT_Byte * limit,FT_Memory memory)1413 ps_parser_init( PS_Parser parser, 1414 FT_Byte* base, 1415 FT_Byte* limit, 1416 FT_Memory memory ) 1417 { 1418 parser->error = PSaux_Err_Ok; 1419 parser->base = base; 1420 parser->limit = limit; 1421 parser->cursor = base; 1422 parser->memory = memory; 1423 parser->funcs = ps_parser_funcs; 1424 } 1425 1426 1427 FT_LOCAL_DEF( void ) ps_parser_done(PS_Parser parser)1428 ps_parser_done( PS_Parser parser ) 1429 { 1430 FT_UNUSED( parser ); 1431 } 1432 1433 1434 /*************************************************************************/ 1435 /*************************************************************************/ 1436 /***** *****/ 1437 /***** T1 BUILDER *****/ 1438 /***** *****/ 1439 /*************************************************************************/ 1440 /*************************************************************************/ 1441 1442 /*************************************************************************/ 1443 /* */ 1444 /* <Function> */ 1445 /* t1_builder_init */ 1446 /* */ 1447 /* <Description> */ 1448 /* Initializes a given glyph builder. */ 1449 /* */ 1450 /* <InOut> */ 1451 /* builder :: A pointer to the glyph builder to initialize. */ 1452 /* */ 1453 /* <Input> */ 1454 /* face :: The current face object. */ 1455 /* */ 1456 /* size :: The current size object. */ 1457 /* */ 1458 /* glyph :: The current glyph object. */ 1459 /* */ 1460 /* hinting :: Whether hinting should be applied. */ 1461 /* */ 1462 FT_LOCAL_DEF( void ) t1_builder_init(T1_Builder builder,FT_Face face,FT_Size size,FT_GlyphSlot glyph,FT_Bool hinting)1463 t1_builder_init( T1_Builder builder, 1464 FT_Face face, 1465 FT_Size size, 1466 FT_GlyphSlot glyph, 1467 FT_Bool hinting ) 1468 { 1469 builder->parse_state = T1_Parse_Start; 1470 builder->load_points = 1; 1471 1472 builder->face = face; 1473 builder->glyph = glyph; 1474 builder->memory = face->memory; 1475 1476 if ( glyph ) 1477 { 1478 FT_GlyphLoader loader = glyph->internal->loader; 1479 1480 1481 builder->loader = loader; 1482 builder->base = &loader->base.outline; 1483 builder->current = &loader->current.outline; 1484 FT_GlyphLoader_Rewind( loader ); 1485 1486 builder->hints_globals = size->internal; 1487 builder->hints_funcs = 0; 1488 1489 if ( hinting ) 1490 builder->hints_funcs = glyph->internal->glyph_hints; 1491 } 1492 1493 builder->pos_x = 0; 1494 builder->pos_y = 0; 1495 1496 builder->left_bearing.x = 0; 1497 builder->left_bearing.y = 0; 1498 builder->advance.x = 0; 1499 builder->advance.y = 0; 1500 1501 builder->funcs = t1_builder_funcs; 1502 } 1503 1504 1505 /*************************************************************************/ 1506 /* */ 1507 /* <Function> */ 1508 /* t1_builder_done */ 1509 /* */ 1510 /* <Description> */ 1511 /* Finalizes a given glyph builder. Its contents can still be used */ 1512 /* after the call, but the function saves important information */ 1513 /* within the corresponding glyph slot. */ 1514 /* */ 1515 /* <Input> */ 1516 /* builder :: A pointer to the glyph builder to finalize. */ 1517 /* */ 1518 FT_LOCAL_DEF( void ) t1_builder_done(T1_Builder builder)1519 t1_builder_done( T1_Builder builder ) 1520 { 1521 FT_GlyphSlot glyph = builder->glyph; 1522 1523 1524 if ( glyph ) 1525 glyph->outline = *builder->base; 1526 } 1527 1528 1529 /* check that there is enough space for `count' more points */ 1530 FT_LOCAL_DEF( FT_Error ) t1_builder_check_points(T1_Builder builder,FT_Int count)1531 t1_builder_check_points( T1_Builder builder, 1532 FT_Int count ) 1533 { 1534 return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); 1535 } 1536 1537 1538 /* add a new point, do not check space */ 1539 FT_LOCAL_DEF( void ) t1_builder_add_point(T1_Builder builder,FT_Pos x,FT_Pos y,FT_Byte flag)1540 t1_builder_add_point( T1_Builder builder, 1541 FT_Pos x, 1542 FT_Pos y, 1543 FT_Byte flag ) 1544 { 1545 FT_Outline* outline = builder->current; 1546 1547 1548 if ( builder->load_points ) 1549 { 1550 FT_Vector* point = outline->points + outline->n_points; 1551 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; 1552 1553 1554 if ( builder->shift ) 1555 { 1556 x >>= 16; 1557 y >>= 16; 1558 } 1559 point->x = x; 1560 point->y = y; 1561 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); 1562 1563 builder->last = *point; 1564 } 1565 outline->n_points++; 1566 } 1567 1568 1569 /* check space for a new on-curve point, then add it */ 1570 FT_LOCAL_DEF( FT_Error ) t1_builder_add_point1(T1_Builder builder,FT_Pos x,FT_Pos y)1571 t1_builder_add_point1( T1_Builder builder, 1572 FT_Pos x, 1573 FT_Pos y ) 1574 { 1575 FT_Error error; 1576 1577 1578 error = t1_builder_check_points( builder, 1 ); 1579 if ( !error ) 1580 t1_builder_add_point( builder, x, y, 1 ); 1581 1582 return error; 1583 } 1584 1585 1586 /* check space for a new contour, then add it */ 1587 FT_LOCAL_DEF( FT_Error ) t1_builder_add_contour(T1_Builder builder)1588 t1_builder_add_contour( T1_Builder builder ) 1589 { 1590 FT_Outline* outline = builder->current; 1591 FT_Error error; 1592 1593 1594 if ( !builder->load_points ) 1595 { 1596 outline->n_contours++; 1597 return PSaux_Err_Ok; 1598 } 1599 1600 error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); 1601 if ( !error ) 1602 { 1603 if ( outline->n_contours > 0 ) 1604 outline->contours[outline->n_contours - 1] = 1605 (short)( outline->n_points - 1 ); 1606 1607 outline->n_contours++; 1608 } 1609 1610 return error; 1611 } 1612 1613 1614 /* if a path was begun, add its first on-curve point */ 1615 FT_LOCAL_DEF( FT_Error ) t1_builder_start_point(T1_Builder builder,FT_Pos x,FT_Pos y)1616 t1_builder_start_point( T1_Builder builder, 1617 FT_Pos x, 1618 FT_Pos y ) 1619 { 1620 FT_Error error = PSaux_Err_Invalid_File_Format; 1621 1622 1623 /* test whether we are building a new contour */ 1624 1625 if ( builder->parse_state == T1_Parse_Have_Path ) 1626 error = PSaux_Err_Ok; 1627 else if ( builder->parse_state == T1_Parse_Have_Moveto ) 1628 { 1629 builder->parse_state = T1_Parse_Have_Path; 1630 error = t1_builder_add_contour( builder ); 1631 if ( !error ) 1632 error = t1_builder_add_point1( builder, x, y ); 1633 } 1634 1635 return error; 1636 } 1637 1638 1639 /* close the current contour */ 1640 FT_LOCAL_DEF( void ) t1_builder_close_contour(T1_Builder builder)1641 t1_builder_close_contour( T1_Builder builder ) 1642 { 1643 FT_Outline* outline = builder->current; 1644 FT_Int first; 1645 1646 1647 if ( !outline ) 1648 return; 1649 1650 first = outline->n_contours <= 1 1651 ? 0 : outline->contours[outline->n_contours - 2] + 1; 1652 1653 /* We must not include the last point in the path if it */ 1654 /* is located on the first point. */ 1655 if ( outline->n_points > 1 ) 1656 { 1657 FT_Vector* p1 = outline->points + first; 1658 FT_Vector* p2 = outline->points + outline->n_points - 1; 1659 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; 1660 1661 1662 /* `delete' last point only if it coincides with the first */ 1663 /* point and it is not a control point (which can happen). */ 1664 if ( p1->x == p2->x && p1->y == p2->y ) 1665 if ( *control == FT_CURVE_TAG_ON ) 1666 outline->n_points--; 1667 } 1668 1669 if ( outline->n_contours > 0 ) 1670 { 1671 /* Don't add contours only consisting of one point, i.e., */ 1672 /* check whether begin point and last point are the same. */ 1673 if ( first == outline->n_points - 1 ) 1674 { 1675 outline->n_contours--; 1676 outline->n_points--; 1677 } 1678 else 1679 outline->contours[outline->n_contours - 1] = 1680 (short)( outline->n_points - 1 ); 1681 } 1682 } 1683 1684 1685 /*************************************************************************/ 1686 /*************************************************************************/ 1687 /***** *****/ 1688 /***** OTHER *****/ 1689 /***** *****/ 1690 /*************************************************************************/ 1691 /*************************************************************************/ 1692 1693 FT_LOCAL_DEF( void ) t1_decrypt(FT_Byte * buffer,FT_Offset length,FT_UShort seed)1694 t1_decrypt( FT_Byte* buffer, 1695 FT_Offset length, 1696 FT_UShort seed ) 1697 { 1698 PS_Conv_EexecDecode( &buffer, 1699 buffer + length, 1700 buffer, 1701 length, 1702 &seed ); 1703 } 1704 1705 1706 /* END */ 1707