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